/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2000-2001 by Andreas Zehender
    email                : zehender@kde.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.                                   *
*                                                                        *
**************************************************************************/

#include "pmmemento.h"
#include <kdebug.h>
#include "pmglobals.h"


PMMementoData::PMMementoData( PMObjectType objType, int vID, const int data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMInt;
   m_pData = new int( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, const unsigned int data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMUnsigned;
   m_pData = new unsigned( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, const double data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMDouble;
   m_pData = new double( data );
}


PMMementoData::PMMementoData( PMObjectType objType, int vID, const bool data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMBool;
   m_pData = new bool( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, const PMThreeState data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMThreeState;
   m_pData = new PMThreeState( data );
}


PMMementoData::PMMementoData( PMObjectType objType, int vID, const QString& data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMString;
   m_pData = new QString( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, const PMVector& data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMVector;
   m_pData = new PMVector( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, const PMColor& data )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMColor;
   m_pData = new PMColor( data );
}

PMMementoData::PMMementoData( PMObjectType objType, int vID, PMObject* obj )
{
   m_objectType = objType;
   m_valueID = vID;

   m_dataType = PMMObjectPointer;
   m_pData = ( void* ) obj;
}

PMMementoData::~PMMementoData( )
{
   switch( m_dataType )
   {
      case PMMInt:
         delete( ( int* ) m_pData );
         break;
      case PMMUnsigned:
         delete( ( unsigned* ) m_pData );
         break;
      case PMMDouble:
         delete( ( double* ) m_pData );
         break;
      case PMMBool:
         delete( ( bool* ) m_pData );
         break;
      case PMMThreeState:
         delete( ( PMThreeState* ) m_pData );
         break;
      case PMMString:
         delete( ( QString* ) m_pData );
         break;
      case PMMVector:
         delete( ( PMVector* ) m_pData );
         break;
      case PMMColor:
         delete( ( PMColor* ) m_pData );
         break;
      case PMMObjectPointer:
         // delete nothing
         break;
   }
}

void PMMementoData::setInt( const int data )
{
   if( m_dataType == PMMInt )
      *( ( int* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setUnsigned( const unsigned int data )
{
   if( m_dataType == PMMUnsigned )
      *( ( unsigned int* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setDouble( const double data )
{
   if( m_dataType == PMMDouble )
      *( ( double* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setBool( const bool data )
{
   if( m_dataType == PMMBool )
      *( ( bool* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setThreeState( const PMThreeState data )
{
   if( m_dataType == PMMThreeState )
      *( ( PMThreeState* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setString( const QString& data )
{
   if( m_dataType == PMMString )
      *( ( QString* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setVector( const PMVector& data )
{
   if( m_dataType == PMMVector )
      *( ( PMVector* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setColor( const PMColor& data )
{
   if( m_dataType == PMMColor )
      *( ( PMColor* ) m_pData ) = data;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

void PMMementoData::setObject( PMObject* obj )
{
   if( m_dataType == PMMObjectPointer )
      m_pData = ( void* ) obj;
   else
      kdError( PMArea ) << "Wrong type in PMMementoData set function\n";
}

int PMMementoData::intData( ) const
{
   if( m_dataType == PMMInt )
      return *( ( int* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return 0;
}

double PMMementoData::doubleData( ) const
{
   if( m_dataType == PMMDouble )
      return *( ( double* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return 0;
}

bool PMMementoData::boolData( ) const
{
   if( m_dataType == PMMBool )
      return *( ( bool* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return false;
}

PMThreeState PMMementoData::threeStateData( ) const
{
   if( m_dataType == PMMThreeState )
      return *( ( PMThreeState* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return PMUnspecified;
}

QString PMMementoData::stringData( ) const
{
   if( m_dataType == PMMString )
      return *( ( QString* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return QString::null;
}

PMVector PMMementoData::vectorData( ) const
{
   if( m_dataType == PMMVector )
      return *( ( PMVector* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return PMVector( );
}

PMColor PMMementoData::colorData( ) const
{
   if( m_dataType == PMMColor )
      return *( ( PMColor* ) m_pData );
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return PMColor( );
}

PMObject* PMMementoData::objectData( ) const
{
   if( m_dataType == PMMObjectPointer )
      return ( PMObject* ) m_pData;
   kdError( PMArea ) << "Wrong type in PMMementoData get function\n";
   return 0;
}

PMMemento::PMMemento( PMObject* originator )
{
   m_data.setAutoDelete( true );
   m_changedObjects.setAutoDelete( true );
   m_pIDData = 0;
   m_pOriginatorChange = 0;
   m_pOriginator = originator;
}

PMMemento::~PMMemento( )
{
   m_data.clear( );
   m_changedObjects.clear( );
   // m_pOriginatorChange is in m_changedObjects and is already deleted!
}

PMMementoData* PMMemento::findData( PMObjectType objType, int vID ) const
{
   PMMementoDataIterator it( m_data );

   for( ; it.current( ); ++it )
   {
      if( ( it.current( )->objectType( ) == objType ) &&
          ( it.current( )->valueID( ) == vID ) )
         return it.current( );
   }
   return 0;
}

void PMMemento::addData( PMMementoData* data )
{
   m_data.append( data );
   addChange( PMCData );
}

void PMMemento::addData( PMObjectType objType, int vID, const int data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const unsigned int data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const double data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const bool data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const PMThreeState data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const QString& data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addIDChange( PMObjectType objType, int vID, const QString& data )
{
   if( !findData( objType, vID ) )
   {
      PMMementoData* d = new PMMementoData( objType, vID, data );
      addData( d );
      m_pIDData = d;
   }
}

void PMMemento::addData( PMObjectType objType, int vID, const PMVector& data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, const PMColor& data )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, data ) );
}

void PMMemento::addData( PMObjectType objType, int vID, PMObject* obj )
{
   if( !findData( objType, vID ) )
      addData( new PMMementoData( objType, vID, obj ) );
}

QString PMMemento::oldID( ) const
{
   if( m_pIDData )
      return m_pIDData->stringData( );
   return QString::null;
}

void PMMemento::addChangedObject( PMObject* obj, int mode )
{
   PMObjectChangeListIterator it( m_changedObjects );
   PMObjectChange* change = 0;

   while( it.current( ) && !change )
   {
      if( it.current( )->object( ) == obj )
         change = it.current( );
      else
         ++it;
   }
   
   if( change )
      change->addMode( mode );
   else
      m_changedObjects.append( new PMObjectChange( obj, mode ) );
}

void PMMemento::addChange( int mode )
{
   if( !m_pOriginatorChange )
   {
      m_pOriginatorChange = new PMObjectChange( m_pOriginator, PMCData );
      m_changedObjects.append( m_pOriginatorChange );
   }
   m_pOriginatorChange->addMode( mode );
}
