#pragma once
#include <iostream>
#include <string>
using namespace std;
#include "params.h"
#include "location.h"
#include "functions.h"
#include "cvec2t.h"
#include "cvec3t.h"
#include <ctime>
#include "al.h" 
#include "alc.h" 
#include "AL/alut.h"

typedef CVec2T<float> Vec2f;
typedef CVec3T<float> Vec3f;

using LocationObjects::PillBox;
using LocationObjects::Germ;
using LocationObjects::Pill;
using LocationObjects::Location;


class Court { 
  public: 
    Court() {}
	
	//draw the court
	void draw (){
    glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 2);
 //   glTranslatef(-2,-2,0);
    glScalef(1,1,1);
    glColor3f(1,1,1);
    glBegin(GL_POLYGON);
      glTexCoord2f(0,0);
      glVertex2f(-1,-1);
      glTexCoord2f(1,0);
      glVertex2f(1,-1);
      glTexCoord2f(1,1);
      glVertex2f(1,1);
      glTexCoord2f(0,1);
      glVertex2f(-1,1);
    glEnd();
    glDisable(GL_TEXTURE_2D);
  glPopMatrix();
	}

}; 


class Game { 
public:
  Game() :
		_pill(0), _nextPill(0), _pause(true), _level(1), _title(true), 
		_rtick(0), _ftick(0), _score(0), _start(true), _gameOver(false),
		_reorganizing(false), _newPill(false), texture(0), textureNumber(0),
		_bg_music(Func::randm(0) ) {
	init();
	cout << "Game - initSounds\n";
	initSounds();
  }

