#include <playfield.h>
#include <stdio.h>
#include <iostream>
#include <jewel.h>
#include <qkeycode.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

// Playfield::Playfield():QWidget(){
//   int i,j;

//   sizeX=7;
//   sizeY=17;
//   for(i=0;i<sizeX;i++){
//     for(j=0;j<sizeY;j++){
//       jewelField[i][j]=0;
//       delList[i][j]=FALSE;
//     }
//   };
//   activeJewel=new(Jewel)(3,4,0);
//   nextJewel=new(Jewel)(3,4,0);
//   score=0;
// }
void Playfield::StartProcedures(){

  int i,j;
  for(i=0;i<sizeX;i++){
    for(j=0;j<sizeY;j++){
      jewelField[i][j]=0;
      delList[i][j]=FALSE;
    }
  };
  score=0;
  emit changeScore(score);
  jewelTimerID=0;
  gamePaused=FALSE;
  gameStarted=FALSE;
  gameOver=FALSE;
  spacePressed=FALSE;
  jewels=1;
  blinkStage=0;
  levelManagment();
  repaint();
}

Playfield::Playfield(QWidget *parent, const char *name,
		     const int diff,QPushButton *start,Highscorelist *hs)
  :QWidget(parent,name){

  noKeys=TRUE;
  mainW=parent;
  sizeX=7;
  sizeY=17;
  difficulty=diff;
  startStop=start;
  highscores=hs;
  StartProcedures();  
  activeJewel=new(Jewel)(3,colors);
  nextJewel=new(Jewel)(3,colors);
}

Playfield::~Playfield(){
  //  if(jewelField)delete[][](jewelField);
}

void Playfield::pauseGame(){
  if(!gamePaused){
    gamePaused=TRUE;
    killTimer(jewelTimerID);
    jewelTimerID=0;
    startStop->setText("Continue");
  }else{
    gamePaused=FALSE;
    jewelTimerID=startTimer(timeSteps);
    startStop->setText("Pause");
  };
}

void Playfield::startPauseGame(){

  if(gameStarted){
    pauseGame();
    return;
  };
  if(gameOver)
    StartProcedures();
  gameStarted=TRUE;
  gamePaused=FALSE;
  emit changeRunStatus(FALSE);
  activateNextJewel();
  startStop->setText("Pause");
}

void Playfield::notifyDifficulty(int d){

  printf("Setting difficulty to %d\n",d);
  difficulty=d;
  levelManagment();
  if(activeJewel)delete(activeJewel);
  activeJewel=new(Jewel)(3,colors);
  if(nextJewel)delete(nextJewel);
  nextJewel=new(Jewel)(3,colors);
  emit nextJewelChanged();
}

void Playfield::showList(){
  highscores->showList();
}

void Playfield::timerEvent(QTimerEvent *e){
  int s;
  static int i;

  noKeys=TRUE;
  if(e->timerId()==jewelTimerID){
    if(!collides(activeJewel->x(),activeJewel->y()-1)){
      erase(activeJewel->thisRect());
      activeJewel->step();
      repaint(activeJewel->thisRect(),FALSE);
      noKeys=FALSE;
    }else{
      killTimer(jewelTimerID);
      jewelTimerID=0;
      i=1;
      if(activeJewel->parts[0]==10)
	// We have a color Remove Jewel here
	s=removeColor();
      else{
	putJewel(); // normal Jewel;
	s=collectJewels();
      };
      if(s){
	score+=s*(difficulty+1)*(50<<i);
	emit changeScore(score);
	levelManagment();
	blinkStage=1;
	blinkTimerID=startTimer(100);
      }else{
	activateNextJewel();
      }
      return;
    }
  }else{
    if(blinkStage<5){
      blinkStage++;
      repaint(QRect(0,0,width(),height()),FALSE);
    }else{
      killTimer(blinkTimerID);
      blinkTimerID=0;
      repaint(QRect(0,0,width(),height()),FALSE);
      eraseJewels();
      if(s=collectJewels()){
	score+=s*(difficulty+1)*(50<<i);
	emit changeScore(score);
	levelManagment();
	blinkStage=1;
	blinkTimerID=startTimer(100);
	i++;
      }else{
	activateNextJewel();
      }
    }
  };
  return;
}

void Playfield::levelManagment(){
  level=jewels/20;
  // emit level Changed
  timeSteps=500-difficulty*50-level*50;
  timeSteps=timeSteps<70?70:timeSteps;
  colors=5+difficulty;
}

