/*
 * PVVMUD a 3D MUD
 * Copyright (C) 1998-1999  Programvareverkstedet (pvv@pvv.org)
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "client.H"
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <iostream.h>
#include <netinet/in.h>
#include "socket.H"
#include "clisrvmanager.H"
#include "msgsrvcli.H"
#include "pvvmudclient.H"

#include "glgeometry.H"
#include "glmaterial.H"
#include "gltexture.H"

CCliSrvManager::CCliSrvManager(CCliSrvProtocol * protocol,CTimeKeeper * timeKeeper):CManager(protocol){
  m_timeKeeper = timeKeeper;
  getProtocol()->setName("Server");
  getProtocol()->setManager(this);
  m_world = new CCliWorld();
  m_viewpoint = new CCliViewpoint(m_world);
  m_cligos = NULL;
  m_worldsrv = NULL;

}

CCliSrvManager::~CCliSrvManager(){
  if (m_world != NULL) delete m_world;
  if (m_viewpoint != NULL) delete m_viewpoint;
#ifndef TEXTURECACHE_USEFILE
  if (m_cligos != NULL) delete m_cligos;
#endif
}

void CCliSrvManager::setClient(CPvvmudClient * client) {
  m_client = client;
}

CPvvmudClient * CCliSrvManager::getClient() {
  return m_client;
}

COption * CCliSrvManager::getOption() {
  return m_client->getOption();
}

void CCliSrvManager::communicate(){
  getProtocol()->readyToRead();
  getProtocol()->readyToWrite();
}

void CCliSrvManager::init(){
  cdebug << "Client manager init\n";
//  createStartFrame();
}

void CCliSrvManager::hello(){
  getProtocol()->login(getOption()->getString("username"),
                       getOption()->getString("passwd"),
                       FALSE);  // This is not a new user!
}

void CCliSrvManager::serverInfo(CInetAddress * worldSrvAddress,CInetAddress * gosAddress){

#ifndef TEXTURECACHE_USEFILE
  try {

    m_cligos = new CCliGOS(this,m_timeKeeper, gosAddress);
    cdebug << "Client GOS manager connected.\n";

  } catch (CSocketException * e){

    cdebug << "Failed to connect to GOS\n";
    m_cligos = NULL;

  }
#endif

  try {

    CClientSocket * socket = 
      new CClientSocket(worldSrvAddress->getAddress(),worldSrvAddress->getPort());

    socket->setNonBlocking();
    cdebug << "Client World manager connected.\n";

    m_worldsrv = 
      new CCliWorldManager(this, new CCliWorldProtocol(socket,m_timeKeeper));

  } catch (CSocketException * e){

    cdebug << "Failed to connect to world server\n";
    m_worldsrv = NULL;

  }

  if (m_cligos != NULL && m_worldsrv != NULL){
//    getProtocol()->sendGetWorld();
//    deleteStartFrame();

    getProtocol()->sendOnline();

  } else {
    quit();
  }

}




void CCliSrvManager::quit(){
  getProtocol()->bye();
}

void CCliSrvManager::exit(){
  ::exit(0);
}

void CCliSrvManager::changeMasterCellId(DWORD newMasterCellId){
  m_worldsrv->getProtocol()->sendChangeMasterCell(newMasterCellId); 
}

void CCliSrvManager::createStartFrame(){
  double trans[3];
  trans[0] = 0; trans[1] = 80; trans[2] = 0;
  double rot[3];
  rot[0] = 90; rot[1] = 0; rot[2] = 0;
//  world->addObject(-1,0,0,trans,rot);
}

void CCliSrvManager::deleteStartFrame(){
  clearWorld();
}

void CCliSrvManager::animate(){
  m_world->animate();
}

void CCliSrvManager::draw(CRenderer * renderer){
  m_world->draw(renderer);
}

void CCliSrvManager::updateViewpoint( const CPosition & position,
                          const CDirection & direction,DWORD targetId ){
  m_viewpoint->setPosition( position );
  m_viewpoint->setDirection( direction );
  m_viewpoint->setTargetId( targetId );
  cdebug << "Viewpoint: Target: " << targetId << " Pos: " << position 
       << " Dir: " << direction << "\n";
}

void CCliSrvManager::playerMove( int move ){
  getProtocol()->sendCommand( move);
}

void CCliSrvManager::playerLook( int look ){
  getProtocol()->sendCommand( look);
}

void CCliSrvManager::userCommand(int num){
  if ((num >= USERCOMMAND_1) && (num <= USERCOMMAND_5)){
    doAction(num - USERCOMMAND_1);
  } else {
    getProtocol()->sendCommand( num);
  }
}

void CCliSrvManager::selection(int objectId){
  getProtocol()->sendSelection( objectId );
}

void CCliSrvManager::sendMsg( const char * msg ){
  getProtocol()->sendMsg( msg );
}

void CCliSrvManager::sendPing(){
  if (m_worldsrv != NULL) m_worldsrv->sendPing();
}

void CCliSrvManager::clearWorld(){
  m_world->clearWorld();
}

void CCliSrvManager::doAction(int actionNum){
  cdebug << "Do action " << actionNum+1 << " on object "  
       << actionObjectId[actionNum] << "\n";
  getProtocol()->sendAction(actionObjectId[actionNum],actionNum+1);
}

void CCliSrvManager::addAction(int objectId, CAction * action){
  actionObjectId[action->getId()-1] = objectId;
}

int CCliSrvManager::request(int requestType,int requestId){
  cdebug << "Request("<<requestType<<") for : " << requestId << "\n";
  if (m_cligos != NULL) {
    m_cligos->request(requestType,requestId);
    return TRUE;
  } 
  return FALSE;
}

void CCliSrvManager::addGeometry(CGeometry * geometry){

  CGeometry * geo = getClient()->getGeometryCache()->add(geometry);
  if (geo != NULL) delete geo;

  cdebug << "Geometry " << geometry->getId() << " loaded\n";

#ifdef USE_LOCAL_FILE_CACHE
  DIR * dir = opendir("goscache");
  if (dir != NULL){
    closedir(dir);
  } else {
    mkdir("goscache",S_IRWXU);
  }
  char fileName[256];
  sprintf(fileName,"goscache/%i.bog",geometry->getId());
  geometry->save(fileName);
#endif // USE_LOCAL_FILE_CACHE

}

void CCliSrvManager::addMaterial(CMaterial * material){

  CMaterial * mat = getClient()->getMaterialCache()->add(material);
  if (mat != NULL) delete mat;

  cdebug << "Material " << material->getId() << " loaded\n";

#ifdef USE_LOCAL_FILE_CACHE
  DIR * dir = opendir("goscache");
  if (dir != NULL){
    closedir(dir);
  } else {
    mkdir("goscache",S_IRWXU);
  }
  char fileName[256];
  sprintf(fileName,"goscache/%i.bmat",material->getId());
  material->save(fileName);
#endif // USE_LOCAL_FILE_CACHE

}

void CCliSrvManager::addTexture(CTexture * texture){

  CTexture * tex = getClient()->getTextureCache()->add(texture);
  if (tex != NULL) delete tex;

  cdebug << "Texture " << texture->getId() << " loaded\n";

#ifdef USE_LOCAL_FILE_CACHE
  DIR * dir = opendir("goscache");
  if (dir != NULL){
    closedir(dir);
  } else {
    mkdir("goscache",S_IRWXU);
  }
  char fileName[256];
  sprintf(fileName,"goscache/%i.tex",texture->getId());
  texture->save(fileName);
#endif // USE_LOCAL_FILE_CACHE

}


void CCliSrvManager::dump(){
  m_world->dump();
}

CGeometry * CCliSrvManager::newGeometry(int geometryId){
  return new CGLGeometry(geometryId);
}

CMaterial * CCliSrvManager::newMaterial(int materialId){
  return new CGLMaterial(materialId);
}

CTexture * CCliSrvManager::newTexture(int textureId){
  return new CGLTexture(textureId);
}