/*
**************************************************************************
                                 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 "pmdeclare.h"
#include "pmdeclareedit.h"
#include "pmoutputdevice.h"
#include "pmxmlhelper.h"
#include "pmmemento.h"

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

#include <klocale.h>

PMDeclare::PMDeclare( )
      : Base( )
{
   m_declareType = NoDeclare;
}

PMDeclare::~PMDeclare( )
{
}

bool PMDeclare::isA( PMObjectType t ) const
{
   if( t == PMTDeclare )
      return true;
   return Base::isA( t );
}

QString PMDeclare::description( ) const
{
   QString d = i18n( "declaration" );
   switch( m_declareType )
   {
      case NoDeclare:
         break;
      case ObjectDeclare:
         d = i18n( "object declaration" );
         break;
      case TextureDeclare:
         d = i18n( "texture declaration" );
         break;
      case PigmentDeclare:
         d = i18n( "pigment declaration" );
         break;
      case FinishDeclare:
         d = i18n( "finish declaration" );
         break;
      case NormalDeclare:
         d = i18n( "normal declaration" );
         break;
      case TextureMapDeclare:
         d = i18n( "texture map declaration" );
         break;
      case PigmentMapDeclare:
         d = i18n( "pigment map declaration" );
         break;
      case ColorMapDeclare:
         d = i18n( "color map declaration" );
         break;
      case NormalMapDeclare:
         d = i18n( "normal map declaration" );
         break;         
      case SlopeMapDeclare:
         d = i18n( "slope map declaration" );
         break;         
      case DensityMapDeclare:
         d = i18n( "density map declaration" );
         break;         
      case InteriorDeclare:
         d = i18n( "interior declaration" );
         break;         
      case MediaDeclare:
         d = i18n( "media declaration" );
         break;         
      case SkySphereDeclare:
         d = i18n( "sky sphere declaration" );
         break;
      case RainbowDeclare:
         d = i18n( "rainbow declaration" );
         break;
      case FogDeclare:
         d = i18n( "fog declaration" );
         break;
      case MaterialDeclare:
         d = i18n( "material declaration" );
         break;
      case DensityDeclare:
         d = i18n( "density declaration" );
         break;
   }
   return d;
}

QString PMDeclare::pixmap( ) const
{
   QString d = "pmdeclare";
   switch( m_declareType )
   {
      case NoDeclare:
         break;
      case ObjectDeclare:
         d = "pmobjectdeclare";
         break;
      case TextureDeclare:
         d = "pmtexturedeclare";
         break;
      case PigmentDeclare:
         d = "pmpigmentdeclare";
         break;
      case FinishDeclare:
         d = "pmfinishdeclare";
         break;
      case NormalDeclare:
         d = "pmnormaldeclare";
         break;
      case TextureMapDeclare:
         d = "pmtexturemapdeclare";
         break;
      case PigmentMapDeclare:
         d = "pmpigmentmapdeclare";
         break;
      case ColorMapDeclare:
         d = "pmcolormapdeclare";
         break;
      case NormalMapDeclare:
         d = "pmnormalmapdeclare";
         break;
      case SlopeMapDeclare:
         d = "pmslopemapdeclare";
         break;
      case DensityMapDeclare:
         d = "pmdensitymapdeclare";
         break;
      case InteriorDeclare:
         d = "pminteriordeclare";
         break;
      case MediaDeclare:
         d = "pmmediadeclare";
         break;
      case SkySphereDeclare:
         d = "pmskyspheredeclare";
         break;
      case RainbowDeclare:
         d = "pmrainbowdeclare";
         break;
      case FogDeclare:
         d = "pmfogdeclare";
         break;
      case MaterialDeclare:
         d = "pmmaterialdeclare";
         break;
      case DensityDeclare:
         d = "pmdensitydeclare";
         break;
   }
   return d;
}

bool PMDeclare::canInsert( PMObjectType ot, const PMObject*,
                           const PMObjectList* objectsBetween ) const
{
   PMDeclareType thisType = m_declareType;
   PMDeclareType t = declareTypeByObjectType( ot );

   if( thisType == NoDeclare )
      if( objectsBetween )
         if( objectsBetween->getFirst( ) )
            thisType = declareTypeByObjectType( objectsBetween->getFirst( )->type( ) );
   
   if( ( ( thisType == NoDeclare ) && ( t != NoDeclare ) )
       || ( !firstChild( ) && ( t != NoDeclare ) && ( t == thisType ) )
       || ( ( thisType == TextureDeclare ) && ( t == TextureDeclare ) ) )
      return true;
   return false;
}

int PMDeclare::canInsert( const PMObjectList& list, const PMObject* )
{
   PMDeclareType thisType = m_declareType;
   PMDeclareType t;
   int num = 0;
   bool children = firstChild( );
   bool stop = children && ( thisType != TextureDeclare );
   PMObjectListIterator it( list );

   for( ; it.current( ) && !stop; ++it )
   {
      t = declareTypeByObjectType( it.current( )->type( ) );
      if( ( thisType == NoDeclare ) && ( t != NoDeclare ) )
      {
         num++;
         thisType = t;
         children = true;
      }
      else if( ( thisType != NoDeclare ) && ( t == thisType ) && !children )
      {
         num++;
         children = true;
      }
      else if( ( thisType == TextureDeclare ) && ( thisType == t ) )
      {
         num++;
         children = true;
      }
         
      stop = children && ( thisType != TextureDeclare );
   }

   return num;
}

int PMDeclare::canInsert( const QValueList<PMObjectType>& list, const PMObject* )
{
   PMDeclareType thisType = m_declareType;
   PMDeclareType t;
   int num = 0;
   bool children = firstChild( );
   bool stop = children && ( thisType != TextureDeclare );
   QValueList<PMObjectType>::ConstIterator it;

   for( it = list.begin( ); ( it != list.end( ) ) && !stop; ++it )
   {
      t = declareTypeByObjectType( *it );
      if( ( thisType == NoDeclare ) && ( t != NoDeclare ) )
      {
         num++;
         thisType = t;
         children = true;
      }
      else if( ( thisType != NoDeclare ) && ( t == thisType ) && !children )
      {
         num++;
         children = true;
      }
      else if( ( thisType == TextureDeclare ) && ( thisType == t ) )
      {
         num++;
         children = true;
      }
         
      stop = children && ( thisType != TextureDeclare );
   }

   return num;
}

void PMDeclare::serialize( PMOutputDevice& dev ) const
{
   if( firstChild( ) )
   {
      dev.declareBegin( m_id );
      Base::serialize( dev );
   }
}

void PMDeclare::serialize( QDomElement& e, QDomDocument& doc ) const
{
   e.setAttribute( "id", m_id );
   Base::serialize( e, doc );
}

void PMDeclare::readAttributes( const PMXMLHelper& h )
{
   m_id = h.stringAttribute( "id", "object" );
   Base::readAttributes( h );
}

PMDialogEditBase* PMDeclare::editWidget( QWidget* parent ) const
{
   return new PMDeclareEdit( parent );
}

void PMDeclare::setID( const QString& newID )
{
   if( newID != m_id )
   {
      if( m_pMemento )
      {
         m_pMemento->addIDChange( PMTDeclare, PMIDID, m_id );
         m_pMemento->setDescriptionChanged( );
      }
         
      m_id = newID;
   }
}

void PMDeclare::setDeclareType( PMDeclareType t )
{
   if( m_declareType != t )
   {
      if( m_pMemento )
      {
         m_pMemento->addData( PMTDeclare, PMDeclareTypeID, m_declareType );
         m_pMemento->setDescriptionChanged( );
      }

      m_declareType = t;
   }
}

void PMDeclare::restoreMemento( PMMemento* s )
{
   PMMementoDataIterator it( s );
   PMMementoData* data;

   for( ; it.current( ); ++it )
   {
      data = it.current( );
      if( data->objectType( ) == PMTDeclare )
      {
         switch( data->valueID( ) )
         {
            case PMIDID:
               setID( data->stringData( ) );
               break;
            case PMDeclareTypeID:
               setDeclareType( ( PMDeclareType ) data->intData( ) );
               break;
            default:
               kdError( PMArea ) << "Wrong ID in PMDeclare::restoreMemento\n";
               break;
         }
      }
   }
   Base::restoreMemento( s );
}

void PMDeclare::addLinkedObject( PMObject* o )
{
   m_linkedObjects.append( o );
}

void PMDeclare::removeLinkedObject( PMObject* o )
{
   m_linkedObjects.removeRef( o );
}

void PMDeclare::childAdded( PMObject* o )
{
   if( m_declareType == NoDeclare )
      setDeclareType( declareTypeByObjectType( o->type( ) ) );

   Base::childAdded( o );
}

PMDeclare::PMDeclareType PMDeclare::declareTypeByObjectType( PMObjectType ot ) const
{
   PMDeclareType t = NoDeclare;
   switch( ot )
   {
      // finite solid
      case PMTBlob:
      case PMTBox:
      case PMTCone:
      case PMTCylinder:
      case PMTHeightField:
      case PMTJuliaFractal:
      case PMTLathe:
      case PMTPrism:
      case PMTSphere:
      case PMTSuperquadricEllipsoid:
      case PMTSurfaceOfRevolution:
      case PMTText:
      case PMTTorus:
      // finite patch
      case PMTBicubicPatch:
      case PMTDisc:
      case PMTMesh:
      case PMTPolygon:
      case PMTTriangle:
      // infinite solid
      case PMTPlane:
      case PMTPolynom:
      // csg   
      case PMTCSG:
      // misc
      case PMTLight:
      case PMTObjectLink:
         t = ObjectDeclare;
         break;
      case PMTTexture:
         t = TextureDeclare;
         break;
      case PMTPigment:
         t = PigmentDeclare;
         break;
      case PMTFinish:
         t = FinishDeclare;
         break;
      case PMTNormal:
         t = NormalDeclare;
         break;
      case PMTTextureMap:
         t = TextureMapDeclare;
         break;
      case PMTPigmentMap:
         t = PigmentMapDeclare;
         break;
      case PMTColorMap:
         t = ColorMapDeclare;
         break;
      case PMTNormalMap:
         t = NormalMapDeclare;
         break;
      case PMTSlopeMap:
         t = SlopeMapDeclare;
         break;
      case PMTDensityMap:
         t = DensityMapDeclare;
         break;
      case PMTInterior:
         t = InteriorDeclare;
         break;
      case PMTMedia:
         t = MediaDeclare;
         break;
      case PMTMaterial:
         t = MaterialDeclare;
         break;
      case PMTDensity:
         t = DensityDeclare;
         break;
      case PMTSkySphere:
         t = SkySphereDeclare;
         break;
      case PMTRainbow:
         t = RainbowDeclare;
         break;
      case PMTFog:
         t = FogDeclare;
         break;
      default:
         t = NoDeclare;
         break;
   }
   return t;
}