  void initSounds(){
	ALuint  buffer_background1, buffer_background2, buffer_background3; 
	ALuint	buffer_screamo, buffer_screamg, buffer_screamy;
	ALuint	buffer_thud, buffer_click, buffer_levelcomplete, buffer_gameover;
	 

	  ALfloat pos_crowd[] = {0,0,0};  

	  cout << "Game - initSounds start\n";
	  alGenBuffers(1,&buffer_background1);
      loadAudioFile(buffer_background1,string("sounds/bg1.wav"));
	  alGenSources(1,&_source_background1);
	  alSourcef(_source_background1,AL_PITCH,1.0f);
	  alSourcef(_source_background1,AL_GAIN,0.5f);
	  alSourcefv(_source_background1,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_background1,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_background1,AL_BUFFER, buffer_background1);
	  alSourcei(_source_background1,AL_LOOPING,AL_TRUE);

	  alGenBuffers(1,&buffer_background2);
      loadAudioFile(buffer_background2,string("sounds/bg2.wav"));
	  alGenSources(1,&_source_background2);
	  alSourcef(_source_background2,AL_PITCH,1.0f);
	  alSourcef(_source_background2,AL_GAIN,0.5f);
	  alSourcefv(_source_background2,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_background2,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_background2,AL_BUFFER, buffer_background2);
	  alSourcei(_source_background2,AL_LOOPING,AL_TRUE);

	  alGenBuffers(1,&buffer_background3);
      loadAudioFile(buffer_background3,string("sounds/bg3.wav"));
	  alGenSources(1,&_source_background3);
	  alSourcef(_source_background3,AL_PITCH,1.0f);
	  alSourcef(_source_background3,AL_GAIN,0.35f);
	  alSourcefv(_source_background3,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_background3,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_background3,AL_BUFFER, buffer_background3);
	  alSourcei(_source_background3,AL_LOOPING,AL_TRUE);

	  alGenBuffers(1,&buffer_screamo);
      loadAudioFile(buffer_screamo,string("sounds/screamo.wav"));
	  alGenSources(1,&_source_screamo);
	  alSourcef(_source_screamo,AL_PITCH,1.0f);
	  alSourcef(_source_screamo,AL_GAIN,0.2f);
	  alSourcefv(_source_screamo,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_screamo,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_screamo,AL_BUFFER, buffer_screamo);
	  alSourcei(_source_screamo,AL_LOOPING,AL_FALSE);
	  
	  alGenBuffers(1,&buffer_screamg);
      loadAudioFile(buffer_screamg,string("sounds/screamg.wav"));
	  alGenSources(1,&_source_screamg);
	  alSourcef(_source_screamg,AL_PITCH,1.0f);
	  alSourcef(_source_screamg,AL_GAIN,0.2f);
	  alSourcefv(_source_screamg,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_screamg,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_screamg,AL_BUFFER, buffer_screamg);
	  alSourcei(_source_screamg,AL_LOOPING,AL_FALSE);

	  alGenBuffers(1,&buffer_screamy);
      loadAudioFile(buffer_screamy,string("sounds/screamy.wav"));
	  alGenSources(1,&_source_screamy);
	  alSourcef(_source_screamy,AL_PITCH,1.0f);
	  alSourcef(_source_screamy,AL_GAIN,0.2f);
	  alSourcefv(_source_screamy,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_screamy,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_screamy,AL_BUFFER, buffer_screamy);
	  alSourcei(_source_screamy,AL_LOOPING,AL_FALSE);

	  alGenBuffers(1,&buffer_thud);
      loadAudioFile(buffer_thud,string("sounds/thud.wav"));
	  alGenSources(1,&_source_thud);
	  alSourcef(_source_thud,AL_PITCH,1.0f);
	  alSourcef(_source_thud,AL_GAIN,0.6f);
	  alSourcefv(_source_thud,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_thud,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_thud,AL_BUFFER, buffer_thud);
	  alSourcei(_source_thud,AL_LOOPING,AL_FALSE);

	  alGenBuffers(1,&buffer_click);
      loadAudioFile(buffer_click,string("sounds/click.wav"));
	  alGenSources(1,&_source_click);
	  alSourcef(_source_click,AL_PITCH,1.0f);
	  alSourcef(_source_click,AL_GAIN,0.3f);
	  alSourcefv(_source_click,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_click,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_click,AL_BUFFER, buffer_click);
	  alSourcei(_source_click,AL_LOOPING,AL_FALSE);

	  alGenBuffers(1,&buffer_levelcomplete);
      loadAudioFile(buffer_levelcomplete,string("sounds/levelcomplete.wav"));
	  alGenSources(1,&_source_levelcomplete);
	  alSourcef(_source_levelcomplete,AL_PITCH,1.0f);
	  alSourcef(_source_levelcomplete,AL_GAIN,0.6f);
	  alSourcefv(_source_levelcomplete,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_levelcomplete,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_levelcomplete,AL_BUFFER, buffer_levelcomplete);
	  alSourcei(_source_levelcomplete,AL_LOOPING,AL_FALSE);

	  alGenBuffers(1,&buffer_gameover);
      loadAudioFile(buffer_gameover,string("sounds/boo.wav"));
	  alGenSources(1,&_source_gameover);
	  alSourcef(_source_gameover,AL_PITCH,1.0f);
	  alSourcef(_source_gameover,AL_GAIN,0.6f);
	  alSourcefv(_source_gameover,AL_POSITION,to3d(Vec2f(0,0)));
	  alSourcefv(_source_gameover,AL_VELOCITY,to3d(Vec2f(0,0)));
      alSourcei(_source_gameover,AL_BUFFER, buffer_gameover);
	  alSourcei(_source_gameover,AL_LOOPING,AL_FALSE);
	  cout << "Game - initSounds finished\n";
  }
  void draw () {
	if(_title){
		drawTitle();
	}
	else if(!_gameOver){
	  court.draw();
	  drawLocations();
	  drawScore();
	  drawPause();
	  drawLevel();
	}
	else
	  drawGameOver();
  }



  void advance() {
    if(_title)
		return;
	if(_gameOver)
		return;
	if(_pause)
		return;
	if(_reorganizing){
		reorganize();
		return;
	}
	if(_newPill){
		_newPill=false;
		initPill();
		return;
	}
	if(_crash){
		crashAction();
		_newPill = true;
	}
	//Move on to the next level.
	if(_remainingGerms <= 0){
		stopMusic();
		alSourcePlay(_source_levelcomplete);
		_level++;
		clear();
		init();
	}
	//Continue dropping the current pill
	drop(0);

  }

