/***************************************************************************
 *   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 "GStorage.h"

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

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

#include <qsqldatabase.h>
#include <qsqlerror.h>
#include <qsqlquery.h>
#include <qsqlcursor.h>
#include <qsqlrecord.h>
#include <qstringlist.h>
#include <qdom.h>
#include <qptrlist.h>


namespace GWE
{

GStorage::GStorage(QObject *parent, const char *name)
 : QObject(parent, name),
   Database(NULL),
   DbDriver(""),
   DbName(""),
   DbHost(""),
   DbPort(0),
   DbUser(""),
   DbPassword("")
{
}


GStorage::~GStorage()
{
  this->disconnectDatabase();
}

void GStorage::setDatabaseDriver(QString driver)
{
  this->DbDriver=driver;
}

void GStorage::setDatabaseName(QString name)
{
  this->DbName=name;
}

void GStorage::setDatabaseHost(QString host)
{
  this->DbHost=host;
}

void GStorage::setDatabasePort(int port)
{
  this->DbPort=port;
}

void GStorage::setDatabaseUser(QString user)
{
  this->DbUser=user;
}

void GStorage::setDatabasePassword(QString password)
{
  this->DbPassword=password;
}

void GStorage::setDatabase(QString driver, QString name, QString user, QString password, QString host, int port )
{
  setDatabaseDriver(driver);
  setDatabaseName(name);
  setDatabaseHost(host);
  setDatabasePort(port);
  setDatabaseUser(user);
  setDatabasePassword(password);
}

bool GStorage::connectDatabase()
{
  if (this->Database)
  {
    if (this->Database->isOpen())
    {
      qWarning("Database is already open, please disconnect first if you want to reconnect!");
      return true;
    }
    else
    {
      qWarning("A Database was already set but closed, removing old database and proceeding with connecting...");
      QSqlDatabase::removeDatabase(this->Database);
    }
  }
  if (QSqlDatabase::isDriverAvailable(this->DbDriver))
  {
    this->Database = QSqlDatabase::addDatabase(this->DbDriver,"GWEStorage");
    if (this->Database)
    {
      if (!this->DbName.isEmpty())
        this->Database->setDatabaseName(this->DbName);
      if (!this->DbHost.isEmpty())
        this->Database->setHostName(this->DbHost);
      if (this->DbPort!=0)
        this->Database->setPort(this->DbPort);
      if (!this->DbUser.isEmpty())
        this->Database->setUserName(this->DbUser);
      if (!this->DbPassword.isEmpty())
        this->Database->setPassword(this->DbPassword);
      
      if (!this->Database->open())
      {
        qWarning("Failed to open database:");
        qWarning(this->Database->lastError().text());
        return false;
      }
      else
      {
        qDebug("Database connection opened.");
        return true;
      }
    }
    else
    {
      return false;
    }
  }
  else
  {
    return false;
  }
}

bool GStorage::isDatabaseConnected()
{
  if (this->Database)
  {
    if (this->Database->isOpen())
    {
      return true;
    }
  }
  return false;
}

bool GStorage::initializeDatabase()
{
  //HACK Currently we make sure all tables are empty after initialization, this should change when the protocol is improved
  if (this->isDatabaseConnected())
  {
    QStringList tables = this->Database->tables();
    
    qDebug(" Listing existing Database tables:");
    
    QStringList::iterator stringit;
    for (stringit = tables.begin(); stringit != tables.end(); ++stringit)
    {
      qDebug(QString("  %1").arg(*stringit));
    }

    QSqlQuery query(this->Database);

    //AGENT
    if (tables.contains("AGENT") || tables.contains("agent"))
    {
      query.prepare("DELETE FROM AGENT");
      if (!query.exec())
      {
        qWarning("Failed to empty AGENT table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE AGENT ( name varchar(50) primary key )");
      if (!query.exec())
      {
        qWarning("Failed to create AGENT table:");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //ELEMENTAGENTMAP
    if (tables.contains("ELEMENTAGENTMAP") || tables.contains("elementagentmap"))
    {
      query.prepare("DELETE FROM ELEMENTAGENTMAP");
      if (!query.exec())
      {
        qWarning("Failed to empty ELEMENTAGENTMAP table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE ELEMENTAGENTMAP ( element integer, agent varchar(50), PRIMARY KEY ( element, agent ) )");
      if (!query.exec())
      {
        qWarning("Failed to create ELEMENTAGENTMAP table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //ELEMENT
    if (tables.contains("ELEMENT") || tables.contains("element"))
    {
      query.prepare("DELETE FROM ELEMENT");
      if (!query.exec())
      {
        qWarning("Failed to empty ELEMENT table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE ELEMENT ( id integer primary key, connection integer NOT NULL, parent integer NOT NULL, server text NOT NULL )");
      if (!query.exec())
      {
        qWarning("Failed to create ELEMENT table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //ELEMENTDATA
    if (tables.contains("ELEMENTDATA") || tables.contains("elementdata"))
    {
      query.prepare("DELETE FROM ELEMENTDATA");
      if (!query.exec())
      {
        qWarning("Failed to empty ELEMENTDATA table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE ELEMENTDATA ( element integer primary key, data text )");
      if (!query.exec())
      {
        qWarning("Failed to create ELEMENTDATA table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //ENERGY
    if (tables.contains("ENERGY") || tables.contains("energy"))
    {
      query.prepare("DELETE FROM ENERGY");
      if (!query.exec())
      {
        qWarning("Failed to empty ENERGY table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE ENERGY ( element integer primary key, level float NOT NULL, amount float NOT NULL, sigma float NOT NULL )");
      if (!query.exec())
      {
        qWarning("Failed to create ENERGY table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //FORM
    if (tables.contains("FORM") || tables.contains("form"))
    {
      query.prepare("DELETE FROM FORM");
      if (!query.exec())
      {
        qWarning("Failed to empty FORM table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      query.prepare("CREATE TABLE FORM ( element integer primary key, positionx float NOT NULL, positiony float NOT NULL, positionz float NOT NULL, rotationx float NOT NULL, rotationy float NOT NULL, rotationz float NOT NULL, ellipsoidx float NOT NULL, ellipsoidy float NOT NULL, ellipsoidz float NOT NULL )");
      if (!query.exec())
      {
        qWarning("Failed to create FORM table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //GWESERVER
    if (tables.contains("GWESERVER") || tables.contains("gweserver"))
    {
      query.prepare("DELETE FROM GWESERVER");
      if (!query.exec())
      {
        qWarning("Failed to empty GWESERVER table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      //master is not yet used
      if (this->DbDriver == "QMYSQL3")
      {
        query.prepare("CREATE TABLE GWESERVER ( jid varchar(100) primary key, presence text NOT NULL, master text NULL )");
      }
      else
      {
        query.prepare("CREATE TABLE GWESERVER ( jid text primary key, presence text NOT NULL, master text NULL )");
      }
      if (!query.exec())
      {
        qWarning("Failed to create GWESERVER table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    //UPDATESUBSCRIPTION
    if (tables.contains("UPDATESUBSCRIPTION") || tables.contains("updatesubscription"))
    {
      query.prepare("DELETE FROM UPDATESUBSCRIPTION");
      if (!query.exec())
      {
        qWarning("Failed to empty UPDATESUBSCRIPTION table:");
        qWarning(query.lastError().text());
        return false;
      }
    }
    else
    {
      //@todo mysql can't handle boolean data type(?!), someone needs to investigate
//       query.prepare("CREATE TABLE UPDATESUBSCRIPTION ( element integer, server varchar(30), subelement boolean, subdata boolean, subenergy boolean, subform boolean, PRIMARY KEY (element, server) )");
      if (this->DbDriver == "QMYSQL3")
      {
        query.prepare("CREATE TABLE UPDATESUBSCRIPTION ( element integer, server varchar(100), subelement integer, subdata integer, subenergy integer, subform integer, PRIMARY KEY (element, server) )");
      }
      else
      {
        query.prepare("CREATE TABLE UPDATESUBSCRIPTION ( element integer, server text, subelement integer, subdata integer, subenergy integer, subform integer, PRIMARY KEY (element, server) )");
      }
      if (!query.exec())
      {
        qWarning("Failed to create UPDATESUBSCRIPTION table.");
        qWarning(query.lastError().text());
        return false;
      }
    }

    return true;
  }
  else
  {
    qWarning("Can't initialize database, not connected.");
    return false;
  }
}

bool GStorage::disconnectDatabase()
{
  if (this->Database)
  {
    if (this->Database->isOpen())
    {
      this->Database->close();
    }
    QSqlDatabase::removeDatabase(this->Database);
    this->Database=NULL;
  }
  return true;
}

QString GStorage::getLastDatabaseError()
{
  if (this->Database)
    return this->Database->lastError().text();
  else
    return "No database set.";
}

//BEGIN Data management

GCS::GVector3 GStorage::getVector3(unsigned long id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT x, y, z FROM VECTOR3 WHERE id = %1").arg(QString::number(id)),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        GCS::GVector3 v = GCS::GVector3(query.value(0).toDouble(),query.value(1).toDouble(),query.value(2).toDouble());
        return v;
//         qDebug( query.value(0).toString() + ": " +
//             query.value(1).toString() );
      }
      else
      {
        throw GStorageException(QString("No vector with ID %1 found.").arg(QString::number(id)));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

//BEGIN GWE stuff

QStringList GStorage::getAllServers() throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query("SELECT jid FROM GWESERVER",this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

bool GStorage::getServerExists(const QString& server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT jid FROM GWESERVER WHERE jid='%1'").arg(server),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return true;
      }
      else
      {
        return false;
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getServersForElementChildren(const GCS::GElementID& parent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM ELEMENT WHERE parent = %1").arg(QString::number(parent.getID())),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElementID> GStorage::getElementsForServer(const QString& server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT id FROM ELEMENT WHERE server = '%1'").arg(server),this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      while ( query.next() )
      {
        result.append(GCS::GElementID(query.value(0).toULongLong()));
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QString GStorage::getManagingServerForElement(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM ELEMENT WHERE id = %1").arg(QString::number(id.getID())),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return query.value(0).toString();
      }
      else
      {
        throw GStorageException(QString("Element with ID %1 not found.").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QString GStorage::getServerPresence(const QString& server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT presence FROM GWESERVER WHERE jid = '%1'").arg(server),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return query.value(0).toString();
      }
      else
      {
        throw GStorageException(QString("GWE Server %1 not found.").arg(server));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getServersSubscribedToElementUpdates(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM UPDATESUBSCRIPTION WHERE subelement = '1' AND element = '%1'").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getServersSubscribedToDataUpdates(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM UPDATESUBSCRIPTION WHERE subdata = '1' AND element = '%1'").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getServersSubscribedToEnergyUpdates(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM UPDATESUBSCRIPTION WHERE subenergy = '1' AND element = '%1'").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getServersSubscribedToFormUpdates(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT server FROM UPDATESUBSCRIPTION WHERE subform = '1' AND element = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

// modifications:

void GStorage::addServer(const QString& server, const QString& presence) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("INSERT INTO GWESERVER (jid, presence) VALUES ('%1', '%2')").arg(server).arg(presence),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::updateServerPresence(const QString& server, const QString& presence) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("UPDATE GWESERVER SET presence = '%1' WHERE jid = '%2'").arg(presence).arg(server),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::removeServer(const QString& server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("DELETE FROM GWESERVER WHERE jid = '%1'").arg(server),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::setSubscription(const GCS::GElementID& element, const QString& server, const QString& type) throw(GStorageException)
{
  //@todo implement
  throw GStorageException("Setting subscriptions not implemented");
//   if (this->isDatabaseConnected())
//   {
//     QString column;
//     QSqlQuery query(QString("SELECT element, server FOR UPDATE ").arg(new_server).arg(element.toString()),this->Database);
//     if (!query.isActive())
//     {
//       throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
//     }
//   }
//   else
//   {
//     throw GStorageException("DB not connected!");
//   }
}

void GStorage::clearSubscription(const GCS::GElementID& element, const QString& server, const QString& type) throw(GStorageException)
{
  //@todo implement
  throw GStorageException("Clearing subscriptions not implemented");
}

void GStorage::updateManagingServer(const GCS::GElementID& element, const QString& new_server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("UPDATE ELEMENT SET server = '%1' WHERE id = %2").arg(new_server).arg(element.toString()),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}


//END GWE stuff

//BEGIN Element stuff

// NOTE the agent list has only one column, it might be extended in the future

// get

bool GStorage::getElementExists(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT id FROM ELEMENT WHERE id = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      if ( query.next() )
      {
        return true;
      }
      else
        return false;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElementID> GStorage::getAllElementIDs() throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query("SELECT id FROM ELEMENT",this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      while ( query.next() )
      {
        result.append(GCS::GElementID(query.value(0).toULongLong()));
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElementID> GStorage::getAllElementIDsByServer(const QString& managing_server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT id FROM ELEMENT WHERE server = '%1'").arg(managing_server),this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      while ( query.next() )
      {
        result.append(GCS::GElementID(query.value(0).toULongLong()));
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

GCS::GElement* GStorage::getElement(const GCS::GElementID& id, const GCS::GWorldData* worlddata) throw(GStorageException)
{
  //@todo improve performance
  if (this->isDatabaseConnected())
  {
    //collect all things:
    
    //@todo, is this correct? And if so, how can we handle optional forms? (not every element has a form)
//     QSqlQuery query(QString("SELECT el.parent, el.connection, \
//                              ed.data, \
//                              en.level, en.sigma, en.amount, \
//                              fo.position, fo.rotation, fo.ellipsoid \
//                              FROM ELEMENT el, ELEMENTDATA ed, ENERGY en, FORM fo \
//                              WHERE el.id = %1 \
//                              AND ed.element = %1 \
//                              AND fo.id = %1").arg(id.toString()));
//     //fetch agents and form vectors...
//     //if above works, it replaces the rest of getElement()
    
    
    //parent + connection:
    unsigned long parent, connection;
    QSqlQuery query(QString("SELECT parent, connection FROM ELEMENT WHERE id = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        parent = query.value(0).toULongLong();
        connection = query.value(1).toULongLong();
      }
      else
      {
        throw GStorageException(QString("Could not find element %1 !").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    QValueList<GCS::GElementID> children = this->getChildren(id);
    
    GCS::GEnergy* energy = NULL;
    GCS::GForm* form = NULL;
    QDomDocument* elementdata = NULL;
    QStringList agents;
    try
    {
      //energy
      energy = this->getElementEnergy(id);
    }
    catch (GStorageException e)
    {
      if (energy)
      {
        delete energy;
        energy=NULL;
      }
      qWarning(QString("Energy of element %1 not found.").arg(id.toString()));
    }
    
    try
    {
      //form
      form = this->getElementForm(id);
    }
    catch (GStorageException e)
    {
      if (form)
      {
        delete form;
        form=NULL;
      }
      qWarning(QString("Form of element %1 not found.").arg(id.toString()));
    }
    
    try
    {
      //data
      elementdata = this->getElementData(id);
    }
    catch (GStorageException e)
    {
      if (elementdata)
      {
        delete elementdata;
        elementdata=NULL;
      }
      qWarning(QString("Data of element %1 not found, creating new data.").arg(id.toString()));
      elementdata = new QDomDocument();
    }
    
    try
    {
      //agents
      agents = this->getElementAgents(id);
    }
    catch (GStorageException e)
    {
      qWarning(QString("Couldn't get agents for element %1.").arg(id.toString()));
    }
    
    //put things together:
    
    GCS::GObject* obj = new GCS::GObject(energy,form,GCS::GElementID(parent),id,GCS::GElementID(connection),elementdata,worlddata);
    
    GCS::GElement* element = new GCS::GElement(obj);
    QStringList::iterator it;
    for (it = agents.begin(); it != agents.end(); ++it)
    {
      QString name = *it;
      GCS::GAgent* agent = NULL;
      //@todo IMPORTANT add plugin infrastructure
      if (name == "GBE::GAttractAgent")
      {
        agent = new GBE::GAttractAgent();
      }
      else if (name == "GBE::GDynamicGeneratorAgent")
      {
        agent = new GBE::GDynamicGeneratorAgent();
      }
      else if (name == "GBE::GEnergyFormAgent")
      {
        agent = new GBE::GEnergyFormAgent();
      }
      else if (name == "GBE::GMoveAgent")
      {
        agent = new GBE::GMoveAgent();
      }
      else if (name == "GBE::GRadiatingAgent")
      {
        agent = new GBE::GRadiatingAgent();
      }
      else
      {
        qWarning(QString("Couldn't determine appropriate agent for given agent name: %1").arg(name));
        agent = NULL;
      }
      element->addAgent(agent);
    }
    
    return element;
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElement*> GStorage::getElements(QValueList<GCS::GElementID> id_list, const GCS::GWorldData* worlddata) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  { 
    //@todo improve performance
    QValueList<GCS::GElement*> list;
    QValueList<GCS::GElementID>::iterator it;
    for (it = id_list.begin(); it != id_list.end(); ++it)
    {
      try
      {
        list.append(this->getElement(*it,worlddata));
      }
      catch (GStorageException e)
      {
        qWarning(QString("Element %1 not found!").arg((*it).toString()));
      }
    }
    return list;
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QDomDocument* GStorage::getElementData(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    //@todo make this work with MySQL
    if (this->Database->driverName() == "QMYSQL3")
      return new QDomDocument();
    QSqlQuery query(QString("SELECT data FROM ELEMENTDATA WHERE element = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      if ( query.next() )
      {
        QDomDocument* d = new QDomDocument();
        QString error;
        int line,column;
        if (d->setContent(query.value(0).toString(),&error,&line,&column))
        {
          return d;
        }
        else
        {
          throw GStorageException(QString("Converting element data to XML failed! %1:%2: %3").arg(QString::number(line)).arg(QString::number(column)).arg(error));
        }
      }
      else
      {
        throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

GCS::GEnergy* GStorage::getElementEnergy(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT level, sigma, amount FROM ENERGY WHERE element = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return new GCS::GEnergy(query.value(0).toDouble(),query.value(1).toDouble(),query.value(2).toDouble());
      }
      else
      {
        throw GStorageException(QString("Energy for element %1 not found.").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

GCS::GForm* GStorage::getElementForm(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT positionx, positiony, positionz, rotationx, rotationy, rotationz, ellipsoidx, ellipsoidy, ellipsoidz FROM FORM WHERE element = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        GCS::GVector3 position(query.value(0).toDouble(),query.value(1).toDouble(),query.value(2).toDouble());
        GCS::GVector3 rotation(query.value(3).toDouble(),query.value(4).toDouble(),query.value(5).toDouble());
        GCS::GVector3 ellipsoid(query.value(6).toDouble(),query.value(7).toDouble(),query.value(8).toDouble());
        
        return new GCS::GForm(position,rotation,ellipsoid);
        
        /*
        QString pos_id = query.value(0).toString();
        QString rot_id = query.value(1).toString();
        QString ell_id = query.value(2).toString();
        GCS::GVector3 pos,rot,ell;
        bool pos_found = false;
        bool rot_found = false;
        bool ell_found = false;
        query.prepare(QString("SELECT id, x, y, z FROM VECTOR3 WHERE id = %1 OR id = %2 OR id = %3").arg(pos_id).arg(rot_id).arg(ell_id));
        if (!query.exec())
        {
          throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
        }
        while (query.next())
        {
          if (query.value(0).toString() == pos_id)
          {
            pos.set(query.value(1).toDouble(),query.value(2).toDouble(),query.value(3).toDouble());
            pos_found = true;
          }
          else if (query.value(0).toString() == rot_id)
          {
            rot.set(query.value(1).toDouble(),query.value(2).toDouble(),query.value(3).toDouble());
            rot_found = true;
          }
          else if (query.value(0).toString() == ell_id)
          {
            ell.set(query.value(1).toDouble(),query.value(2).toDouble(),query.value(3).toDouble());
            ell_found = true;
          }
        }
        if (pos_found && rot_found && ell_found)
        {
          return new GCS::GForm(pos,rot,ell);
        }
        else
        {
          throw GStorageException(QString("Could not find all vectors for form of element %1, pos: %2, rot: %3, ellipsoid: %4").arg(id.toString()).arg(pos_found ? "yes" : "no").arg(rot_found ? "yes" : "no").arg(ell_found ? "yes" : "no"));
        }
        */
      }
      else
      {
        throw GStorageException(QString("Form for element %1 not found.").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElementID> GStorage::getChildren(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT id FROM ELEMENT WHERE parent = %1 AND id != %2").arg(id.toString()).arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QValueList<GCS::GElementID> result;
      while ( query.next() )
      {
        result.append(GCS::GElementID(query.value(0).toULongLong()));
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

GCS::GElementID GStorage::getParent(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT parent FROM ELEMENT WHERE id = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return GCS::GElementID(query.value(0).toULongLong());
      }
      else
      {
        throw GStorageException(QString("Element %1 not found.").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::getElementAgents(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT agent FROM ELEMENTAGENTMAP WHERE element = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

GCS::GElementID GStorage::getConnection(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT connection FROM ELEMENT WHERE id = %1").arg(id.toString()),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return GCS::GElementID(query.value(0).toULongLong());
      }
      else
      {
        throw GStorageException(QString("Element %1 not found.").arg(id.toString()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}


QStringList GStorage::getAllAgents() throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT name FROM AGENT"),this->Database);
    if (query.isActive())
    {
      QStringList result;
      while ( query.next() )
      {
        result.append(query.value(0).toString());
      }
      return result;
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QString GStorage::getAgent(const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("SELECT name FROM AGENT WHERE name = %1").arg(agent),this->Database);
    if (query.isActive())
    {
      if ( query.next() )
      {
        return query.value(0).toString();
      }
      else
      {
        throw GStorageException(QString("Agent %1 not found.").arg(agent));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

// modifications

void GStorage::addElement(const GCS::GElement* element, const QString& managing_server) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    this->Database->transaction();
    
    const GCS::GObject* object = element->getObject();
    const GCS::GElementID id = object->getID();
    QString id_string = id.toString();
    
    //element
    QSqlQuery query(QString("INSERT INTO ELEMENT ( id, connection, parent, server ) VALUES ( %1, %2, %3, '%4' )").arg(id_string).arg(object->getConnection().toString()).arg(object->getParent().toString()).arg(managing_server),this->Database);
    if (!query.isActive())
    {
      qWarning("INSERT INTO ELEMENT failed!");
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    //agents
    QValueList<const GCS::GAgent*> agents = element->getAgents();
    QValueList<const GCS::GAgent*>::iterator it;
    for (it = agents.begin(); it != agents.end(); ++it)
    {
      this->addElementAgent(id, (*it)->className());
    }
    
    //form
    if (object->hasForm())
    {
      const GCS::GForm* form = object->getForm();
      QString statement("INSERT INTO FORM ( element, positionx, positiony, positionz, rotationx, rotationy, rotationz, ellipsoidx, ellipsoidy, ellipsoidz ) VALUES ( ");
      
      statement.append(QString("%1, ").arg(id_string));
      
      statement.append(QString("%1, ").arg(form->Position.x));
      statement.append(QString("%1, ").arg(form->Position.y));
      statement.append(QString("%1, ").arg(form->Position.z));
      
      statement.append(QString("%1, ").arg(form->Rotation.x));
      statement.append(QString("%1, ").arg(form->Rotation.y));
      statement.append(QString("%1, ").arg(form->Rotation.z));
      
      statement.append(QString("%1, ").arg(form->Ellipsoid.x));
      statement.append(QString("%1, ").arg(form->Ellipsoid.y));
      statement.append(QString("%1 )").arg(form->Ellipsoid.z));
      
      query.prepare(statement);
      if (!query.exec())
      {
        qWarning("INSERT INTO FORM failed!");
        this->Database->rollback();
        throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
      }
    }
    
    //energy
    if (object->hasEnergy())
    {
      const GCS::GEnergy* energy = object->getEnergy();
      query.prepare(QString("INSERT INTO ENERGY ( element, level, amount, sigma ) VALUES ( %1, %2, %3, %4 )").arg(id_string).arg(energy->level()).arg(energy->amount()).arg(energy->sigma()));
      if (!query.exec())
      {
        qWarning("INSERT INTO ENERGY failed!");
        this->Database->rollback();
        throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
      }
    }
    
    //data
    //@todo make this work with MySQL
    if (object->hasElementData() && this->Database->driverName()!="QMYSQL3")
    {
      const QDomDocument* data = object->getElementData();
      QSqlCursor cursor("ELEMENTDATA",TRUE,this->Database);
      QSqlRecord *buffer = cursor.primeInsert();
      buffer->setValue("element",id_string);
      buffer->setValue("data",data->toString());
      
      //the following does not work since an XML string usually contains single quotes!!!
//       query.prepare(QString("INSERT INTO ELEMENTDATA ( element, data ) VALUES ( %1, '%2' )").arg(id_string).arg(data->toString()));
      if (cursor.insert() < 1)
      {
        qWarning("INSERT INTO ELEMENTDATA failed!");
        this->Database->rollback();
        throw GStorageException(QString("Query failed! %1").arg(cursor.lastError().text()));
      }
    }
    
    this->Database->commit();

    qDebug(QString("Element %1 added to database.").arg(id.toString()));
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::updateElement(const GCS::GElement* element) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    this->Database->transaction();
    
    const GCS::GObject* object = element->getObject();
    const GCS::GElementID id = object->getID();
    QString id_string = id.toString();
    
    //element
    QSqlQuery query(QString("UPDATE ELEMENT SET connection = %1, parent = %2 WHERE id = %3 ").arg(object->getConnection().toString()).arg(object->getParent().toString()).arg(id_string),this->Database);
    if (!query.isActive())
    {
      qWarning("UPDATE ELEMENT failed!");
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }

//     qDebug("updating agents...");
    
    //agents
    this->removeAllElementAgents(id);
    QValueList<const GCS::GAgent*> agents = element->getAgents();
    QValueList<const GCS::GAgent*>::iterator it;
    for (it = agents.begin(); it != agents.end(); ++it)
    {
      try
      {
        this->addElementAgent(id, (*it)->className());
      }
      catch (GStorageException e)
      {
        this->Database->rollback();
        throw e;
      }
    }

//     qDebug("updating form...");
    
    //form
    if (object->hasForm())
    {
      try
      {
        this->updateForm(id,object->getForm());
      }
      catch (GStorageException e)
      {
        this->Database->rollback();
        throw e;
      }
    }

//     qDebug("updating energy...");
    
    //energy
    if (object->hasEnergy())
    {
      try
      {
        this->updateEnergy(id,object->getEnergy());
      }
      catch (GStorageException e)
      {
        this->Database->rollback();
        throw e;
      }
    }

//     qDebug("updating element data...");
    
    //data
    if (object->hasElementData())
    {
      try
      {
        this->updateData(id,object->getElementData());
      }
      catch (GStorageException e)
      {
        this->Database->rollback();
        throw e;
      }
    }
    
    this->Database->commit();
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::removeElement(const GCS::GElementID& id) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    this->Database->transaction();
    
    //agents
    QSqlQuery query(QString("DELETE FROM ELEMENTAGENTMAP WHERE element = %1").arg(id.toString()),this->Database);
    if (!query.isActive())
    {
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    //form
    query.prepare(QString("DELETE FROM FORM WHERE element = %1").arg(id.toString()));
    if (!query.exec())
    {
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    //element
    query.prepare(QString("DELETE FROM ELEMENT WHERE id = %1").arg(id.toString()));
    if (!query.exec())
    {
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    //energy
    query.prepare(QString("DELETE FROM ENERGY WHERE element = %1").arg(id.toString()));
    if (!query.exec())
    {
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    //data
    query.prepare(QString("DELETE FROM ELEMENTDATA WHERE element = %1").arg(id.toString()));
    if (!query.exec())
    {
      this->Database->rollback();
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    this->Database->commit();
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::removeElements(QValueList<GCS::GElementID> id_list) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QValueList<GCS::GElementID>::iterator it;
    for (it = id_list.begin(); it != id_list.end(); ++it)
    {
      this->removeElement(*it);
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::reparentElement(const GCS::GElementID& element, const GCS::GElementID& old_parent, const GCS::GElementID& new_parent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("UPDATE ELEMENT SET parent = %1 WHERE id = %2").arg(new_parent.toString()).arg(element.toString()),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::changeConnection(const GCS::GElementID& element, const GCS::GElementID& connection) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("UPDATE ELEMENT SET connection = %1 WHERE id = %2").arg(connection.toString()).arg(element.toString()),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::addElementAgent(const GCS::GElementID& element, const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("INSERT INTO ELEMENTAGENTMAP (element, agent) VALUES (%1, '%2')").arg(element.toString()).arg(agent),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::removeElementAgent(const GCS::GElementID& element, const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("DELETE FROM ELEMENTAGENTMAP WHERE element = %1 AND agent = '%2'").arg(element.toString()).arg(agent),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QStringList GStorage::removeAllElementAgents(const GCS::GElementID& element) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QStringList agents = this->getElementAgents(element);
    QSqlQuery query(QString("DELETE FROM ELEMENTAGENTMAP WHERE element = %1").arg(element.toString()),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    return agents;
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

QValueList<GCS::GElementID> GStorage::removeAgentFromAllElements(const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QValueList<GCS::GElementID> elements;
    QSqlQuery query(QString("SELECT element FROM ELEMENTAGENTMAP WHERE agent = '%1'").arg(agent),this->Database);
    if (query.isActive())
    {
      while (query.next())
      {
        elements.append(GCS::GElementID(query.value(0).toULongLong()));
      }
    }
    else
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    
    query.prepare(QString("DELETE FROM ELEMENTAGENTMAP WHERE agent = '%1'").arg(agent));
    if (!query.exec())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
    return elements;
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::updateData(const GCS::GElementID& element, const QDomDocument* data) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    //@todo make this work with MySQL
    if (this->Database->driverName() == "QMYSQL3")
      return;
    QSqlCursor cursor("ELEMENTDATA",TRUE,this->Database);
    cursor.select(QString("element=%1").arg(element.toString()));
    if (cursor.next())
    {
      QSqlRecord* buffer = cursor.primeUpdate();
      buffer->setValue("data",data->toString());
      if (cursor.update() < 1)
      {
        qWarning(QString("UDATE ELEMENTDATA for element %1 failed! Updating the record failed.").arg(element.toString()));
        throw GStorageException(QString("Query failed! %1").arg(cursor.lastError().text()));
      }
    }
    else
    {
      qWarning(QString("UDATE ELEMENTDATA for element %1 failed! Record not found. Inserting new Record.").arg(element.toString()));
      QSqlRecord *buffer = cursor.primeInsert();
      buffer->setValue("element",element.toString());
      buffer->setValue("data",data->toString());
      if (cursor.insert() < 1)
      {
        qWarning("INSERT INTO ELEMENTDATA failed!");
        throw GStorageException(QString("Query failed! %1").arg(cursor.lastError().text()));
      }
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::updateEnergy(const GCS::GElementID& element, const GCS::GEnergy* energy) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("UPDATE ENERGY SET level = %1, amount = %2, sigma = %3 WHERE element = %4").arg(QString::number(energy->level())).arg(QString::number(energy->amount())).arg(QString::number(energy->sigma())).arg(element.toString()),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::updateForm(const GCS::GElementID& element, const GCS::GForm* form) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QString statement("UPDATE FORM SET ");
    
    statement.append(QString("positionx = %1, ").arg(form->Position.x));
    statement.append(QString("positiony = %1, ").arg(form->Position.y));
    statement.append(QString("positionz = %1, ").arg(form->Position.z));
        
    statement.append(QString("rotationx = %1, ").arg(form->Rotation.x));
    statement.append(QString("rotationy = %1, ").arg(form->Rotation.y));
    statement.append(QString("rotationz = %1, ").arg(form->Rotation.z));
        
    statement.append(QString("ellipsoidx = %1, ").arg(form->Ellipsoid.x));
    statement.append(QString("ellipsoidy = %1, ").arg(form->Ellipsoid.y));
    statement.append(QString("ellipsoidz = %1 ").arg(form->Ellipsoid.z));

    statement.append(QString("WHERE element = %1").arg(element.toString()));

    
    QSqlQuery query(statement,this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}


void GStorage::removeAllAgents() throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query("DELETE FROM AGENT",this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::addAgent(const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("INSERT INTO AGENT ( name ) VALUES ( '%1' )").arg(agent),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

void GStorage::removeAgent(const QString& agent) throw(GStorageException)
{
  if (this->isDatabaseConnected())
  {
    QSqlQuery query(QString("DELETE FROM AGENT WHERE name = '%1'").arg(agent),this->Database);
    if (!query.isActive())
    {
      throw GStorageException(QString("Query failed! %1").arg(query.lastError().text()));
    }
  }
  else
  {
    throw GStorageException("DB not connected!");
  }
}

//END Element stuff

//END Data management

}


syntax highlighted by Code2HTML, v. 0.9.1