/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2001-2002 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 "pmxmlhelper.h"
#include "pmlistpatternedit.h"
#include "pmcompositeobject.h"
#include "pmmemento.h"
#include "pmenumproperty.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 PMPattern::PMNoiseType noiseGeneratorDefault = PMPattern::GlobalSetting;
const QString noiseGeneratorDefaultText = QString( "global_setting" );
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;

PMDefinePropertyClass( PMPattern, PMProperty );
PMDefineEnumPropertyClass( PMPattern, PMPattern::PMPatternType,
                           PMPatternTypeProperty );
PMDefineEnumPropertyClass( PMPattern, PMPattern::PMNoiseType,
                           PMNoiseProperty );

PMMetaObject* PMPattern::s_pMetaObject = 0;
PMObject* createNewPattern( PMPart* part )
{
   return new PMPattern( part );
}

PMPattern::PMPattern( PMPart* part )
      : Base( part )
{
   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_noiseGenerator = noiseGeneratorDefault;
   m_enableTurbulence = false;
   m_valueVector = valueVectorDefault;
   m_octaves = octavesDefault;
   m_omega = omegaDefault;
   m_lambda = lambdaDefault;
   m_depth = depthDefault;
}

PMPattern::PMPattern( const PMPattern& p )
      : Base( p )
{
   m_patternType = p.m_patternType;
   m_agateTurbulence = p.m_agateTurbulence;
   m_densityInterpolate = p.m_densityInterpolate;
   m_gradient = p.m_gradient;
   m_maxIterations = p.m_maxIterations;
   m_quiltControl0 = p.m_quiltControl0;
   m_quiltControl1 = p.m_quiltControl1;
   m_spiralNumberArms = p.m_spiralNumberArms;
   m_noiseGenerator = p.m_noiseGenerator;
   m_enableTurbulence = p.m_enableTurbulence;
   m_valueVector = p.m_valueVector;
   m_octaves = p.m_octaves;
   m_omega = p.m_omega;
   m_lambda = p.m_lambda;
   m_depth = p.m_depth;
}

PMPattern::~PMPattern( )
{
}

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( ) );
   switch ( m_noiseGenerator )
   {
      case GlobalSetting:
         e.setAttribute( "noise_generator", "global_setting" );
         break;
      case Original:
         e.setAttribute( "noise_generator", "original" );
         break;
      case RangeCorrected:
         e.setAttribute( "noise_generator", "range_corrected" );
         break;
      case Perlin:
         e.setAttribute( "noise_generator", "perlin" );
         break;
   }
   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 );
   str = h.stringAttribute( "noise_generator", noiseGeneratorDefaultText );
   if ( str == "original" )
      m_noiseGenerator = Original;
   else if ( str == "range_corrected" )
      m_noiseGenerator = RangeCorrected;
   else if ( str == "perlin" )
      m_noiseGenerator = Perlin;
   else
      m_noiseGenerator = GlobalSetting;
   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 );
}

