/*
 * 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 "server.H"
#include <iostream.h>
#include "srvclimanager.H"
#include "srvcliprotocol.H"
#include "mud.H"
#include "viewpoint_1p.H"

static int currSrvCliId = 0;

CClientManager::CClientManager(CMud * mud, CSrvProtocol * protocol):CManager(protocol){
  m_mud = mud;
  m_viewpoint = new CViewpoint_1p();
  // status = MANAGER_INIT;
  m_commandParser = new CSrvCliCmdParser(mud,this);

  // Set client connection name
  char name[16];
  sprintf(name,"Client %i",currSrvCliId++);
  getProtocol()->setName(name);

  getProtocol()->sendHello();
  // status = MANAGER_LOGIN;
  m_quit = FALSE;
}

CClientManager::~CClientManager(){
  cdebug << "Destructor CClientManager\n";
  if (m_viewpoint != NULL) delete m_viewpoint;
}

void CClientManager::quit(){
  m_quit = TRUE;
  m_mud->markClient();
}

CWorldWorld * CClientManager::getWorld(){
  return m_mud->getWorld();
}

void CClientManager::setPlayer(CPlayer * player){
  m_player = player;
}

void CClientManager::login(char * name,char *passwd,BOOL newUser){
  static CInetAddress noAddr;

  setName(name);

  if (!m_mud->getUserDB()->verifyUser(name,passwd)){ 
    // Login failed
    sendMsg("Failed to verify username and password!");
    quit();
    return;
  }

  CInetAddress * worldAddr = m_mud->getWorldSrvAddress();
  if (worldAddr == NULL) worldAddr = &noAddr;
  CInetAddress * gosAddr = m_mud->getGOSAddress();
  if (gosAddr == NULL) gosAddr = &noAddr;

  cdebug << "ServerInfo : world = " << *worldAddr 
       << " GOS = " << *gosAddr << "\n"; 

  getProtocol()->sendServerInfo(*worldAddr,*gosAddr);

}

void CClientManager::online(){
  cdebug << "Client online\n";

  CSrvObject * cell = (CSrvObject*)getWorld()->getObject("cell5");  

  if (cell != NULL){

    m_player = (CPlayer*)cell->createObject("player",0,CPosition(0,0,0),
      CDirection(0,0,0),getName());
    cdebug << "Player created\n";

    m_player->setManager(this); 

    m_viewpoint->setTargetId(m_player->getObjectId());
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );

    sendWorld();
  } else {
    cdebug << "Player online failed to get cell!\n";
  }

}

void CClientManager::logout(){
  cdebug << "Player " << m_player->getName() << " logout!\n";
  sendBye(MSGBYE_QUIT);
  CWorldObject * parent = (CWorldObject*)m_player->getParent();
  if (parent != NULL){
    parent->removeObject(m_player);
  }
}

void CClientManager::sendWorld(){
  CWorldObject * parent = (CWorldObject*)m_player->getParent();
  if (parent != NULL){
    getProtocol()->sendClearWorld();
    getProtocol()->sendPlayerInfo(parent->getObjectId());
//    getProtocol()->sendCell(cell);
  }
}

void CClientManager::sendBye(WORD reason){
  getProtocol()->sendBye(reason);
}

void CClientManager::userCommand(WORD command){
  switch(command){
  case PLAYERMOVE_STEPFORWARD:
    m_player->move(0.25);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_STEPBACKWARD:
    m_player->move(-0.25);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_STEPLEFT:
    m_player->turn(5.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_STEPRIGHT:
    m_player->turn(-5.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_MOVEFORWARD:
    m_player->move(1.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_MOVEBACKWARD:
    m_player->move(-1.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_MOVELEFT:
    m_player->turn(10.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_MOVERIGHT:
    m_player->turn(-10.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_RUNFORWARD:
    m_player->move(10.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_RUNBACKWARD:
    m_player->move(-10.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_RUNLEFT:
    m_player->turn(20.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERMOVE_RUNRIGHT:
    m_player->turn(-20.0);
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_DEFAULT:
    m_viewpoint->lookDefault();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_UP:
    m_viewpoint->lookUp();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_DOWN:
    m_viewpoint->lookDown();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_RIGHT:
    m_viewpoint->lookRight();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_LEFT:
    m_viewpoint->lookLeft();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_FORWARD:
    m_viewpoint->lookForward();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case PLAYERLOOK_BACKWARD:
    m_viewpoint->lookBackward();
    m_viewpoint->update(m_player);
    getProtocol()->sendViewpoint( m_viewpoint );
    break;
  case USERCOMMAND_0:
//    CWorld * world = getWorld();
//    movePlayer(world->getCell("City central"));  
    break;
  case MSGCOMMAND_ONLINE:
    online();
    break;
  }
}

/*

void CClientManager::updatePosition( CGeometryObject * geometryObject ){
  getProtocol()->sendUpdatePosition( geometryObject );
}

void CClientManager::updateDirection( CGeometryObject * geometryObject ){
  getProtocol()->sendUpdateDirection( geometryObject );
}

void CClientManager::sendAddGeometryObject(CGeometryObject * geometryObject){
  getProtocol()->sendAddGeometryObject(geometryObject);
}
void CClientManager::sendRemoveGeometryObject(CGeometryObject * geometryObject){
  getProtocol()->sendRemoveGeometryObject(geometryObject);
}
*/

void CClientManager::selection(WORD objectId){
  CWorldWorld * world = getWorld();
  CWorldObject * object = world->getObject(objectId);
  if (m_player->objectReachable( object )){
    getProtocol()->sendObjectCommands( object ); 
  }
}

void CClientManager::action(WORD objectId,WORD actionId){
  CWorldWorld * world = getWorld();
  CWorldObject * object = world->getObject(objectId);
  if (m_player->objectReachable( object )){
    cdebug << "CWorldObject->action not implemented!!!\n";
//    object->action(actionId);
  }
}

void CClientManager::userCommand(char * messageString){
  cdebug << "MESSAGE FROM CLIENT: "  << messageString << "\n";
  m_commandParser->parseCommand(messageString);
}

void CClientManager::sendMsg(const char *message){
  getProtocol()->sendMsg(message);
}

void CClientManager::updateMasterCell(CSrvObject * newcell){

//  cdebug << "CClientManager::updateMasterCell: HACK Do not clear world and build world from scratch!!!!\n"
//       << "                                       Only need to update some cells.\n";
//  sendWorld(); 

  // Update client with new cells. 
  getProtocol()->sendPlayerInfo(newcell->getObjectId());

}