/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2000-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 "pmoutputdevice.h"
#include "pmxmlhelper.h"
#include "pmvector.h"
#include "pmwarp.h"
#include "pmwarpedit.h"
#include "pmmemento.h"

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

#include <klocale.h>

const PMVector directionDefault = PMVector( 1.0, 0.0, 0.0 );
const PMVector offsetDefault = PMVector( 0.0, 0.0, 0.0 );
const PMVector flipDefault = PMVector( 0.0, 0.0, 0.0 );
const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 );
const double radiusDefault = 0;
const double strengthDefault = 0;
const double falloffDefault = 0;
const bool inverseDefault = false;
const PMVector repeatDefault = PMVector( 0.0, 0.0, 0.0 );
const PMVector turbulenceDefault = PMVector( 0.0, 0.0, 0.0 );
const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
const int octavesDefault = 6;
const double omegaDefault = 0.5;
const double lambdaDefault = 2.0;

PMWarp::PMWarp( )
      : Base( )
{
   m_warpType = PMWarp::Repeat;
   m_direction = directionDefault;
   m_offset = offsetDefault;
   m_flip = flipDefault;
   m_location = locationDefault;
   m_radius = radiusDefault;
   m_strength = strengthDefault;
   m_falloff = falloffDefault;
   m_inverse = inverseDefault;
   m_repeat = repeatDefault;
   m_turbulence = turbulenceDefault;
   m_valueVector = valueVectorDefault;
   m_octaves = octavesDefault;
   m_omega = omegaDefault;
   m_lambda = lambdaDefault;
}

PMWarp::~PMWarp( )
{
}

QString PMWarp::description( ) const
{
   return i18n( "warp" );
}

void PMWarp::serialize( PMOutputDevice& dev ) const
{
   QString str1;

   dev.objectBegin( "warp" );
   switch( m_warpType )
   {
      case PMWarp::Repeat:
         dev.writeLine( "repeat" );
         dev.writeLine( m_direction.serialize( ) );
         dev.writeLine( "offset " + m_offset.serialize( ) );
         dev.writeLine( "flip " + m_flip.serialize( ) );
         break;
      case PMWarp::BlackHole:
         dev.writeLine( "black_hole" );
         dev.writeLine( m_location.serialize( ) );
         str1.setNum(m_radius);
         dev.writeLine( ", " + str1 );
         if( m_strength != strengthDefault )
         {
            str1.setNum(m_strength);
            dev.writeLine( "strength " + str1 );
         }
         if( m_falloff != falloffDefault )
         {
            str1.setNum(m_falloff);
            dev.writeLine( "falloff " + str1 );
         }
         if( m_inverse != inverseDefault )
         {
            if( m_inverse ) dev.writeLine( "inverse" );
         }
         if( m_repeat != repeatDefault )
         {
            dev.writeLine( "repeat " + m_repeat.serialize( ) );
         }
         if( m_turbulence != turbulenceDefault )
         {
            dev.writeLine( "turbulence " + m_turbulence.serialize( ) );
         }
         break;
      case PMWarp::Turbulence:
         dev.writeLine( "turbulence " + m_valueVector.serialize( ) );
         if( m_octaves != octavesDefault )
         {
            str1.setNum(m_octaves);
            dev.writeLine( "octaves " + str1 );
         }
         if( m_omega != omegaDefault )
         {
            str1.setNum(m_omega);
            dev.writeLine( "omega " + str1 );
         }
         if( m_lambda != lambdaDefault )
         {
            str1.setNum(m_lambda);
            dev.writeLine( "lambda " + str1 );
         }
         break;
   }
   dev.objectEnd( );
}

void PMWarp::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
{
   switch( m_warpType )
   {
      case PMWarp::Repeat:
         e.setAttribute( "warp_type", "repeat");
         e.setAttribute( "direction", m_direction.serializeXML( ) );
         e.setAttribute( "offset", m_offset.serializeXML( ) );
         e.setAttribute( "flip", m_flip.serializeXML( ) );
         break;
      case PMWarp::BlackHole:
         e.setAttribute( "warp_type", "black hole");
         e.setAttribute( "location", m_location.serializeXML( ) );
         e.setAttribute( "radius", m_radius );
         e.setAttribute( "strength", m_strength );
         e.setAttribute( "falloff", m_falloff );
         e.setAttribute( "inverse", m_inverse );
         e.setAttribute( "repeat", m_repeat.serializeXML( ) );
         e.setAttribute( "turbulence", m_turbulence.serializeXML( ) );
         break;
      case PMWarp::Turbulence:
         e.setAttribute( "warp_type", "turbulence");
         e.setAttribute( "turbulence", m_valueVector.serializeXML( ) );
         e.setAttribute( "octaves", m_octaves );
         e.setAttribute( "omega", m_omega );
         e.setAttribute( "lambda", m_lambda );
         break;
   }
}