  void swapPause(){
	if(_title){
		_title = false;
		return;
	}
	if(_start){
		_start = false;
		_pause = false;
		playMusic();
		initPill();
		return;
	}
	//Unpause
	if(_pause){
		playMusic();
		_pause = false;
	}
	//Pause
	else{
		pauseMusic();
		_pause = true;
	}
  }
  void cheat(char c){
	if(c == '0'){
		_pause = false;
		_newPill = false;
		_reorganizing = false;
		_crash = false;
		_remainingGerms = 0;
	}
  }
 /**
  * Routine to swap orientation of the pill.
  * Includes testing for walls.
  */
  void swapPill(){
	if(_pause || _reorganizing || _title) return;

	Location* loc1 = _pill->getLoc1();
	Location* loc2 = _pill->getLoc2();
	int col1 = loc1->getColumn();
	int col2 = loc2->getColumn();
	int row1 = loc1->getRow();
	int row2 = loc2->getRow();
	int orientation = _pill->getOr();
	
	updateSourcePosition(_source_click, loc1->getPos() );
	alSourcePlay(_source_click);

	if(orientation == Params::HORIZONTAL){
		//Check for top row or something above
		if(row1 == 0 || !testDrop(-1)){
			_pill->swapBox();	
		}
		else{
			_pill->setLoc( field[row1][col1], field[row2-1][col1]  );
			_pill->setOr(Params::VERTICAL);
		}
	}
	else if(orientation == Params::VERTICAL){
		//Check for RightMost Wall or to the right, while the left is clear
		if(col1 == 7 && testMove(-1) ){
			_pill->setLoc( field[row1][col1-1], field[row1][col1]  );
			_pill->setOr(Params::HORIZONTAL);		
		}
		//Else we are clear on the right and can swap normally
		else if( testMove(1) ) {
			_pill->setLoc( field[row1][col1], field[row1][col1+1]  );
			_pill->setOr(Params::HORIZONTAL);
		}
		_pill->swapBox();
	}	
  }
 /**
  * Routine to move the pill left or right.
  * Includes testing for impact.
  * -1 for Left
  * 1 for Right
  */
  void move(int c){
	if(_pause || _reorganizing || _title) return;

	Location* loc1 = _pill->getLoc1();
	Location* loc2 = _pill->getLoc2();
	int col1 = loc1->getColumn();
	int col2 = loc2->getColumn();
	int row1 = loc1->getRow();
	int row2 = loc2->getRow();
	int orientation = _pill->getOr();

	//We satisfied all tests, now we can move the pill locations
	if(testMove(c) ){
		alSourcePlay(_source_click);
		_pill->setLoc(field[row1][col1+c], field[row2][col2+c] );
	}

  }
 /**
  * Routine to drop the pill one row.
  * c = 1 forces a drop from the keyboard.
  * Includes testing for a crash.
  * Sets bool crash to true if we hit something.
  */
  void drop(int c){
	if(_pause || _reorganizing || _title) return;
	if(_pill->getLoc1()->isEmpty() || _pill->getLoc2()->isEmpty() ) return;

	if(_ftick >= 100 || (c==1) ){
		_ftick = 0;

		Location* loc1 = _pill->getLoc1();
		Location* loc2 = _pill->getLoc2();
		int col1 = loc1->getColumn();
		int col2 = loc2->getColumn();
		int row1 = loc1->getRow();
		int row2 = loc2->getRow();
		int orientation = _pill->getOr();

		if(!testDrop(1) ){
			updateSourcePosition(_source_thud, loc1->getPos() );
			alSourcePlay(_source_thud);
			_crash=true;
			return;
		}

		//Manual Drop gets a click
		if(c==1){
			updateSourcePosition(_source_thud, loc1->getPos() );
			alSourcePlay(_source_click);
		}
		//Passed all tests, drop the pill
		_pill->setLoc(field[row1+1][col1], field[row2+1][col2] );
		
	}
	//Timer Delay for pill drop.
	//Speed up every four levels
	else{
		_ftick+=(_level/4)+1;
	}
  }
private:
  unsigned int* texture;
  int textureNumber;
  Pill* _pill;
  Pill* _nextPill;
  Location* field[16][8];
  Location* _next[2];
  Court  court;
  int _level;
  int _remainingGerms;
  int _ftick;
  int _rtick;
  int _score;
  int _bg_music;
  bool _title;
  bool _newPill;
  bool _pause;
  bool _crash;
  bool _start;
  bool _gameOver;
  bool _reorganizing;
  ALuint _source_background1;
  ALuint _source_background2;
  ALuint _source_background3;
  ALuint _source_screamo;
  ALuint _source_screamg;
  ALuint _source_screamy;
  ALuint _source_thud;
  ALuint _source_click;
  ALuint _source_levelcomplete;
  ALuint _source_gameover;


