/***************************************************************************
 *   Copyright (C) 2005 by the G System Team                               *
 *   http://www.g-system.at                                                *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

#include "GClientFactory.h"

#include "GCommunicationWidget.h"

#include <GOpenGLFrame.h>
#include <GCamera.h>

#include <GDataController.h>
#include <GXmlDataController.h>

#include <GMoveAgent.h>
#include <GEnergyFormAgent.h>

#include <GVector3.h>
#include <GMatrix44.h>
#include <GElementID.h>
#include <GElement.h>
#include <GObject.h>
#include <GForm.h>
#include <GEnergy.h>

#include <qdom.h>
#include <qgl.h>
#include <qframe.h>
#include <qlayout.h>
#include <qgroupbox.h>
#include <qsplitter.h>
#include <qtimer.h>
#include <qtooltip.h>

#include <kmainwindow.h>
#include <klistbox.h>
#include <klineedit.h>
#include <ktextedit.h>

GClientFactory::GClientFactory(QObject* parent, const char* name)
: QObject(parent, name),
  WorldEngineController(NULL),
  MainFrame(NULL),
  Frame(NULL),
  Camera(NULL)
{
  connect(&CheckTimer,SIGNAL(timeout()),this,SLOT(checkWorldEngineReady()));
}


GClientFactory::~GClientFactory()
{
}

void GClientFactory::renderInitStatus()
{
  if (this->Frame)
  {
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glDisable(GL_LIGHTING);
//   Frame->qglColor(QColor(0,255,255)); //yellow
    glColor4f(0,1,1,1);
    Frame->renderText(Frame->width()/2-70, Frame->height()/2-5, "Connecting to the G Universe...");
    glEnable(GL_LIGHTING);
    glFlush();
  }
}

void GClientFactory::checkWorldEngineReady()
{
  if (GCS::GElementID::countFreeIDs() > 0)
  {
    CheckTimer.stop();
    //finalize initialization (create client "element") and start rendering

    qDebug("ID is now available, creating user element");

    qDebug("Getting free ID");
    GCS::GElementID user_id(GCS::GElementID::getFreeID());
    
    GCS::GForm* user_form = new GCS::GForm(GCS::GVector3(10,10,10));

    qDebug("Creating Element");
    GCS::GElement* client_element =
        new GCS::GElement(
          new GCS::GObject(new GCS::GEnergy(5,0.1,10),
                           user_form,
                           GCS::GElementID(1),  //galaxy as parent
                           GCS::GElementID(user_id),  //own ID
                           GCS::GElementID(1),   //connect to the parent (connectionID is the same as ID of the galaxy element)
                           new QDomDocument(),
                           this->WorldEngineController->getDataController()));

    Q_CHECK_PTR(client_element);

    qDebug("Creating agents and connecting user element to camera");

    GBE::GMoveAgent* move_agent = new GBE::GMoveAgent();
    QObject::connect(Camera,SIGNAL(translationSpeedImpulse(const GCS::GVector3& )),move_agent,SLOT(addTranslationSpeedImpulse(const GCS::GVector3& )));
    QObject::connect(Camera,SIGNAL(rotationSpeedImpulse(const GCS::GVector3& )),move_agent,SLOT(addRotationImpulse(const GCS::GVector3& )));
    QObject::connect(Camera,SIGNAL(stopMovement()),move_agent,SLOT(fullStop()));
    client_element->addAgent(move_agent);
    move_agent->initSlowDownFactor(0.5);
    move_agent->initUpdateInterval(50);

    GBE::GEnergyFormAgent* form_agent = new GBE::GEnergyFormAgent();
    client_element->addAgent(form_agent);

    this->Camera->setForm(user_form);
    this->Camera->setFrame(Frame);
    this->Camera->setViewDistance(2000);
    this->Camera->setSpeedFactor(2);
    this->Camera->startCamera();

    qDebug("Adding user element to world engine");

    this->WorldEngineController->getDataController()->add(client_element);

    client_element->executeElement();

    qDebug("Simulate a reparent event which produces a reparent message in the GWE");
    //this will generate a proper reparented signal which is handled by
    //the GWE which propagates a proper reparenting message to the parent - the universe element
//     client_element->reparent(GCS::GElementID(0),GCS::GElementID(1),GCS::GMatrix44::createIdentityMatrix());

    qDebug("Beginning rendering in user interface");
    Frame->ViewProperties.CameraElement = user_id;
    Frame->addTopElement(GCS::GElementID(1));
    //     Frame->startRendering(15);  //already done in init()
    disconnect(Frame,SIGNAL(afterRendering()),this,SLOT(renderInitStatus()));
    
    QTimer* listupdater = new QTimer(this->MainFrame,"serverlistupdater");
    
    connect(listupdater,SIGNAL(timeout()),this,SLOT(updateServerList()));
    
    listupdater->start(4013);
  }
}

/**
 * @todo This is a dirty mess, but it's experimental anyway
 *       As soon as a the interface looks the way it should,
 *       a separate client interface class should be created
 *       since most of the things here are not the job of a
 *       factory.
 */