int Playfield::removeColor(){
  int color;
  int x,y;
  int s=0,i;
  QPainter painter;
  QBrush br;

  killTimer(jewelTimerID);
  jewelTimerID=0;
  if(activeJewel->y()){
    color=jewelField[activeJewel->x()][activeJewel->y()-1];
    for(y=0;y<sizeY;y++){
      for(x=0;x<sizeX;x++){
	delList[x][y]=FALSE;
      }
    };
    for(x=0;x<sizeX;x++){
      for(y=0;y<sizeY;y++){
	if(!jewelField[x][y])break;
	if(jewelField[x][y]==color || jewelField[x][y]==10){
	  s++;
	  delList[x][y]=TRUE;
	}
      }
    }
  };
  painter.begin(this);
  painter.setPen(NoPen);
  br.setStyle(SolidPattern);
  br.setColor(QColor("black"));
  x=activeJewel->x();
  y=activeJewel->y();
  //painter.setBrush(br);
  painter.fillRect(x*32+2,32*16-((y+2)*32+2),32,96,br);
  painter.end();
  return(s);
}
void Playfield::endEffect(){
  QPainter painter;
  struct timeval tv;

  tv.tv_sec=0;
  tv.tv_usec=1000;
  painter.begin(this);
  painter.setPen(QColor(0,0,0));
  long int n = this->width()*this->height();
  for (long int i=0; i<n;i++){
    select (0,NULL,NULL,NULL,&tv);
    painter.drawPoint((i*15379)%this->width(),
		      ((i*15379)/this->width())%this->height()
		      );
  };
  painter.end();
}

void Playfield::activateNextJewel(){

  *activeJewel=*nextJewel;
  if(collides(activeJewel->x(),activeJewel->y())){
    gamePaused=FALSE;
    gameStarted=FALSE;
    gameOver=TRUE;
    spacePressed=FALSE;
    endEffect();
    repaint();
    highscores->addToList(score,difficulty);
    highscores->writeList();
    startStop->setText("Start");
    return;
  };
  spacePressed=FALSE;
  jewelTimerID=startTimer(timeSteps);
  nextJewel->newJewel();
  emit nextJewelChanged();
  jewels++;
  repaint(activeJewel->thisRect(),FALSE);
  noKeys=FALSE;
}

int Playfield::collides(int x, int y){

  if(x<0 || x>=sizeX)return(TRUE);
  if(y<0)return(TRUE);
  if(jewelField[x][y])return(TRUE);
  return(FALSE);
}

int Playfield::collectInDirection(int x, int y, int dx, int dy)
{
  int l=1;
  short v=0;

  v=jewelField[x][y];
  while(x+dx*l>=0 && x+dx*l<sizeX && y+dy*l>=0 && y+dy*l<sizeY){
    //    printf("%d %d %d %d\n",x+dx*l,y+dy*l,v,jewelField[x+dx*l][y+dy*l]);
    if(v==jewelField[x+dx*l][y+dy*l] || jewelField[x+dx*l][y+dy*l]==100 ){
      l++;
      continue;
    };
    if(v==100){
      v=jewelField[x+dx*l][y+dy*l];
      if(!v)break;
      l++;     
      continue;
    };
    break;
  };
  //  printf("%d\n",l);
  if(l<3)return(0);
  //  printf("deleting %d: %d %d %d %d\n",l,x,y,dx,dy);
  for(v=0;v<l;v++)delList[x+v*dx][y+v*dy]=TRUE;
  return(l);
}

int Playfield::collectJewels()
{
  int x,y,dx,dy,s;
  int sum=0;

  // printf("Entering Collection\n");
  for(y=0;y<sizeY;y++){
    for(x=0;x<sizeX;x++){
      delList[x][y]=FALSE;
    }
  };
  for(y=0;y<sizeY;y++){
    for(x=0;x<sizeX;x++){
      if(jewelField[x][y]==0)continue;
      if(delList[x][y])continue;
      for(dx=-1;dx<=1;dx++){
	for(dy=-1;dy<=1;dy++){
	  if(dx==0 && dy==0)continue;
	  if(s=collectInDirection(x,y,dx,dy)){
	    sum+=s;
	    break;
	  }
	}
      }
    }
  };
  //  printf("Sum is:%d\n",sum);
  return(sum);
}

void Playfield::eraseJewels()
{
  short x,y,d;

  for(x=0;x<sizeX;x++){
    d=0;
    for(y=0;y<sizeY;y++){
      //      if(!jewelField[x][y])break;
      if(delList[x][y]){
	//	printf("%d %d\n",x,y);
	d--;
	continue;
      };
      jewelField[x][y+d]=jewelField[x][y];
    };
    for(y=sizeY+d;y<sizeY;y++)jewelField[x][y]=0;
  }
  for(x=0;x<sizeX;x++)
    for(y=0;y<sizeY;y++)
      delList[x][y]=0;
}