 /**
  * Routine to test if a pill can move to the side given.
  * -1 Left
  * 1 Right
  */
  bool testMove(int c){
	Location* loc1 = _pill->getLoc1();
	Location* loc2 = _pill->getLoc2();
	int col1 = loc1->getColumn();
	int col2 = loc2->getColumn();
	int row1 = loc1->getRow();
	int row2 = loc2->getRow();
	int orientation = _pill->getOr();


	//If this is NOT within the constraints of the field, do NOT move
	if( (col1+c >= 8) || (col1+c < 0) || (col2+c >= 8) || (col2+c < 0) ){
	  return false;
	}
	
	//Horizontal Pill to the Right check
	if(orientation == Params::HORIZONTAL && c==1){
		if(!field[row2][col2+1]->isEmpty() )
			return false;
	}
	//Horizontal Pill to the Left check
	else if(orientation == Params::HORIZONTAL && c==-1){
		if(!field[row1][col1+c]->isEmpty() )
			return false;
	}
	//Vertical Pills we check left or right (inherent in c)
	//of both parts of the pill
	else if(orientation == Params::VERTICAL){
		if(!field[row1][col1+c]->isEmpty() )
			return false;
		if(!field[row2][col2+c]->isEmpty() )
			return false;
	}
	
	return true;
  }

 /**
  * Routine to test if a pill can move up or down.
  * -1 UP
  * 1 DOWN
  */
  bool testDrop(int c){
		Location* loc1 = _pill->getLoc1();
		Location* loc2 = _pill->getLoc2();
		int col1 = loc1->getColumn();
		int col2 = loc2->getColumn();
		int row1 = loc1->getRow();
		int row2 = loc2->getRow();
		int orientation = _pill->getOr();

		//if at the bottom, don't drop
		if(row1 >= 15 || row2 >= 15){
			return false;
		}

		//Vertical Pills we check below the first parts of the pill
		if(orientation == Params::VERTICAL && c==1){
			if(!field[row1+1][col1]->isEmpty() ){
				return false;
			}
		}
		//To Check Up we use the top part
		if(orientation == Params::VERTICAL && c==-1){
			if(!field[row2-1][col2]->isEmpty() ){
				return false;
			}
		}

		//Horizontal Pills check below both
		if(orientation == Params::HORIZONTAL && c==1){
			if(!field[row1+1][col1]->isEmpty() || !field[row2+1][col2]->isEmpty() ){
				return false;
			}
		}
		//Horizontal Pills check above both
		if(orientation == Params::HORIZONTAL && c==-1){
			if(!field[row1-1][col1]->isEmpty() || !field[row2-1][col2]->isEmpty() ){
				return false;
			}
		}		

		return true;
  }

