/*  
    Crystal Shooter, a first person shooter game engine.
    Homepage: http://members.xoom.com/thieber/cs

    Copyright (C) 1999 Thomas Hieber (thieber@gmx.net)
 
    This program is free software; you can redistribute it and/or modify 
    it under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2 of the License, or 
    (at your option) any later version. 
 
    This program is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details. 
 
    You should have received a copy of the GNU General Public License 
    along with this program; if not, write to the Free Software 
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
*/

#include "csgame/gstd.h"
#include "sentry.h"
#include "shooter.h"
#include "csgeom/csrect.h"
#include "qint.h"

#include "csengine/pol2d.h"
#include "csengine/polygon.h"

geMenuInterface::geMenuInterface(geSystem* pSystem)
 : geUserInterface(pSystem)
{
  m_CurrentOption  = 0;

  m_pLogo          = NULL;
  m_pLegal         = NULL;   
  m_pCslogo        = NULL;  
  m_pCslegal       = NULL;
  m_pNew1          = NULL;    
  m_pNew2          = NULL;    
  m_pLoad1         = NULL;   
  m_pLoad2         = NULL;   
  m_pOptions1      = NULL;
  m_pOptions2      = NULL;
  m_pQuit1         = NULL;   
  m_pQuit2         = NULL;   
}

geMenuInterface::~geMenuInterface()
{
  delete m_pLogo;
  delete m_pLegal;
  delete m_pCslogo;
  delete m_pCslegal;
  delete m_pNew1;
  delete m_pNew2;
  delete m_pLoad1;
  delete m_pLoad2;
  delete m_pOptions1;
  delete m_pOptions2;
  delete m_pQuit1;
  delete m_pQuit2;
}

bool geMenuInterface::Init(int argc, char* argv[])
{
  if (!geUserInterface::Init(argc, argv)) return false;

  m_pLogo     = CreateSprite("logo.gif");
  m_pLegal    = CreateSprite("legal.gif");
  m_pCslogo   = CreateSprite("cslogo.gif");
  m_pCslegal  = CreateSprite("cslegal.gif");
  m_pNew1     = CreateSprite("new1.gif");
  m_pNew2     = CreateSprite("new2.gif");
  m_pLoad1    = CreateSprite("load1.gif");
  m_pLoad2    = CreateSprite("load2.gif");
  m_pOptions1 = CreateSprite("options1.gif");
  m_pOptions2 = CreateSprite("options2.gif");
  m_pQuit1    = CreateSprite("quit1.gif");
  m_pQuit2    = CreateSprite("quit2.gif");

  csTextureHandle* hTex = m_pSystem->GetTexture("shotfont1.gif");
  if (!hTex) return false;

  m_Font      = hTex->GetTextureHandle();

  if (!m_Font) return false;

  hTex = m_pSystem->GetTexture("shotfont2.gif");
  if (!hTex) return false;

  m_Shadow = hTex->GetTextureHandle();

  //todo: Need to do checks if all Sprites were created!!!
  return true;
}

void geMenuInterface::EatKeypress (int key, bool /*shift*/, bool /*alt*/, bool /*ctrl*/)
{
//  csSoundBuffer* wMissile_boom;

  switch (key)
  {
    case 'q':
      //Make the system quit the render loop.
      m_pSystem->EndLoop();
      break;
    case CSKEY_UP:
      m_CurrentOption--;
      if (m_CurrentOption < 0) m_CurrentOption = 0;
      break;
    case CSKEY_DOWN:
      m_CurrentOption++;
      if (m_CurrentOption > 3) m_CurrentOption = 3;
      break;
    case CSKEY_ENTER:
    {
      switch (m_CurrentOption)
      {
        case 0: //NewGame
          m_pSystem->SetCurrentUI(geShooter::GameUI);
          break;
        case 1: //Load Game
          break;
        case 2: //Options
          break;
        case 3: //Quit
          m_pSystem->EndLoop();
          break;
      }    
      break;
    }
    default:
      break;
  }
}

void geMenuInterface::PrepareFrame (long /*elapsed_time*/, long /*current_time*/)
{
}

void geMenuInterface::Write(int x, int y, int size, RGBcolor topcolor, RGBcolor bottomcolor, const char* text)
{
  float corrx = (float)m_FrameWidth  / 640.0f;
  float corry = (float)m_FrameHeight / 480.0f;
  
  x  = QInt (x * corrx);
  y  = QInt (y * corry);
  int h  = (int)(size * corry);
  int w  = (int)(size * corrx * 0.7f);
  int fa = (int)(size * corrx * 0.12f);
  int sx = (int)(w/4);
  int sy = (int)(h/5);

  WriteShandowText(m_piG3D, m_Font, m_Shadow, x, y, w, h, fa, sx, sy,
                   topcolor, bottomcolor, text);
}

