#ifdef WIN32
#define STL_USING_ALL
#include "stl.h"
#endif

#include <GL/glut.h>
#include <string>
#include <vector>
#include <iostream>
#include <cmath>

#include "glpng/glpng.h"

#include "CException.h"
#include "CMove.h"
#include "Pieces.h"
#include "CBoard.h"
#include "CTexture.h"
#include "CWindow.h"
#include "CActiveWin.h"
#include "CWindowSection.h"
#include "CSectionBoard.h"

#include "Network.h"
#include "CNetMessage.h"
#include "CNetStream.h"

#include "CGameInfo.h"


void CSectionBoard::Display(void)
{
  PushMatrix();

  glEnable(GL_TEXTURE_2D);

  textureboard->Bind();

  glColor3f(1,1,1);
  glBegin(GL_QUADS);
  glTexCoord2f(0,4); glVertex2i(0,0);
  glTexCoord2f(0,0); glVertex2i(0,8);
  glTexCoord2f(4,0); glVertex2i(8,8);
  glTexCoord2f(4,4); glVertex2i(8,0);
  glEnd();

  if ((MotionPiece) && (board.IsMoveValid(CurrentMove)))
    {
      int x = CurrentMove.GetDestinationX();
      int y = CurrentMove.GetDestinationY();

      glDisable(GL_TEXTURE_2D);

      glColor4f(0.3, 0, 0, 1);
      glBegin(GL_QUADS);
      glVertex2i(x, y);
      glVertex2i(x+1, y);
      glVertex2i(x+1,y+1);
      glVertex2i(x,y+1);
      glEnd();

      glEnable(GL_TEXTURE_2D);
    }


  texturechess->Bind();
  board.Draw();

  if (MotionPiece)
    {
      MotionPiece->DragDraw(MotionPosX - OffsetX, MotionPosY - OffsetY);
    }

  glDisable(GL_TEXTURE_2D);

  PopMatrix();
}


void CSectionBoard::Motion(int x, int y)
{
  if ( (x>=0) && (x<Width) && (y>=0) && (y<Height) )
    {
      MotionPosX = ((float) (x << 3)) / ((float) Width);
      MotionPosY = 8.0f - ((float) (y << 3)) / ((float) Height);
      if ( (((int) MotionPosX) != CurrentMove.GetDestinationX()) ||
           (((int) MotionPosY) != CurrentMove.GetDestinationY()) )
        {
          CurrentMove.SetDestinationX(MotionPosX);
          CurrentMove.SetDestinationY(MotionPosY);

          if (MotionPiece)
            {
              if (board.IsMoveValid(CurrentMove))
                glutSetCursor(GLUT_CURSOR_CROSSHAIR);
              else
                glutSetCursor(GLUT_CURSOR_DESTROY);
            }
        }

      glutPostRedisplay();
    }
}



void CSectionBoard::Mouse(int button, int state, int x, int y)
{
  MotionPosX = ((float) (x << 3)) / ((float) Width);
  MotionPosY = 8.0f - ((float) (y << 3)) / ((float) Height);

  if (button == GLUT_LEFT_BUTTON)
    {
      if (state == GLUT_DOWN)
        {
          if ( (x>=0) && (x<=Width) && (y>=0) && (y<=Height) )
            {
              if ( (board(MotionPosX, MotionPosY)->GetColor() ==
                    board.GetTurn()) &&
                   (board.GetTurn() == g_gameinfo.PlayerColor) )
                {
                  CurrentMove.SetSourceX(MotionPosX);
                  CurrentMove.SetDestinationX(MotionPosX);
                  CurrentMove.SetSourceY(MotionPosY);
                  CurrentMove.SetDestinationY(MotionPosY);

                  try
                    {
                      MotionPiece = board(MotionPosX, MotionPosY)->GetCopy(0);
                    }
                  catch (CFatalError Error)
                    {
                      std::cerr << Error.GetErrorString();
                      exit(1);
                    }

                  OffsetX = MotionPosX - floorf(MotionPosX);
                  OffsetY = MotionPosY - floorf(MotionPosY);

                  glutSetCursor(GLUT_CURSOR_DESTROY);
                }
            }
        }

      if ( (state == GLUT_UP) && (MotionPiece) )
        {
          delete MotionPiece;
          MotionPiece = 0;
          glutSetCursor(GLUT_CURSOR_LEFT_ARROW);

          if ( (x>=0) && (x<=Width) && (y>=0) && (y<=Height) )
            {
              CurrentMove.SetDestinationX(MotionPosX);
              CurrentMove.SetDestinationY(MotionPosY);

              if ((board.IsMoveValid(CurrentMove)) ||
                  (GLUT_ACTIVE_CTRL == glutGetModifiers()))
                {
                  board.Move(CurrentMove);
                  n_in_out << CNetMessage(MESSAGE_MOVE, &CurrentMove);
                  board.SwitchTurn();
                }
            }
        }

      glutPostRedisplay();
    }
}


void CSectionBoard::LoadTexture(void)
{
  if (textureboard)
    {
      if (textureboard->GetName() != FileBoard)
        {
          delete textureboard;
          textureboard = 0;
        }
    }
  if (texturechess)
    {
      if (texturechess->GetName() != FileChess)
        {
          delete texturechess;
          texturechess = 0;
        }
    }

  if (!textureboard)
    {
      textureboard = new CTexture(FileBoard);
      if (!textureboard)
        throw MEMORY_ERROR;
    }
  if (!texturechess)
    {
      texturechess = new CTexture(FileChess);
      if (!texturechess)
        throw MEMORY_ERROR;
    }
}



CSectionBoard::CSectionBoard(CWindow* parent, const std::string& boardfile,
                             const std::string& chessfile,
                             const CBoard& theboard)
  : CWindowSection(parent, 20, 20, 300, 300), CurrentMove(0,0,0,0)
{
  FileBoard = boardfile;
  FileChess = chessfile;
  board = theboard;

  textureboard = 0;
  texturechess = 0;

  MotionPiece = 0;
}
