/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2001 by Luis Carvalho
    email                : lpassos@mail.telepac.pt
**************************************************************************

**************************************************************************
*                                                                        *
*  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 "pmpatternedit.h"
#include "pmpattern.h"

#include "pmoutputdevice.h"
#include "pmxmlhelper.h"
#include "pmlistpatternedit.h"
#include "pmcompositeobject.h"
#include "pmmemento.h"

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

#include <klocale.h>

const PMPattern::PMPatternType patternTypeDefault = PMPattern::PatternAgate;
const double agateTurbulenceDefault = 0.5;
const int densityInterpolateDefault = 0;
const PMVector gradientDefault = PMVector( 1.0, 1.0, 1.0 );
const int maxIterationsDefault = 10;
const double quiltControl0Default = 1.0;
const double quiltControl1Default = 1.0;
const int spiralNumberArmsDefault = 0;
const QString densityFileDefault = QString( "" );
const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
const int octavesDefault = 6;
const double omegaDefault = 0.5;
const double lambdaDefault = 2.0;
const double depthDefault = 0.0;


PMPattern::PMPattern( )
      : Base( )
{
   m_patternType = patternTypeDefault;
   m_agateTurbulence = agateTurbulenceDefault;
   m_densityInterpolate = densityInterpolateDefault;
   m_gradient = gradientDefault;
   m_maxIterations = maxIterationsDefault;
   m_quiltControl0 = quiltControl0Default;
   m_quiltControl1 = quiltControl1Default;
   m_spiralNumberArms = spiralNumberArmsDefault;
   m_enableTurbulence = false;
   m_valueVector = valueVectorDefault;
   m_octaves = octavesDefault;
   m_omega = omegaDefault;
   m_lambda = lambdaDefault;
   m_depth = depthDefault;
}

PMPattern::~PMPattern( )
{
}

void PMPattern::serialize( PMOutputDevice& dev ) const
{
   QString str;

   // pattern type
   switch( m_patternType )
   {
      case PatternAgate:
         dev.writeLine( "agate" );
         break;
      case PatternAverage:
         dev.writeLine( "average" );
         break;
      case PatternBoxed:
         dev.writeLine( "boxed" );
         break;
      case PatternBozo:
         dev.writeLine( "bozo" );
         break;
      case PatternBumps:
         dev.writeLine( "bumps" );
         break;
      case PatternCrackle:
         dev.writeLine( "crackle" );
         break;
      case PatternCylindrical:
         dev.writeLine( "cylindrical" );
         break;
      case PatternDensity:
         dev.writeLine( "density_file df3 \"" + m_densityFile + "\"");  
         break;
      case PatternDents:
         dev.writeLine( "dents" );
         break;
      case PatternGradient:
         dev.writeLine( "gradient " + m_gradient.serialize( ) );
         break;
      case PatternGranite:
         dev.writeLine( "granite" );
         break;
      case PatternLeopard:
         dev.writeLine( "leopard" );
         break;
      case PatternMandel:
         str.setNum( m_maxIterations );
         dev.writeLine( "mandel " + str );
         break;
      case PatternMarble:
         dev.writeLine( "marble" );
         break;
      case PatternOnion:
         dev.writeLine( "onion" );
         break;
      case PatternPlanar:
         dev.writeLine( "planar" );
         break;
      case PatternQuilted:
         dev.writeLine( "quilted" );
         break;
      case PatternRadial:
         dev.writeLine( "radial" );
         break;
      case PatternRipples:
         dev.writeLine( "ripples" );
         break;
      case PatternSpherical:
         dev.writeLine( "spherical" );
         break;
      case PatternSpiral1:
         str.setNum( m_spiralNumberArms );
         dev.writeLine( "spiral1 " + str );
         break;
      case PatternSpiral2:
         str.setNum( m_spiralNumberArms );
         dev.writeLine( "spiral2 " + str );
         break;
      case PatternSpotted:
         dev.writeLine( "spotted" );
         break;
      case PatternWaves:
         dev.writeLine( "waves" );
         break;
      case PatternWood:
         dev.writeLine( "wood" );
         break;
      case PatternWrinkles:
         dev.writeLine( "wrinkles" );
         break;
   }
   // depth
   if( parent( ) )
   {
      if( m_depth && parent( )->type( ) == PMTNormal )
      {
         str.setNum( m_depth );
         dev.writeLine( str );
      }
   }
   // modifiers
   switch( m_patternType )
   {
      case PatternAgate:
         str.setNum( m_agateTurbulence );
         dev.writeLine( "agate_turb " + str );
         break;
      case PatternDensity:
         str.setNum( m_densityInterpolate );
         dev.writeLine( "interpolate " + str );
         break;
      case PatternQuilted:
         str.setNum( m_quiltControl0 );
         dev.writeLine( "control0 " + str );
         str.setNum( m_quiltControl1 );
         dev.writeLine( "control1 " + str );
         break;
      default:
         break;
   }
   if( m_enableTurbulence )
   {
      dev.writeLine( "turbulence " + m_valueVector.serialize( ) );
      if( m_octaves != octavesDefault )
      {
         str.setNum(m_octaves);
         dev.writeLine( "octaves " + str );
      }
      if( m_omega != omegaDefault )
      {
         str.setNum(m_omega);
         dev.writeLine( "omega " + str );
      }
      if( m_lambda != lambdaDefault )
      {
         str.setNum(m_lambda);
         dev.writeLine( "lambda " + str );
      }
   }
}