 /**
  * Routine to empty the field and delete the boxes.
  */
  void clear(){
	//Clear the board each level
	for(int r=0; r<16; r++){
		//Scroll across the grid setting positions
		for(int c=0; c<8; c++){
			field[r][c]->deleteBox();
		}
	}
  }
 /**
  * Routine to init the field and create the locations.
  */
  void init(){
    //Create the field only on the first level
    if(_level == 1){
	  //Establish Positions for all Locations on the field.
	  for(int r=0; r<16; r++){
		//Scroll across the grid setting positions
		for(int c=0; c<8; c++){
			Vec2f off( (float)c*Params::PillBoxWidth, -(float)r*Params::PillBoxHeight );
			field[r][c] = new Location(Params::CourtUpperLeftCorner+off, r, c);
		}
	  }//end FOR
	  //Create nextPill locations
	  _next[0]=new Location(Params::NextPillUpperLeft);
	  _next[1]=new Location(Params::NextPillUpperLeft+Params::PillBoxRight);
	  _nextPill = new Pill(_next[0], _next[1]);
	}//end IF
	_pause = true;
	_start = true;
	_reorganizing = false;
	_newPill = false;
	_ftick = 0;
	_remainingGerms = _level*3;
	initGerms();
	//initPill();
		
  }
 /**
  * Routine to init a new pill and set _crash to false.
  * Sets our falling delay back to zero
  */
  void initPill(){
	//If the start locations aren't empty, GameOver	
	if(!field[0][3]->isEmpty() || !field[0][4]->isEmpty() )
		gameOver();

	delete _pill;
	//Swap the next into the start spot
	_pill = _nextPill;
	_pill->setLoc(field[0][3], field[0][4]);

	//Initialize a new Pill into Next
	_nextPill = new Pill(_next[0], _next[1]);
	_crash = false;
	_ftick = 0;
	cout << "\nRemaining Germs: " << _remainingGerms;
  }
 /**
  * Routine to init a set of germs.
  * Random locations in the bottom half of the board.
  */
  void initGerms(){
	
	//Count of original red, blue, and yellow germs we make
	int red=0;
	int blue=0;
	int yellow=0;
	int gcolor=0;

	while(red<_level || blue<_level || yellow<_level){

		int col = Func::randm(7);
		//Row should be on the bottom half of the screen
		int row = 8+Func::randm(7);
		if(field[row][col]->isEmpty() ){
			if(red<_level){
				red++;
				gcolor=Params::RED;
			}
			else if(blue<_level){
				blue++;
				gcolor=Params::BLUE;
			}
			else{
				yellow++;
				gcolor=Params::YELLOW;
			}
			//Create a germ in the location
			field[row][col]->putBox(new Germ(gcolor) );

		}

	}
	

  } 

 /**
  * Routine to draw the field.
  */
  void drawLocations (){
	  for(int i=0; i<16; i++){
	    for(int j=0; j<8; j++){
		  if(field[i][j] != 0)
			//Only print the Germs when paused.
			if(_pause){
				if(field[i][j]->isGerm() )
					field[i][j]->draw();
			}
			else
				field[i][j]->draw();
		}
	  }
	  //Draw  NextArea
	  if(!_pause){
		_next[0]->draw();
		_next[1]->draw();
	  }
  }