void Playfield::putJewel()
{
  int i;

  for(i=0;i<activeJewel->numParts;i++)
    jewelField[activeJewel->xp][activeJewel->yp+i]=activeJewel->parts[i];
}

void Playfield::paintEvent(QPaintEvent *pe){
  short  x,y,d,i;
  QPainter painter;
  QBrush brush(black);
  QRect updateRect;

  //if(!gameStarted)return;
  updateRect=pe->rect();

  if(updateRect==activeJewel->thisRect()){
    painter.begin(this);
    activeJewel->show(painter);
    painter.end();
    return;
  };
  // printf("repainting all\n");
  painter.begin(this);
  painter.setPen(NoPen);
  switch(blinkStage){
  case 0:
  case 5:
    for(x=0;x<sizeX;x++){
      d=0;
      for(y=0;y<sizeY;y++){
	if(!jewelField[x][y])break;
	if(delList[x][y]){
	  d--;
	  continue;
	};
	drawOneJewel(painter,x,y+d,jewelField[x][y]);
      };
      painter.setBrush(brush);
      for(i=d;i<0;i++) // clear above
	painter.fillRect(x*32+2,32*16-((y+i)*32+2),32,32,brush);
    };
    break;
  case 1:
  case 3:
    // The jewels are shown dark
    for(x=0;x<sizeX;x++){
      for(y=0;y<sizeY;y++){
	if(!jewelField[x][y])break;
	if(delList[x][y])
	  clearOneJewel(painter,x,y,jewelField[x][y]);
      }
    };
    break;
  case 2:
  case 4:
    // jewels are bright
    for(x=0;x<sizeX;x++){
      for(y=0;y<sizeY;y++){
	if(!jewelField[x][y])break;
	if(delList[x][y])
	  drawOneJewel(painter,x,y,jewelField[x][y]);
      }
    };
    break;
  };
  painter.setBrush(brush);
  if(gameOver){
    painter.setPen(QColor("peru"));
    painter.setFont(QFont( "helvetica", 20, QFont::Bold)); 
    painter.drawText(60,200,"Game Over",9);
  };
  if(gamePaused)activeJewel->show(painter);
  painter.end();
  return;
}

void Playfield::drawOneJewel(QPainter &p,short x,short y,short c){
  
  p.setPen(NoPen);
  if(c<100)
    p.drawPixmap(x*32+2,32*16-(y*32+2),*(activeJewel->jewelPixmaps[c]));
  else
    p.drawPixmap(x*32+2,32*16-(y*32+2),*(activeJewel->jewelPixmaps[0]));
}
void Playfield::clearOneJewel(QPainter &p,short x,short y,short c){
  QBrush br;
  
  p.setPen(NoPen);
  br.setStyle(SolidPattern);
  br.setColor(QColor("black"));
  p.fillRect(x*32+2,32*16-(y*32+2),32,32,br);
}
void Playfield::keyPressed(QKeyEvent *e)
{
  if (noKeys) return;
  switch(e->key()){
    case Key_Left:
      if(!gameStarted || gameOver)return;
      if(!collides(activeJewel->x()-1,activeJewel->y())){
        erase(activeJewel->thisRect());
        activeJewel->left();
        repaint(activeJewel->thisRect(),FALSE);
      };
      break;
    case Key_Right:
      if(!gameStarted || gameOver)return;
      if(!collides(activeJewel->x()+1,activeJewel->y())){
	erase(activeJewel->thisRect());
	activeJewel->right();
	repaint(activeJewel->thisRect(),FALSE);
      };
      break;
    case Key_Up:
      if(!gameStarted || gameOver)return;
      //      erase(activeJewel->thisRect());
      activeJewel->up();
      repaint(activeJewel->thisRect(),FALSE);
      break;
    case Key_Down:
      if(!gameStarted || gameOver)return;
      //      erase(activeJewel->thisRect());
      activeJewel->down();
      repaint(activeJewel->thisRect(),FALSE);
      break;
    case Key_Space:
      if(!gameStarted || gameOver)return;
      if(!spacePressed){
	spacePressed=TRUE;
	if(jewelTimerID){
	  killTimer(jewelTimerID);
	};
	erase(activeJewel->thisRect());
	while(!collides(activeJewel->x(),activeJewel->y()-1))
	  activeJewel->step();
	repaint(activeJewel->thisRect(),FALSE);
        jewelTimerID=startTimer(1);
      };
      break;
    case Key_P:
      if(gameStarted){
	pauseGame();
      };
      break;
  };
  return;
}

int *Playfield::getNextJewel(){
  static int col[4];
  int i;

  for(i=0;i<4;i++)col[i]=nextJewel->parts[i];
  return(col);
}