void PMPattern::serialize( QDomElement& e, QDomDocument& ) const
{
   switch( m_patternType )
   {
      case PatternAgate:
         e.setAttribute( "patterntype", "agate" );
         break;
      case PatternAverage:
         e.setAttribute( "patterntype", "average" );
         break;
      case PatternBoxed:
         e.setAttribute( "patterntype", "boxed" );
         break;
      case PatternBozo:
         e.setAttribute( "patterntype", "bozo" );
         break;
      case PatternBumps:
         e.setAttribute( "patterntype", "bumps" );
         break;
      case PatternCrackle:
         e.setAttribute( "patterntype", "crackle" );
         break;
      case PatternCylindrical:
         e.setAttribute( "patterntype", "cylindrical" );
         break;
      case PatternDensity:
         e.setAttribute( "patterntype", "density" );
         break;
      case PatternDents:
         e.setAttribute( "patterntype", "dents" );
         break;
      case PatternGradient:
         e.setAttribute( "patterntype", "gradient" );
         break;
      case PatternGranite:
         e.setAttribute( "patterntype", "granite" );
         break;
      case PatternLeopard:
         e.setAttribute( "patterntype", "leopard" );
         break;
      case PatternMandel:
         e.setAttribute( "patterntype", "mandel" );
         break;
      case PatternMarble:
         e.setAttribute( "patterntype", "marble" );
         break;
      case PatternOnion:
         e.setAttribute( "patterntype", "onion" );
         break;
      case PatternPlanar:
         e.setAttribute( "patterntype", "planar" );
         break;
      case PatternQuilted:
         e.setAttribute( "patterntype", "quilted" );
         break;
      case PatternRadial:
         e.setAttribute( "patterntype", "radial" );
         break;
      case PatternRipples:
         e.setAttribute( "patterntype", "ripples" );
         break;
      case PatternSpherical:
         e.setAttribute( "patterntype", "spherical" );
         break;
      case PatternSpiral1:
         e.setAttribute( "patterntype", "spiral1" );
         break;
      case PatternSpiral2:
         e.setAttribute( "patterntype", "spiral2" );
         break;
      case PatternSpotted:
         e.setAttribute( "patterntype", "spotted" );
         break;
      case PatternWaves:
         e.setAttribute( "patterntype", "waves" );
         break;
      case PatternWood:
         e.setAttribute( "patterntype", "wood" );
         break;
      case PatternWrinkles:
         e.setAttribute( "patterntype", "wrinkles" );
         break;
   }
   e.setAttribute( "agateturbulence", m_agateTurbulence );
   e.setAttribute( "spiralnumberarms", m_spiralNumberArms );
   e.setAttribute( "maxiterations", m_maxIterations );
   e.setAttribute( "quiltcontrol0", m_quiltControl0 );
   e.setAttribute( "quiltcontrol1", m_quiltControl1 );
   e.setAttribute( "densityinterpolate", m_densityInterpolate );
   e.setAttribute( "densityfile", m_densityFile );
   e.setAttribute( "gradient", m_gradient.serializeXML( ) );
   e.setAttribute( "enable_turbulence", m_enableTurbulence );
   e.setAttribute( "turbulence", m_valueVector.serializeXML( ) );
   e.setAttribute( "octaves", m_octaves );
   e.setAttribute( "omega", m_omega );
   e.setAttribute( "lambda", m_lambda );
   e.setAttribute( "depth", m_depth );
}