 /**
  * Routine will check to see if we have cleared anything
  * and take appropriate action.
  */
  void crashAction(){
	Location* loc1 = _pill->getLoc1();
	Location* loc2 = _pill->getLoc2();
	int col1 = loc1->getColumn();
	int col2 = loc2->getColumn();
	int row1 = loc1->getRow();
	int row2 = loc2->getRow();
	int orientation = _pill->getOr();

	cout << "\nStarting Test of UDLR on pill1 (r"<<row1<<",c"<<col1<<")";
	int* count1 = testUDLR(loc1);
	cout << "\nStarting Test of UDLR on pill2 (r"<<row1<<",c"<<col1<<")";
	int* count2 = testUDLR(loc2);
	
	_reorganizing = clearUDLR(loc1, count1) || clearUDLR(loc2, count2);
  }
 /**
  * Routine will recieve the counts and clear appropriate boxes.
  */
  bool clearUDLR(Location* loc, int* c){
	int col = loc->getColumn();
	int row = loc->getRow();

	bool cleared = false;

	//If there were 4 in a row up or down
	if(c[0]+c[1] >= 3){
		cout << "\n 4 in a row UD";
		for(int i=row-c[0]; i<= row+c[1]; i++){
			cout << "\n Deleting r"<<i<<" , c"<<col;
			//Test for Germ status
			if(field[i][col]->isGerm() ){
				cout << "\nDeleting Germ";
				germScream(field[i][col]->getBox()->getColor() );
				_remainingGerms--;
				_score += 100;
			}
			severConnection(field[i][col]);
			field[i][col]->deleteBox();
		}
		cleared = true;
	}
	//If there were 4 in a row left or right
	if(c[2]+c[3] >= 3){
		cout << "\n 4 in a row LR";
		for(int i=col-c[2]; i<= col+c[3]; i++){
			cout << "\n Deleting r"<<row<<" , c"<<i;
			//Test for Germ status
			if(field[row][i]->isGerm() ){
				cout << "\nDeleting Germ";
				germScream(field[row][i]->getBox()->getColor() );
				_remainingGerms--;
				_score += 100;
			}
			severConnection(field[row][i]);
			field[row][i]->deleteBox();
		}
		cleared = true;
	}
	delete c;
	return cleared;
  }
 /**
  * Routine will check Up, Down, Left, Right of the given location
  * And return an array of locations valid for clearing.
  */
  int* testUDLR(Location* loc){
	int color = loc->getBox()->getColor();
	int col = loc->getColumn();
	int row = loc->getRow();
	int countLeft = 0;
	int countRight = 0;
	int countUp = 0;
	int countDown = 0;

	bool consecutive = true;
	//Count Up
	cout << "\nCounting Up: ";
	consecutive = true;
	for(int i=(row-1); i>=0; i--){
		Location* temp = field[i][col];
		if(temp->isEmpty() )
			break;
		int tempColor = temp->getBox()->getColor();
		//A non match will break our consecutive boolean
		//and the count will be suspended
		if(tempColor == color  && consecutive==true){
			countUp++;
		}
		else
			consecutive=false;
	}
	cout << countUp;

	//Count Down
	cout << "\nCounting Down: ";
	consecutive = true;
	for(int i=(row+1); i<=15; i++){
		Location* temp = field[i][col];
		if(temp->isEmpty() )
			break;
		int tempColor = temp->getBox()->getColor();
		//A non match will break our consecutive boolean
		//and the count will be suspended
		if(tempColor == color  && consecutive==true){
			countDown++;
		}
		else
			consecutive=false;
	}
	cout << countDown;

	//Count left
	cout << "\nCounting Left: ";
	consecutive = true;
	for(int i=(col-1); i>=0; i--){
		Location* temp = field[row][i];
		if(temp->isEmpty() )
			break;
		int tempColor = temp->getBox()->getColor();
		//A non match will break our consecutive boolean
		//and the count will be suspended
		if(tempColor == color  && consecutive==true){
			countLeft++;
		}
		else
			consecutive=false;
	}
	cout << countLeft;

	//Count right
	cout << "\nCounting Right: ";
	for(int i=(col+1); i<=7; i++){
		Location* temp = field[row][i];
		if(temp->isEmpty() )
			break;
		int tempColor = temp->getBox()->getColor();
		//A non match will break our consecutive boolean
		//and the count will be suspended
		if(tempColor == color  && consecutive==true){
			countRight++;
		}
		else
			consecutive=false;
	}
	cout << countRight;

	int* c = new int[4];
	c[0] = countUp;
	c[1] = countDown;
	c[2] = countLeft;
	c[3] = countRight;
	return c;

  }



