/*  
    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 "sysdef.h"
#include "csgame/gstd.h"
#include "csgame/gsystem.h"

geSystem::geSystem()
{
  m_pView      = NULL;
  m_pCurrentUI = NULL;
  m_AllUIs     = NULL;
  m_pWorld     = NULL;
}

geSystem::~geSystem()
{
  csBeing::EndWorld();
  delete m_pWorld;
  //delete m_pView; //todo: Will cause a crash in  g3d_d3d.cpp line 591. (think it is correct though!)
}

bool geSystem::Init(int argc, char* argv[])
{
  //-------------------------------------------------------------------------
  //First adjust some configuration
  //-------------------------------------------------------------------------
  CHK (config = new csIniFile ("shooter.cfg"));
  
  csCamera::aspect                = 0;

  //-------------------------------------------------------------------------
  //Create a new World
  //-------------------------------------------------------------------------
  CHK (m_pCsWorld = new csWorld ());

  //-------------------------------------------------------------------------
  //Initialize the SystemInterface
  //-------------------------------------------------------------------------
  Initialize (argc, argv, m_pCsWorld->GetEngineConfigCOM ());

  //-------------------------------------------------------------------------
  //Try to open the Window for the Shooter
  //-------------------------------------------------------------------------
  if (!Open ("Crystal Shooter"))
  {
    return false;
  }

  //-------------------------------------------------------------------------
  //Initialize the World: 
  //-------------------------------------------------------------------------
  ITextureManager* txtmgr = NULL;
  piG3D->GetTextureManager (&txtmgr);
  m_pCsWorld->Initialize (GetISystemFromSystem (this), piG3D, config);
  txtmgr->Initialize();
  txtmgr->ReserveColor (0, 0, 0);
  txtmgr->ReserveColor (255, 255, 255);
  txtmgr->Prepare ();
  txtmgr->AllocPalette ();

  // Create console object for text and commands.
  geConsole* pCon = new geConsole ();
  CHK (Console = pCon);
  pCon->SetupColors (txtmgr);
  pCon->SetMaxLines (1000);       // Some arbitrary high value.
  pCon->SetTransparent (1);

  DemoReady = true;

  Printf (MSG_INITIALIZATION, "Crystal Shooter\n");
  Printf (MSG_INITIALIZATION, "Created by Thomas Hieber\n");
  Printf (MSG_INITIALIZATION, "Based on Crystal Space, written by Jorrit Tyberghein and others...\n\n");

  //txtmgr->SetVerbose (true);

  //create view. (it will automatically create a camera by itself.)
  m_pView  = new csView(m_pCsWorld, piG3D);

  //-------------------------------------------------------------------------
  //load world from file.
  //-------------------------------------------------------------------------
  char worldfile[256];
  strcpy (worldfile, config->GetStr ("World", "WORLDFILE", "maze.zip"));
  if (!CSLoader::LoadWorldFile (m_pCsWorld, NULL, worldfile))
  {
    char ErrorMessage[1000];
    sprintf(ErrorMessage, "Could not load worldfile '%s'", worldfile);
    Alert (ErrorMessage);
    delete m_pCsWorld;
    return false;
  }

  //Load our own standards library
  CSLoader::LoadLibrary (m_pCsWorld, "shootlib_g", "shtlib_g.zip");
  //Load our own standards library
  CSLoader::LoadLibrary (m_pCsWorld, "shootlib_m", "shtlib_m.zip");

  //Mark all textures for 2d use. Later, that code should be replaced by dynamic change 
  //of this flag, when needed. Jorrit says this is possible, and will be the way to go
  //in the future.
  csTextureList *texlist = m_pCsWorld->GetTextures ();
  if (texlist)
  {
    for (int i = 0; i < texlist->GetNumTextures (); i++)
    {
      csTextureHandle *texh = texlist->GetTextureMM (i);
      if (texh)
      {
        texh->for_2d = true;
      }
    }
  }
  
  // Prepare the world. This will calculate all lighting and
  // prepare the lightmaps for the 3D rasterizer.
  m_pCsWorld->Prepare (piG3D);

  m_pWorld = new geWorld(m_pCsWorld);

  //initialize collision detection.
  m_pWorld->InitCollisionDetection();

  //-------------------------------------------------------------------------
  //Look for the starting Sector
  //-------------------------------------------------------------------------
  //if world->start_sector==NULL we use "room" as default
  const char* strt = m_pCsWorld->start_sector ? m_pCsWorld->start_sector : "room";
  //find the sector with that name
  csSector* room = (csSector*)m_pCsWorld->sectors.FindByName (strt);
  //If we have no sector to start from, we quit
  if (!room) return false;

  //-------------------------------------------------------------------------
  //Initialize the View. The View will take care of handling the camera and
  //the world objects. It will also take care of the rendering process later
  //on.
  //-------------------------------------------------------------------------
  //Set the current sector for that view
  m_pView->SetSector(room);
  //Set the position for the camera
  m_pView->GetCamera()->SetPosition(m_pCsWorld->start_vec);
  //Set the screen area for rendering
  m_pView->SetRectangle (0, 0, FrameWidth - 0, FrameHeight - 0);

  m_pWorld->SetView(m_pView);
  m_pWorld->GetPlayer()->SetPosition(room, m_pCsWorld->start_vec);

  csBeing::InitWorld(m_pCsWorld,m_pView->GetCamera());

  piG2D->SetMousePosition(FrameWidth/2, FrameHeight/2);

  DemoReady = false;

  return true;
}

void geSystem::Done()
{
}

void geSystem::EatKeypress (int key, bool shift, bool alt, bool ctrl)
{
  ASSERT(m_pCurrentUI);
  m_pCurrentUI->EatKeypress(key, shift, alt, ctrl);
}

void geSystem::EatMousemove (int x, int y)
{
  ASSERT(m_pCurrentUI);
  m_pCurrentUI->EatMousemove(x,y);
}

void geSystem::NextFrame (long elapsed_time, long current_time)
{
  //-----
  // elapsed_time is the time in milliseconds elapsed since the
  // previous call to NextFrame. current_time is a global time
  // counter
  //-----
  SysSystemDriver::NextFrame (elapsed_time, current_time);

  //-----
  // First handle all events since the previous frame.
  //-----
  csEvent *event;
  while ((event = EventQueue->Get ()))
  {
    switch (event->Type)
    {
      case csevKeyDown:
      {
        EatKeypress (event->Key.Code,
                     event->Key.ShiftKeys & CSMASK_SHIFT,
                     event->Key.ShiftKeys & CSMASK_ALT,
                     event->Key.ShiftKeys & CSMASK_CTRL);
        break;
      }
      case csevMouseMove:
      {
        EatMousemove(event->Mouse.x, event->Mouse.y);
        break;
      }
      default: 
      {
        break;
      }
    }
    delete event;
  }

  ASSERT(m_pCurrentUI);

  //-----
  // Advance all sprite animation frames in the world.
  //-----
  //m_pCsWorld->AdvanceSpriteFrames (current_time);

  m_pCurrentUI->PrepareFrame (elapsed_time,current_time);

  // start drawing 3D graphics ...
  piG3D->BeginDraw (CSDRAW_3DGRAPHICS);
  m_pCurrentUI->DrawFrame3d(elapsed_time,current_time);

  //Draw testimages for DrawPolyFX
  //ITextureHandle *handle=GetTexture("test1.gif")->GetTextureHandle();
  //DisplayFXTextpattern(piG3D, handle);

  // now draw everything in 2D we have to draw ...
  piG3D->BeginDraw (CSDRAW_2DGRAPHICS);
  m_pCurrentUI->DrawFrame2d(elapsed_time,current_time);

  piG3D->FinishDraw ();
  piG3D->Print (NULL);
}

void geSystem::SetCurrentUI(int Nr)
{ 
  if (m_pCurrentUI)
  {
    m_pCurrentUI->Deactivate();
  }

  m_pCurrentUI = m_AllUIs[Nr];
  m_pCurrentUI->Activate();
}


csTextureHandle*  geSystem::GetTexture(char* name)
{
  ASSERT(m_pCsWorld);
  return m_pCsWorld->GetTextures()->GetTextureMM(name);
}

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