void PMWarp::readAttributes( const PMXMLHelper& h )
{
   QString str = h.stringAttribute( "warp_type", "repeat" );

   if( str == "repeat" )
   {
      m_warpType = PMWarp::Repeat;
      m_direction = h.vectorAttribute( "direction", directionDefault );
      m_offset = h.vectorAttribute( "offset", offsetDefault );
      m_flip = h.vectorAttribute( "flip", flipDefault );
   } 
   else if( str == "black hole" )
   {
      m_warpType = PMWarp::BlackHole;
      m_location = h.vectorAttribute( "location", locationDefault );
      m_radius = h.doubleAttribute( "radius", radiusDefault );
      m_strength = h.doubleAttribute( "strength", strengthDefault );
      m_falloff = h.doubleAttribute( "falloff", falloffDefault );
      m_inverse = h.boolAttribute( "inverse", inverseDefault );
      m_repeat = h.vectorAttribute( "repeat", repeatDefault );
      m_turbulence = h.vectorAttribute( "turbulence", turbulenceDefault );
   } 
   else if( str == "turbulence" )
   {
      m_warpType = PMWarp::Turbulence;
      m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault );
      m_octaves = h.intAttribute( "octaves", octavesDefault );
      m_omega = h.doubleAttribute( "omega", omegaDefault );
      m_lambda = h.doubleAttribute( "lambda", lambdaDefault );
   }
}

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

void PMWarp::setWarpType( PMWarpType c )
{
   if( c != m_warpType )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMWarpTypeID, m_warpType );
      m_warpType = c;
   }
}

void PMWarp::setDirection( const PMVector& c )
{
   if( c != m_direction )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMDirectionID, m_direction );
      m_direction = c;
   }
}

void PMWarp::setOffset( const PMVector& c )
{
   if( c != m_offset )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMOffsetID, m_offset );
      m_offset = c;
   }
}

void PMWarp::setFlip( const PMVector& c )
{
   if( c != m_flip )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMFlipID, m_flip );
      m_flip = c;
   }
}

void PMWarp::setLocation( const PMVector& c )
{
   if( c != m_location )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMLocationID, m_location );
      m_location = c;
   }
}

void PMWarp::setRadius( const double c )
{
   if( c != m_radius )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMRadiusID, m_radius );
      m_radius = c;
   }
}

void PMWarp::setStrength( const double c )
{
   if( c != m_strength )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMStrengthID, m_strength );
      m_strength = c;
   }
}

void PMWarp::setFalloff( const double c )
{
   if( c != m_falloff )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMFalloffID, m_falloff );
      m_falloff = c;
   }
}

void PMWarp::setInverse( const bool c )
{
   if( c != m_inverse )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMInverseID, m_inverse );
      m_inverse = c;
   }
}

void PMWarp::setRepeat( const PMVector& c )
{
   if( c != m_repeat )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMRepeatID, m_repeat );
      m_repeat = c;
   }
}

void PMWarp::setTurbulence( const PMVector& c )
{
   if( c != m_turbulence )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTWarp, PMTurbulenceID, m_turbulence );
      m_turbulence = c;
   }
}

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

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

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

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

PMDialogEditBase* PMWarp::editWidget( QWidget* parent ) const
{
   return new PMWarpEdit( parent );
}

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

   for( ; it.current( ); ++it )
   {
      data = it.current( );
      if( data->objectType( ) == PMTWarp )
      {
         switch( data->valueID( ) )
         {
            case PMWarpTypeID:
               setWarpType( ( PMWarpType )data->intData( ) );
               break;
            case PMDirectionID:
               setDirection( data->vectorData( ) );
               break;
            case PMOffsetID:
               setOffset( data->vectorData( ) );
               break;
            case PMFlipID:
               setFlip( data->vectorData( ) );
               break;
            case PMLocationID:
               setLocation( data->vectorData( ) );
               break;
            case PMRadiusID:
               setRadius( data->doubleData( ) );
               break;
            case PMStrengthID:
               setStrength( data->doubleData( ) );
               break;
            case PMFalloffID:
               setFalloff( data->doubleData( ) );
               break;
            case PMInverseID:
               setInverse( data->boolData( ) );
               break;
            case PMRepeatID:
               setRepeat( data->vectorData( ) );
               break;
            case PMTurbulenceID:
               setTurbulence( data->vectorData( ) );
               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;
            default:
               kdError( PMArea ) << "Wrong ID in PMWarp::restoreMemento\n";
               break;
         }
      }
   }
   Base::restoreMemento( s );
}