 /**
  * Routine will reorganize boxes shaken loose by the clearing
  * Counts a ticker so they fall gracefully.
  */  
  void reorganize(){
	bool still_falling = true;
	  
	//Iterate over the field and lower everything that needs to be lowered.
	//Use rtick to fall gracefully.
	_rtick++;
	cout << _rtick << "\n";
	if(_rtick >= 15 ){
		_rtick = 0;
		still_falling = false;
		//Set to false, will be turned back on if something falls.


	  //Loop from second to bottom, drop things that aren't held up.
	  for(int i=14; i>=0; i--){
		  for(int j=0; j<=7; j++){
			//If theres nothing there, skip
			if(field[i][j]->isEmpty() ){
				continue;
			}
			cout << "\nfield "<<i<<","<<j;
			//If clear below and not a germ
			if(field[i+1][j]->isEmpty() && !field[i][j]->isGerm() ){
				//if the one to the right is connected to us and NOT clear below
				if(j!=7 && !field[i][j+1]->isEmpty() && 
					field[i][j+1]->getBox()->getCon() == Params::LEFT){
					if(!field[i+1][j+1]->isEmpty() ){
						cout << " right connection is sturdy";
						continue;
					}
				}
				//if the one to the left is connected to us and NOT clear below
				else if(j!=0 && !field[i][j-1]->isEmpty() && 
					field[i][j-1]->getBox()->getCon() == Params::RIGHT){
					if(!field[i+1][j-1]->isEmpty() ){
						cout << " left connection is sturdy";
						continue;
					}
				}
				//This needs to drop one and we should loop again to drop more.
				else{
					field[i][j]->moveBox(field[i+1][j] );
					cout << "should be dropped";
					still_falling = true;
				}
			}
			//It's a germ or it is help up
			else {
				//cout << "is held up or a germ";
			}
		  }//end FOR j
	  }//end FOR i

	//If we are done falling, search for new clear sequences
	//which will again reorganize if something is cleared.
	if(!still_falling){
	  for(int i=15; i>=0; i--){
		  for(int j=0; j<=7; j++){
			//If theres nothing there, skip
			if(field[i][j]->isEmpty() ){
				continue;
			}
			//Else check for clear
			else{
				int* c = testUDLR(field[i][j]);
				still_falling = clearUDLR(field[i][j], c);
			}
		  }
	  }	
	}
	  
	}//end IF rtick
	
	if(!still_falling)
		_reorganizing = false;
  }
  void severConnection(Location* loc){
	if(loc->isEmpty() )
		return;
	PillBox* box = loc->getBox();
	int connection = box->getCon();
	int row = loc->getRow();
	int col = loc->getColumn();

	switch(connection){
		case Params::RIGHT:
			cout << "\nSever RIGHT Connection";			
			box = field[row][col+1]->getBox();
			break;
		case Params::LEFT:
			cout << "\nSever LEFT Connection";	
			box = field[row][col-1]->getBox();
			break;
		case Params::TOP:
			cout << "\nSever TOP Connection";	
			box = field[row-1][col]->getBox();
			break;
		case Params::BOTTOM:
			cout << "\nSever BOTTOM Connection";	
			box = field[row+1][col]->getBox();
			break;
		default:
			box = 0;
			break;
	};
	if(box !=0 )
		box->setCon(Params::NONE);

  }

