/***************************************************************************
 *   Copyright (C) 2004 - 2005 by Raphael Langerhorst                      *
 *   raphael-langerhorst@gmx.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 "CreateUniverseButton.h"

#include <GElement.h>
#include <GObject.h>
#include <GElementInfluence.h>
#include <GForm.h>
#include <GEnergy.h>

#include <GweController.h>
#include <GweSimpleController.h>
#include <GDataController.h>

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

//#include <InvestigationInterface.h>
#include <GDynamicGeneratorAgent.h>
#include <GSolarsystemCategory.h>

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

#include <qapplication.h>
#include <qdom.h>

using namespace GCS;
using namespace GWE;
using namespace GBE;

using namespace GCE;

class PositionShowAgent : public GCS::GAgent
{
  virtual ~PositionShowAgent() {}
  void run()
  {
    while(!shutdown)
    {
//       qDebug(requestForm()->Ellipsoid.toString());
      qDebug(QString::number(requestEnergy()->amount()));

      msleep(100);
    }
  }
};


CreateUniverseButton::CreateUniverseButton(QSpinBox* spin_box_random_seed, QString text, QWidget *parent, const char *name)
 : QPushButton(text, parent, name),
   RandomSeed(spin_box_random_seed)
{
  connect(this,SIGNAL(pressed()),this,SLOT(createUniverse()));
}


CreateUniverseButton::~CreateUniverseButton()
{
}

QWidget* CreateUniverseButton::createUniverse()
{
  //create the G World Engine, it holds all element data and manages influences (routing between elements)    
  GweController* gwe = new GweSimpleController();
  
  GDataController* gwedata = gwe->getDataController();
  
  //create the 3D client interface, this is were everything is displayed
  GOpenGLFrame* frame = new GOpenGLFrame(gwe);
  
  //create a camera, the camera will work on the view properties of the frame
  GCamera* cam = new GCamera(frame);
    
  //to start with we want to create a galaxy:
  
  //a form with 100 000 units radius
  GForm* myForm = new GForm( GVector3(0,0,0), GVector3(0,0,0), GVector3(10000,10000,10000) );
  Q_CHECK_PTR(myForm);
  
  //set alpha component to 0 (the borders should not be visible)
  
  GElementID galaxy_id = GElementID::getFreeID();
  
  GObject* galaxy_object = new GObject(
                                new GEnergy(10,100000,3),
                                myForm,
                                GElementID(galaxy_id),  //the galaxy is it's own parent ;)
                                GElementID(galaxy_id),  //own ID is 1
                                GElementID(galaxy_id),   //connect to itself (connectionID is the same as own ID)
                                new QDomDocument(),
                                gwedata
                              );
  
  //now create the solar system element
  GElement* galaxy = new GElement(galaxy_object);

  //add a generator agent to the element, it will take care of galaxy generation handling
  //including generation of solar systems,...
  GDynamicGeneratorAgent* generator = new GDynamicGeneratorAgent();
  
  galaxy->addAgent(generator);
  
  generator->initRandomSeed(RandomSeed->value());
  generator->initCategory(new GSolarsystemCategory(0.3));
  generator->initCreationTime();
  generator->initDensity(4);
  generator->initAllAtOnce(false);
  
  
  //the galaxy should radiate some energy as well:
  GRadiatingAgent* radiator = NULL;
  radiator = new GRadiatingAgent();
  galaxy->addAgent(radiator);
  radiator->initFraction(0.0000002);
  radiator->initMinEnergy(100);
  radiator->initMaxEnergy(100000);
  radiator->initInterval(10000);
  
  GEnergyFormAgent* efa = NULL;
  efa = new GEnergyFormAgent();
  galaxy->addAgent(efa);
  efa->initAlpha(0);
  efa->initSizeFactorEnabled(false);
//   efa->initSizeFactor(GVector3(1000,1000,1000));
  
//   PositionShowAgent* psa = new PositionShowAgent();
//   galaxy->addAgent(psa);
  
  
  //galaxy should handle reparenting
  //   galaxy->addAgent(new GReparentAgent());  //now handled by GWE
                         
  //now we add the galaxy to the world engine, the world engine takes care
  //of influence routing, element storage, etc. (later also the network layer,...)
  //note that created children are automatically recognized by the GWE
  gwedata->add(galaxy);
  
  
  //now we will also create an investigation element so we can analyse what's going on in
  //the universe...

  //the big size results in larger areas being generated around the element
  myForm = new GForm(GVector3(0,0,-5),GVector3(0,0,0),GVector3(1000,1000,1000));
  Q_CHECK_PTR(myForm);
//   myForm->RGBA[0] = myForm->RGBA[1] = myForm->RGBA[2] = 1;
  
  cam->setForm(myForm);
  
  GElement* i_element = new GElement(
                           new GObject(      //create an object that holds most of the element data
                             new GEnergy(5,1,5),  //energy level, energy amount, sigma; big sigma is good ;-)
                             myForm,         //the form for the element, we created it above;
                             GElementID(galaxy_id),  //galaxy as parent
                             GElementID(GElementID::getFreeID()),  //own ID
                             GElementID(galaxy_id),   //connect to the parent (connectionID is the same as ID of the galaxy element)
                             new QDomDocument(),
                             gwedata
                           )
                         );
                           
  //add some more agents to the element
//   i_element->addAgent(new GInfluenceableAgent());
  
  //note that we currently use the camera to accelerate the speed of the form attribute.
  GMoveAgent* move_agent = new GMoveAgent();
  QObject::connect(cam,SIGNAL(translationSpeedImpulse(const GCS::GVector3& )),move_agent,SLOT(addTranslationSpeedImpulse(const GCS::GVector3& )));
  QObject::connect(cam,SIGNAL(rotationSpeedImpulse(const GCS::GVector3& )),move_agent,SLOT(addRotationImpulse(const GCS::GVector3& )));
  QObject::connect(cam,SIGNAL(stopMovement()),move_agent,SLOT(fullStop()));
  i_element->addAgent(move_agent);
  move_agent->initSlowDownFactor(0.5);
  move_agent->initUpdateInterval(50);
  
  radiator = new GRadiatingAgent();
  i_element->addAgent(radiator);
  radiator->initFraction(0.0002);
  radiator->initMinEnergy(0.001);
  radiator->initMaxEnergy(10);
  radiator->initInterval(1000);
  
  efa = new GEnergyFormAgent();
  i_element->addAgent(efa);
  efa->initAlpha(0);
  efa->initSizeFactorEnabled(false);
  
  //currently we do NOT reparent the investigation element
  //because of limitations in the camer to transform position
  //and rotation correctly - these are relative to the parent element.
  //please note that this can produces a corrupted parent/child hierarchy!
  //@todo improve client engine to be able to set camera on child elements
//   ii_element->addAgent(new GReparentAgent());
  
  //add the investigation element to the GWE
  gwedata->add(i_element);
  
    
  //set the frame as the main widget
  //@todo: we should create a sophisticated KDE interface for the next release
  
  
  //frame initialization
  frame->resizeGL(640,480);
  frame->resize(640,480);
  frame->initializeGL();
  
  frame->setFocusPolicy(QWidget::StrongFocus);
  frame->setFocus();
  
  frame->ViewProperties.NearClippingPlane = 1;
  frame->ViewProperties.FarClippingPlane = 10000;  //reduce this if you have slow rendering
  frame->ViewProperties.ViewPosition.z = 0.5;
  frame->ViewProperties.ViewTarget = GVector3(0,0,0);
  frame->ViewProperties.update();
  
  //tell the frame wich element it should render
  frame->addTopElement(galaxy->getElementID());

  cam->setViewDistance(1);
  cam->setSpeedFactor(100);
    
  //update the frame regularly:  
  frame->startRendering(1);
  //start camera handling:
  cam->startCamera();  

  // added elements are automatically executed
  //start element execution, this effectively starts the agent threads
  galaxy->executeElement();
  
  //run our investigation element
  i_element->executeElement();
  
  frame->show();
  
  return frame;
}


syntax highlighted by Code2HTML, v. 0.9.1