void geMenuInterface::DrawFrame3d  (long elapsed_time, long current_time)
{
  inherited::DrawFrame3d(elapsed_time, current_time);

  Write(320, 410, 60, RGBcolor(255,255,0), RGBcolor(255, 0,0), "CRYSTAL SHOOTER");

  RGBcolor c1(128+(int)(127*sin(0.0010*current_time)), 
              128+(int)(127*cos(0.0015*current_time)),  
              128+(int)(127*sin(0.0008*current_time)));
  RGBcolor c2(128+(int)(127*sin(0.0013*current_time)), 
              128+(int)(127*cos(0.0008*current_time)), 
              128+(int)(127*sin(0.0011*current_time)));
  RGBcolor c3(128, 128, 128);
  RGBcolor c4(255, 255, 255);

  if (m_CurrentOption == 0)
  {
    Write(320, 280, 50, c1, c2, "NEW GAME");
  } 
  else
  {
    Write(320, 280, 50, c3, c4, "NEW GAME");
  }
                                                                        
  if (m_CurrentOption == 1)                                               
  {                                                                       
    Write(320, 220, 50, c1, c2, "LOAD GAME");
  }                                                                       
  else
  {
    Write(320, 220, 50, c3, c4, "LOAD GAME");
  }
                                                                        
  if (m_CurrentOption == 2)                                               
  {                                                                       
    Write(320, 160, 50, c1, c2, "OPTIONS");
  }                                                                       
  else
  {
    Write(320, 160, 50, c3, c4, "OPTIONS");
  }
                                                                        
  if (m_CurrentOption == 3)                                               
  {                                                                       
    Write(320, 100, 50, c1, c2, "QUIT");
  }
  else
  {
    Write(320, 100, 50, c3, c4, "QUIT");
  }
}

void geMenuInterface::DrawFrame2d  (long /*elapsed_time*/, long /*current_time*/)
{
  //DrawSprite(m_pLogo,    320, 0,   h_align_mid,   v_align_top);
  DrawSprite(m_pLegal,   320, 80,  h_align_mid,   v_align_top);
  DrawSprite(m_pCslegal, 5,   475, h_align_left,  v_align_bottom);
  DrawSprite(m_pCslogo,  635, 475, h_align_right, v_align_bottom);

                                                                       
}

void geMenuInterface::Activate()
{
}

//---------------------------------------------------------------------------

geGameInterface::geGameInterface(geSystem* pSystem)
 : geUserInterface(pSystem)
{
}

geGameInterface::~geGameInterface()
{
}

bool geGameInterface::Init(int argc, char* argv[])
{
  if (!geUserInterface::Init(argc, argv)) return false;

  return true;
}

void RandomColor (float& r, float& g, float& b)
{
  switch ((rand ()>>3) % 3)
  {
    case 0:
      r = (float)(900+(rand () % 100))/1000.;
      g = (float)(rand () % 1000)/1000.;
      b = (float)(rand () % 1000)/1000.;
      break;
    case 1:
      r = (float)(rand () % 1000)/1000.;
      g = (float)(900+(rand () % 100))/1000.;
      b = (float)(rand () % 1000)/1000.;
      break;
    case 2:
      r = (float)(rand () % 1000)/1000.;
      g = (float)(rand () % 1000)/1000.;
      b = (float)(900+(rand () % 100))/1000.;
      break;
  }
}

void geGameInterface::EatKeypress (int key, bool /*shift*/, bool /*alt*/, bool /*ctrl*/)
{
  gePlayer* pPlayer = m_pSystem->m_pWorld->GetPlayer();
  ASSERT(pPlayer);

  switch (key)
  {
    case CSKEY_ESC:
      //Switch back to Menu
      m_pSystem->SetCurrentUI(geShooter::MenuUI);
      break;
    case ' ':
    {
      pPlayer->Shoot();
      break;
    }
    case 'm':
    case 'M':
    {
      geSentry* pSentry = new geSentry(m_pSystem->m_pWorld);
      gePosition Pos = pPlayer->GetPosition();

      Pos.Move(csVector3(4.0f*sin(pPlayer->GetRotation()),
                         -0.4f,
                         4.0f*cos(pPlayer->GetRotation())));

      //Pos.Move(pPlayer->GetViewDirection()*2.0);
      pSentry->Create(Pos);
      break;
    }
    default:
      break;
  }
}

void geGameInterface::EatMousemove (int x, int y)
{
  int DeltaX = x-m_FrameWidth/2;
  int DeltaY = y-m_FrameHeight/2;

  /*char str[1000];
  sprintf(str, "%d %d", DeltaX, DeltaY);
  OutputDebugString(str);*/
  
  //Change pitch and angle according to mouse movement
  m_pSystem->m_pWorld->GetPlayer()->Rotate(DeltaX * 0.01);
  m_pSystem->m_pWorld->GetPlayer()->Pitch (DeltaY * 0.01);
  
  m_piG2D->SetMousePosition(m_FrameWidth/2, m_FrameHeight/2);
}