  void gameOver(){
	_gameOver = true;
	_pause = true;
	alSourcePlay(_source_gameover);
	clear();
  }
  void drawTitle(){
	glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 1);
    glScalef(1,1,1);
    glColor3f(1,1,1);
    glBegin(GL_POLYGON);
      glTexCoord2f(0,0);
      glVertex2f(-1,-1);
      glTexCoord2f(1,0);
      glVertex2f(1,-1);
      glTexCoord2f(1,1);
      glVertex2f(1,1);
      glTexCoord2f(0,1);
      glVertex2f(-1,1);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
  }
  void drawPause(){
	if(_pause){
	  glLineWidth(2.0);
      glColor3fv(Params::Black);
	glDisable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glDisable(GL_ALPHA);
      glPushMatrix();
        glTranslatef(Params::CourtUpperLeftCorner.x()+(1.0/100.0),
			Params::CourtUpperLeftCorner.y()-(1.0/20.0),1);
        glScalef(Params::InfoFontScale,Params::InfoFontScale,1);
        glColor3fv(Params::Black);
        drawString("Paused. Press P" );
      glPopMatrix();

    glEnable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glEnable(GL_ALPHA);
	}
  }
  void drawScore(){
    glLineWidth(2.0);
    glColor3fv(Params::CourtColor);
	glDisable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glDisable(GL_ALPHA);
    glPushMatrix();
      glTranslatef(Params::ScoreLowerLeftCorner.x(),Params::ScoreLowerLeftCorner.y(),1);
      glScalef(Params::InfoFontScale,Params::InfoFontScale,1);
      ostrstream score;
      score << _score;
      glColor3fv(Params::ScoreColor);
      drawString(score.str());
    glPopMatrix();
	//Print the word "Score"
    glPushMatrix();
      glTranslatef(Params::ScoreLowerLeftCorner.x(),
			Params::ScoreLowerLeftCorner.y()+(1.0/16.0),1);
      glScalef(Params::InfoFontScale,Params::InfoFontScale,1);
      glColor3fv(Params::ScoreColor);
      drawString("Score" );
    glPopMatrix();
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glEnable(GL_ALPHA);
  }
  void drawLevel(){
    glLineWidth(1.0);
    glColor3fv(Params::CourtColor);
	glDisable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glDisable(GL_ALPHA);
    glPushMatrix();
      glTranslatef(Params::LevelUpperLeft.x(),Params::LevelUpperLeft.y(),1);
      glScalef(Params::InfoFontScale,Params::InfoFontScale,1);
      ostrstream level;
      level << _level;
      glColor3fv(Params::LevelColor);
      drawString(level.str());
    glPopMatrix();
	//Print the word "Level"
    glPushMatrix();
      glTranslatef(Params::LevelUpperLeft.x(),Params::LevelUpperLeft.y()+(1.0/16.0),1);
      glScalef(Params::InfoFontScale,Params::InfoFontScale,1);
      glColor3fv(Params::LevelColor);
      drawString("Level" );
    glPopMatrix();
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	glEnable(GL_ALPHA);
  }
  void drawGameOver(){
	glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 21);
    glScalef(1,1,1);
    glColor3f(1,1,1);
    glBegin(GL_POLYGON);
      glTexCoord2f(0,0);
      glVertex2f(-1,-1);
      glTexCoord2f(1,0);
      glVertex2f(1,-1);
      glTexCoord2f(1,1);
      glVertex2f(1,1);
      glTexCoord2f(0,1);
      glVertex2f(-1,1);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
  }
  void drawString(const string& str) {
   for(int i = 0; i < str.length(); i++) {
     glutStrokeCharacter(Params::InfoFont,str[i]);
   }
  }



  void loadAudioFile(ALuint buffer_id, string fname) { 
		ALsizei size,freq;
		ALenum	format;
		ALvoid	*data;
		ALboolean loop;
		

		//buffer_id = alutCreateBufferFromFile(fname.c_str() );
		//if (buffer_id == AL_NONE) {
		//	cout << "Failed to load "<<fname.c_str()<<"\n";
		//}
		
		// Load file
		alutLoadWAVFile(const_cast<char*>(fname.c_str()),&format,&data,&size,&freq,&loop);
		// Copy data to the buffer
		alBufferData(buffer_id,format,data,size,freq);
		// Unload file
		alutUnloadWAV(format,data,size,freq);
		
  }

  // this is needed to interface Vec2fs with OpenAL functions
  // three things need to be done: 
  // add a zero at the end (there is no 2fv version of these functions) 
  // convert to const float* using the operator defined in cvec2f
  // cast away const, because OpenAL unlike OpenGL, does not accept 
  // const pointers as arguments
  float* to3d(const Vec2f& v ) { 
    return const_cast<float*>((const float*)(Vec3f(v.x(),v.y(),0)));
  }

  void updateSourcePosition(ALuint& source, Vec2f pos){
		alSourcefv(source,AL_POSITION,to3d(pos));
		alSourcefv(source,AL_POSITION,to3d(pos));
  }

  void playMusic(){
	  ALuint source;
	  switch(_bg_music ){
		case 0:		source = _source_background1;break;
		case 1:		source = _source_background2;break;
		case 2:		source = _source_background3;break;
	  }
	  alSourcePlay(source);
  }
  void pauseMusic(){
	  ALuint source;
	  switch(_bg_music ){
		case 0:		source = _source_background1;break;
		case 1:		source = _source_background2;break;
		case 2:		source = _source_background3;break;
	  }
	  alSourcePause(source);
  }
  void stopMusic(){
	  ALuint source;
	  switch(_bg_music ){
		case 0:		source = _source_background1;break;
		case 1:		source = _source_background2;break;
		case 2:		source = _source_background3;break;
	  }
	  alSourceStop(source);
	  alSourceRewind(source);
	  _bg_music++;
	  if(_bg_music > 2)
		  _bg_music = 0;
  }

  void germScream(int col){
	  switch(col){
		  case Params::RED:		alSourcePlay(_source_screamo); break;
		  case Params::BLUE:	alSourcePlay(_source_screamg); break;
		  case Params::YELLOW:  alSourcePlay(_source_screamy); break;
	  }
  }

};

