#ifndef cgame_h
#define cgame_h

#include "ForwardDeclarations.h"
#include "OGLPlatformSpecific.h"
#include "cGrid.h"
#include "cTimer.h"
//declarations for sound
#include "C3DSound.h"
#include "CDXAudio.h"
#include "StdAfx.h"

#include <iostream>
#include <String>
#include <queue>
using namespace std;

class cGame
{   
public:
    static cGame* instance();
    
    // since we use the game as a global variable and objects 
    // are constructed that require opengl already to be initialized,
    // delay allocating them intil later.
    void init(); 
    
    void display(void);
    void idle();
    void keyboard(unsigned char key, int x, int y);
    void specialKey(int key, int x, int y);
    void specialKeyUp(int key, int x, int y);
    void mouseClick(int button, int state, int x, int y); 
    void mouseMove(int x, int y);
    
    int screenWidth_, screenHeight_; // updated by reshape in main
    
    float t_; 	
    
    bool upKeyPressed_, downKeyPressed_, leftKeyPressed_, rightKeyPressed_;
private:
    enum GAME_MODE { DROPPING_BLOCKS, EXPLODING, GRID_FALL };
    
    GAME_MODE mode_;
    
    cGame(); // do nothing
    
    void startGame();				// setup everything at the beginning of the game
    void randomizeDropBlocks();			// reset the drop blocks to the top of the screen, randomize types
    bool moveDroppingBlocks(int dx, int dy);	// returns true if the block could be moved, false otherwise
    bool rotateDroppingBlocksR();		// rotate right
    bool rotateDroppingBlocksL();		// rotate right
    void collideBlocks();			// sticks the dropping blocks into the grid and rerandomizes them 
    void dropBlocks();				// respond to input and automatically fall in block dropping mode
    
    void explode();				// handle explosions of blocks
    
    bool neighborIsSameType(cGrid::cBlock* p, int dx, int dy); // returns true if neighbor is same type
    // adds p's neighbor to the explosion queue if it exists and is the same type as p
    // return true if the neighbor was added, false otherwise
    bool addNeighborToExplosionQueue(cGrid::cBlock* p, int dx, int dy);	
                                                
    void startExplosions();			// find each explosion type box and adds appropriate neighbors to explosion queue
    
    void gridFall();				// move blocks in grid that have nothing under them down
    
    void update();				// gets time difference between last update call. causes blocks to move down with time
    
    cGrid grid_;
    cGrid::cBlock droppingBlock1_, droppingBlock2_;
    
    queue<cGrid::cBlock*> explosionQueue_;
    
    cTimer timer_;
                                                // total time running in round
    float timeSinceDrop_;			// time since game automatically moved a piece down
    float timeToDrop_;				// how often we cause the block to move down
    float timeToFall_;				// time inbetween making blocks fall due to gravity
    float timeSinceMove_;			// time since the dropping blocks last moved under user control
    float timeToMove_;				// time between dropping blocks moves under user control
    float timeSinceExplode_;			// time since a block last exploded in an explosion chain
    float timeToExplode_;			// time between explosions in an explosion chain
    
	//sound variables
	CDXAudio Audio;
	C3DSound SoundEffect;
	C3DSound BckgrndMsc;
	C3DSound movement;
	
    // singleton instance
    static cGame* instance_; 
};

#endif // end define cgame_h