void geGameInterface::PrepareFrame (long elapsed_time, long current_time)
{
  //-----
  //Avoid that the player passes through walls. I think that system still needs
  //a lot of work to be done, but at least it works for now.
  //-----
  DoCollisionDetection();

  //Call all game Objects
  m_pSystem->m_pWorld->PrepareFrame(elapsed_time, current_time);
  
  //Check which keys are corrently pressed to decide where to move.
  MoveCamera(elapsed_time);
}

void geGameInterface::DrawFrame2d  (long /*elapsed_time*/, long /*current_time*/)
{
  //Draw HUD here... later...
}

void geGameInterface::DoCollisionDetection()
{
  /*
  //-------------------------------------------------------------------------
  //Collision detection
  //-------------------------------------------------------------------------
  csCamera c;
  c.set_sector(m_pView->camera->get_sector());
  c.set_position(m_pView->camera->v_origin());

  //First init the camera with a standard view Matrix
  Matrix3 m(1,0,0, 0,1,0, 0,0,1);
  c.set_world2cam(m);
  //Now rotate the camera according to the calculated angles.
  c.rotate_w (VEC_ROT_RIGHT, m_pSystem->GetCamera()->m_CameraRotation);

  Being::player->sector = m_pView->camera->get_sector();
  Being::player->transform = &c;
  Being::player->collision_detect ();    
  
  // Load player transformation back into camera.
  m_pView->camera->set_position(Being::player->transform->v_world2this());
  m_pView->camera->set_sector(Being::player->sector);
  */
}

void geGameInterface::MoveCamera(long elapsed_time)
{
  float speed = elapsed_time * 0.04;

  gePlayer* pPlayer = m_pSystem->m_pWorld->GetPlayer();
  ASSERT(pPlayer);

  if (m_pSystem->GetKeyboard()->Key.up)
  {
    pPlayer->Walk(speed*0.2);
  }
  if (m_pSystem->GetKeyboard()->Key.down)
  {
    pPlayer->Walk(-speed*0.2);
  }
  if (m_pSystem->GetKeyboard()->Key.right) 
  {
    pPlayer->Strafe(speed*0.2);
  }
  if (m_pSystem->GetKeyboard()->Key.left)  
  {
    pPlayer->Strafe(-speed*0.2);
  }
}

//---------------------------------------------------------------------------

geCamera::geCamera()
  : m_CameraPosition(0,0,0),
    m_CameraRotation(0.0),
    m_CameraPitch   (0.0)
{
}

geCamera::~geCamera()
{
}

void geCamera::AdjustCamera(csCamera* pCamera)
{
  //m_CameraPosition = m_pView->camera->v_origin();

  //First init the camera with a standard view Matrix
  csMatrix3 m(1,0,0, 0,1,0, 0,0,1);
  pCamera->SetW2C(m);

  //Now rotate the camera according to the calculated angles.
  pCamera->RotateWorld(VEC_ROT_RIGHT, m_CameraRotation);
  pCamera->Rotate     (VEC_RIGHT,     m_CameraPitch);
}

//---------------------------------------------------------------------------


geShooter::geShooter()
{
  m_pSystem = new geSystem;

  m_AllUIs         = new geUserInterface*[NumUIs];
  m_AllUIs[MenuUI] = new geMenuInterface(m_pSystem);
  m_AllUIs[GameUI] = new geGameInterface(m_pSystem);

  m_pSystem->SetAllUIs(m_AllUIs);
  m_pSystem->SetCurrentUI(MenuUI);
}

geShooter::~geShooter()
{
  for (int i=0; i<NumUIs; i++)
  {
    delete m_AllUIs[i];
  }
  delete [] m_AllUIs;

  delete m_pSystem;
}

bool geShooter::Init(int argc, char* argv[])
{
  if (!m_pSystem->Init(argc, argv)) return false;
  for (int i=0; i<NumUIs; i++)
  {
    if (!m_AllUIs[i]->Init(argc, argv)) return false;
  }

  int pixelbytes = 0;
  m_pSystem->piGI->GetPixelBytes(pixelbytes);

  if (pixelbytes != 2 && pixelbytes != 4)
  {
    m_pSystem->Printf(MSG_FATAL_ERROR, 
      "Crystal Shooter will only work in 16Bit color mode or 32Bit color mode!");
    return false;
  }

  return true;
}

void geShooter::Go()
{
  ASSERT(m_pSystem);
  m_pSystem->Loop();
}


//Dummyfunction, that is needed by cspace.lib :-(
void cleanup ()
{
}

//Dummyfunction, that is needed by cspace.lib :-(
void debug_dump ()
{
}

/*---------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  geShooter Game;

  if (!Game.Init(argc, argv))
  {
    fatal_exit (0, false);
  }

  Game.Go();

  return (0);
}