void PMPattern::readAttributes( const PMXMLHelper& h )
{
   QString str = h.stringAttribute( "patterntype", "agate" );

   if( str == "agate" )
      m_patternType = PatternAgate;
   else if( str == "average" )
      m_patternType = PatternAverage;
   else if( str == "boxed" )
      m_patternType = PatternBoxed;
   else if( str == "bozo" )
      m_patternType = PatternBozo;
   else if( str == "bumps" )
      m_patternType = PatternBumps;
   else if( str == "crackle" )
      m_patternType = PatternCrackle;
   else if( str == "cylindrical" )
      m_patternType = PatternCylindrical;
   else if( str == "density" )
      m_patternType = PatternDensity;
   else if( str == "dents" )
      m_patternType = PatternDents;
   else if( str == "gradient" )
      m_patternType = PatternGradient;
   else if( str == "granite" )
      m_patternType = PatternGranite;
   else if( str == "leopard" )
      m_patternType = PatternLeopard;
   else if( str == "mandel" )
      m_patternType = PatternMandel;
   else if( str == "marble" )
      m_patternType = PatternMarble;
   else if( str == "onion" )
      m_patternType = PatternOnion;
   else if( str == "planar" )
      m_patternType = PatternPlanar;
   else if( str == "quilted" )
      m_patternType = PatternQuilted;
   else if( str == "radial" )
      m_patternType = PatternRadial;
   else if( str == "ripples" )
      m_patternType = PatternRipples;
   else if( str == "spherical" )
      m_patternType = PatternSpherical;
   else if( str == "spiral1" )
      m_patternType = PatternSpiral1;
   else if( str == "spiral2" )
      m_patternType = PatternSpiral2;
   else if( str == "spotted" )
      m_patternType = PatternSpotted;
   else if( str == "waves" )
      m_patternType = PatternWaves;
   else if( str == "wood" )
      m_patternType = PatternWood;
   else if( str == "wrinkles" )
      m_patternType = PatternWrinkles;

   m_agateTurbulence = h.doubleAttribute( "agateturbulence", agateTurbulenceDefault );
   m_gradient = h.vectorAttribute( "gradient", gradientDefault );
   m_maxIterations = h.intAttribute( "maxiterations", maxIterationsDefault );
   m_spiralNumberArms = h.intAttribute( "spiralnumberarms", spiralNumberArmsDefault );
   m_quiltControl0 = h.doubleAttribute( "quiltcontrol0", quiltControl0Default );
   m_quiltControl1 = h.doubleAttribute( "quiltcontrol1", quiltControl1Default );
   m_densityInterpolate = h.intAttribute( "densityinterpolate", densityInterpolateDefault );
   m_densityFile = h.stringAttribute( "densityfile", densityFileDefault );
   m_enableTurbulence = h.boolAttribute( "enable_turbulence" , false );
   m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault );
   m_octaves = h.intAttribute( "octaves", octavesDefault );
   m_omega = h.doubleAttribute( "omega", omegaDefault );
   m_lambda = h.doubleAttribute( "lambda", lambdaDefault );
   m_depth = h.doubleAttribute( "depth", depthDefault );

   Base::readAttributes( h );
}

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

QString PMPattern::description( ) const
{
   return i18n( "pattern" );
}

void PMPattern::setPatternType( PMPatternType c )
{
   if( c != m_patternType )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMPatternTypeID, m_patternType );
      m_patternType = c;
   } 
}

void PMPattern::setAgateTurbulence( double c )
{
   if( c != m_agateTurbulence )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMAgateTurbulenceID, m_agateTurbulence );
      m_agateTurbulence = c;
   } 
}