void GClientFactory::init(GWE::GweController* controller)
{
  this->WorldEngineController = controller;
  
  GWE::GDataController* dc = controller->getDataController();
  
  this->MainFrame = new QFrame(NULL,"gclientwindow");  //KMainWindow is rather nasty, connects its own signals for quitting the application
  this->MainFrame->resize(790,580);  //fit to 800x600 (consider window decoration,...)
  
  QGridLayout* mainlayout = new QGridLayout(MainFrame,1,1,4,4,"mainlayout");
  
  QSplitter* framecommsplitter = new QSplitter(Qt::Vertical,MainFrame,"framecommsplitter");
  
  mainlayout->addWidget(framecommsplitter,0,0);
  
  //create the 3D client interface, this is were everything is displayed
  this->Frame = new GCE::GOpenGLFrame(controller,framecommsplitter,"openglframe");
  
  this->Frame->setFocusPolicy(QWidget::StrongFocus);
  this->Frame->setFocus();
  
  //communication widget
  CommWidget = new GCommunicationWidget(framecommsplitter,"comm frame");
  
//   layout->addWidget(framecommsplitter,1,0);
  
//   this->Frame->setCaption("G Universe Client");

  //frame initialization
  Frame->resizeGL(640,480);
  Frame->resize(640,480);
  Frame->initializeGL();
  
  Frame->ViewProperties.NearClippingPlane = 1;
  Frame->ViewProperties.FarClippingPlane = 10000;  //reduce this if you have slow rendering
  Frame->ViewProperties.ViewPosition.z = 0.5;
  Frame->ViewProperties.ViewTarget = GCS::GVector3(0,0,0);
  Frame->ViewProperties.update();

  MainFrame->show();
  
  if (dc->inherits("GWE::GXmlDataController"))
  {
    GWE::GXmlDataController* xdc = (GWE::GXmlDataController*)dc;
    qDebug("XML Data Controller found, connecting signals and slots for user messages");
    connect(xdc,SIGNAL(userMessageReceived(QString, QString, bool )),CommWidget,SLOT(receiveMessage(QString, QString, bool )));
    connect(CommWidget,SIGNAL(sendMessage(QString, QString )),xdc,SLOT(sendUserMessage(QString, QString )));
    connect(xdc,SIGNAL(serverPresenceChanged(QString, bool, bool )),CommWidget,SLOT(updateContactState(QString, bool, bool )));
  }
  else
  {
    CommWidget->hide();
    qWarning("No network capable data controller found, sending user messages is not possible!");
  }
  
  //create a camera, the camera will work on the view properties of the frame
  this->Camera = new GCE::GCamera(Frame);
  
  connect(Frame,SIGNAL(afterRendering()),this,SLOT(renderInitStatus()));
  Frame->startRendering();

  //periodically checks checkWorldEngineReady()
  CheckTimer.start(500);
}

/*

void GClientFactory::prepareMessageForSending()
{
  if (this->MessageText->text().isEmpty() || this->MessageDestination->text().isEmpty())
  {
    qWarning("Not sending message, message text and/or destination empty.");
    return;
  }
  
  QString dest = this->MessageDestination->text();
  QString msg = this->MessageText->text();
  
  qDebug("Sending User Message:");
  qDebug(QString(" destination: %1").arg(dest));
  qDebug(QString(" message: %1").arg(msg));
  
  if (dest=="*")
  {
    //broadcast message
    int n = this->ServerList->numRows();
    for (int i=0; i<n; i++)
    {
      QString destination = this->ServerList->text(i);
      if (!destination.isEmpty())
        emit this->sendMessage(msg,destination);
    }
    
    this->MessageHistory->append(QString("SENT TO ALL: ") + msg);
    this->MessageText->clear();
  }
  else
  {
    //ordinary mssage
    emit this->sendMessage(msg,dest);
    this->MessageHistory->append(QString("SENT TO ") + dest + ": " + msg);
    this->MessageText->clear();
  }
}

void GClientFactory::receiveMessage(QString message, QString sender, bool internal)
{
  QString m;
  if (!internal)
    m.append("EXTERNAL: ");
  m.append(sender);
  m.append(": ");
  m.append(message);
  this->MessageHistory->append(m);
}

*/

void GClientFactory::updateServerList()
{
  if (this->WorldEngineController!=NULL)
  {
    GWE::GDataController* dc = this->WorldEngineController->getDataController();
    if (dc->inherits("GWE::GXmlDataController"))
    {
      GWE::GXmlDataController* xdc = (GWE::GXmlDataController*)dc;
//       this->CommWidget->clearExternalContacts();
//       this->CommWidget->clearInternalContacts();
      this->CommWidget->replaceInternalContactList(xdc->getAllKnownServers());
//       this->ServerList->insertStringList(xdc->getAllKnownServers());
    }
  }
}


syntax highlighted by Code2HTML, v. 0.9.1