PMMetaObject* PMPattern::metaObject( ) const
{
   if( !s_pMetaObject )
   {
      s_pMetaObject = new PMMetaObject( "Pattern", Base::metaObject( ),
                                        createNewPattern );
      s_pMetaObject->addProperty(
         new PMProperty( "agateTurbulence", &PMPattern::setAgateTurbulence, &PMPattern::agateTurbulence ) );
      s_pMetaObject->addProperty(
         new PMProperty( "spiralNumberArms", &PMPattern::setSpiralNumberArms, &PMPattern::spiralNumberArms ) );
      s_pMetaObject->addProperty(
         new PMProperty( "maxIterations", &PMPattern::setMaxIterations, &PMPattern::maxIterations ) );
      s_pMetaObject->addProperty(
         new PMProperty( "gradient", &PMPattern::setGradient, &PMPattern::gradient ) );
      s_pMetaObject->addProperty(
         new PMProperty( "quiltControl0", &PMPattern::setQuiltControl0, &PMPattern::quiltControl0 ) );
      s_pMetaObject->addProperty(
         new PMProperty( "quiltControl1", &PMPattern::setQuiltControl1, &PMPattern::quiltControl1 ) );
      s_pMetaObject->addProperty(
         new PMProperty( "densityFile", &PMPattern::setDensityFile, &PMPattern::densityFile ) );
      s_pMetaObject->addProperty(
         new PMProperty( "densityInterpolate", &PMPattern::setDensityInterpolate, &PMPattern::densityInterpolate ) );
      s_pMetaObject->addProperty(
         new PMProperty( "valueVector", &PMPattern::setValueVector, &PMPattern::valueVector ) );
      s_pMetaObject->addProperty(
         new PMProperty( "octaves", &PMPattern::setOctaves, &PMPattern::octaves ) );
      s_pMetaObject->addProperty(
         new PMProperty( "omega", &PMPattern::setOmega, &PMPattern::omega ) );
      s_pMetaObject->addProperty(
         new PMProperty( "lambda", &PMPattern::setLambda, &PMPattern::lambda ) );
      s_pMetaObject->addProperty(
         new PMProperty( "turbulence", &PMPattern::enableTurbulence, &PMPattern::isTurbulenceEnabled ) );

      PMPatternTypeProperty* p = new PMPatternTypeProperty(
         "patternType", &PMPattern::setPatternType, &PMPattern::patternType );
      p->addEnumValue( "Agate", PatternAgate );
      p->addEnumValue( "Average", PatternAverage );
      p->addEnumValue( "Boxed", PatternBoxed );
      p->addEnumValue( "Bozo", PatternBozo );
      p->addEnumValue( "Bumps", PatternBumps );
      p->addEnumValue( "Crackle", PatternCrackle );
      p->addEnumValue( "Cylindrical", PatternCylindrical );
      p->addEnumValue( "Density", PatternDensity );
      p->addEnumValue( "Dents", PatternDents );
      p->addEnumValue( "Gradient", PatternGradient );
      p->addEnumValue( "Granite", PatternGranite );
      p->addEnumValue( "Leopard", PatternLeopard );
      p->addEnumValue( "Mandel", PatternMandel );
      p->addEnumValue( "Marble", PatternMarble );
      p->addEnumValue( "Onion", PatternOnion );
      p->addEnumValue( "Planar", PatternPlanar );
      p->addEnumValue( "Quilted", PatternQuilted );
      p->addEnumValue( "Radial", PatternRadial );
      p->addEnumValue( "Ripples", PatternRipples );
      p->addEnumValue( "Spherical", PatternSpherical );
      p->addEnumValue( "Spiral1", PatternSpiral1 );
      p->addEnumValue( "Spiral2", PatternSpiral2 );
      p->addEnumValue( "Spotted", PatternSpotted );
      p->addEnumValue( "Waves", PatternWaves );
      p->addEnumValue( "Wood", PatternWood );
      p->addEnumValue( "Wrinkles", PatternWrinkles );
      s_pMetaObject->addProperty( p );

      PMNoiseProperty* p2 = new PMNoiseProperty(
         "noiseGenerator", &PMPattern::setNoiseGenerator, &PMPattern::noiseGenerator );
      p2->addEnumValue( "GlobalSetting", GlobalSetting );
      p2->addEnumValue( "Original", Original );
      p2->addEnumValue( "RangeCorrected", RangeCorrected );
      p2->addEnumValue( "Perlin", Perlin );
      s_pMetaObject->addProperty( p2 );
   }
   return s_pMetaObject;
}

void PMPattern::cleanUp( ) const
{
   if( s_pMetaObject )
   {
      delete s_pMetaObject;
      s_pMetaObject = 0;
   }
   Base::cleanUp( );
}

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

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

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

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

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

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

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

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

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

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

void PMPattern::setNoiseGenerator( PMNoiseType c )
{
   if( c != m_noiseGenerator )
   {
      if( m_pMemento )
         m_pMemento->addData( s_pMetaObject, PMNoiseGeneratorID, m_noiseGenerator );
      m_noiseGenerator = c;
   }
}

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

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

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

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

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

void PMPattern::setDepth( const double c )
{
   if( c != m_depth )
   {
      if( m_pMemento )
         m_pMemento->addData( s_pMetaObject, 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( ) == s_pMetaObject )
      {
         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 PMNoiseGeneratorID:
               setNoiseGenerator( ( PMNoiseType ) ( data->intData( ) ) );
               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 );
}