void PMPattern::setSpiralNumberArms( int c )
{
   if( c != m_spiralNumberArms )
   {
      if(m_pMemento )
         m_pMemento->addData( PMTPattern, PMSpiralNumberArmsID, m_spiralNumberArms );
      m_spiralNumberArms = c;
   } 
}

void PMPattern::setMaxIterations( int c )
{
   if( c != m_maxIterations )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMMaxIterationsID, m_maxIterations );
      m_maxIterations = c;
   } 
}

void PMPattern::setQuiltControl0( double c )
{
   if( c != m_quiltControl0 )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMQuiltControl0ID, m_quiltControl0 );
      m_quiltControl0 = c;
   } 
}

void PMPattern::setQuiltControl1( double c )
{
   if( c != m_quiltControl1 )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMQuiltControl1ID, m_quiltControl1 );
      m_quiltControl1 = c;
   } 
}

void PMPattern::setDensityInterpolate( int c )
{
   if( c != m_densityInterpolate )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMDensityInterpolateID, m_densityInterpolate );
      m_densityInterpolate = c;
   } 
}

void PMPattern::setGradient( const PMVector& v )
{
   if( v != m_gradient )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMGradientID, m_gradient );
      m_gradient = v;
   } 
}

void PMPattern::setDensityFile( const QString& s )
{
   if( s != m_densityFile )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMDensityFileID, m_densityFile );
      m_densityFile = s;
   } 
}

void PMPattern::enableTurbulence( bool c )
{
   if( c != m_enableTurbulence )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMEnableTurbulenceID, m_enableTurbulence );
      m_enableTurbulence = c;
   }
}

void PMPattern::setValueVector( const PMVector& c )
{
   if( c != m_valueVector )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMValueVectorID, m_valueVector );
      m_valueVector = c;
   }
}

void PMPattern::setOctaves( const int c )
{
   if( c != m_octaves )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMOctavesID, m_octaves );
      m_octaves = c;
   }
}

void PMPattern::setOmega( const double c )
{
   if( c != m_omega )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMOmegaID, m_omega );
      m_omega = c;
   }
}

void PMPattern::setLambda( const double c )
{
   if( c != m_lambda )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMLambdaID, m_lambda );
      m_lambda = c;
   }
}

void PMPattern::setDepth( const double c )
{
   if( c != m_depth )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTPattern, PMDepthID, m_depth );
      m_depth = c;
   }
}

PMDialogEditBase* PMPattern::editWidget( QWidget* parent ) const
{
   return new PMPatternEdit( parent );
}

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

   for( ; it.current( ); ++it )
   {
      data = it.current( );
      if( data->objectType( ) == PMTPattern )
      {
         switch( data->valueID( ) )
         {
            case PMPatternTypeID:
               setPatternType( ( PMPatternType )data->intData( ) );
               break;
            case PMAgateTurbulenceID:
               setAgateTurbulence( data->doubleData( ) );
               break;
            case PMSpiralNumberArmsID:
               setSpiralNumberArms( data->intData( ) );
               break;
            case PMMaxIterationsID:
               setMaxIterations( data->intData( ) );
               break;
            case PMQuiltControl0ID:
               setQuiltControl0( data->doubleData( ) );
               break;
            case PMQuiltControl1ID:
               setQuiltControl1( data->doubleData( ) );
               break;
            case PMDensityInterpolateID:
               setDensityInterpolate( data->intData( ) );
               break;
            case PMGradientID:
               setGradient( data->vectorData( ) );
               break;
            case PMDensityFileID:
               setDensityFile( data->stringData( ) );
               break;
            case PMEnableTurbulenceID:
               enableTurbulence( data->boolData( ) );
               break;
            case PMValueVectorID:
               setValueVector( data->vectorData( ) );
               break;
            case PMOctavesID:
               setOctaves( data->intData( ) );
               break;
            case PMOmegaID:
               setOmega( data->doubleData( ) );
               break;
            case PMLambdaID:
               setLambda( data->doubleData( ) );
               break;
            case PMDepthID:
               setDepth( data->doubleData( ) );
               break;
            default:
               kdError( PMArea ) << "Wrong ID in PMPattern::restoreMemento\n";
               break;
         }
      }
   }
   Base::restoreMemento( s );
}

