/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2002 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 "pmheightfield.h"

#include "pmoutputdevice.h"
#include "pmxmlhelper.h"
#include "pmheightfieldedit.h"
#include "pmmemento.h"
#include "pmviewstructure.h"

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

#include <klocale.h>

const PMHeightField::HeightFieldType c_defaultType = PMHeightField::HFgif;
const QString c_defaultTypeText = QString( "gif" );
const QString c_defaultFileName = QString( "" );
const bool c_defaultHierarchy = true;
const bool c_defaultSmooth = false;
const double c_defaultWaterLevel = 0.0;

PMViewStructure* PMHeightField::s_pDefaultViewStructure = 0;

PMHeightField::PMHeightField( )
      : Base( )
{
   m_hfType = c_defaultType;
   m_fileName = c_defaultFileName;
   m_hierarchy = c_defaultHierarchy;
   m_smooth = c_defaultSmooth;
   m_waterLevel = c_defaultWaterLevel;
}

PMHeightField::~PMHeightField( )
{
}

QString PMHeightField::description( ) const
{
   return i18n( "height field" );
}

void PMHeightField::serialize( PMOutputDevice& dev ) const
{
   dev.objectBegin( "height_field" );

   serializeName( dev );

   dev.writeLine( typeToString( m_hfType ) + " \"" + m_fileName + "\"" );
   if( m_waterLevel > 0.0 )
      dev.writeLine( QString( "water_level %1" ).arg( m_waterLevel ) );
   if( !m_hierarchy )
      dev.writeLine( "hierarchy off" );
   if( m_smooth )
      dev.writeLine( "smooth" );
   
   Base::serialize( dev );
   dev.objectEnd( );
}

void PMHeightField::serialize( QDomElement& e, QDomDocument& doc ) const
{
   e.setAttribute( "hf_type", typeToString( m_hfType ) );
   e.setAttribute( "file_name", m_fileName );
   e.setAttribute( "hierarchy", m_hierarchy );
   e.setAttribute( "smooth", m_smooth );
   e.setAttribute( "water_level", m_waterLevel );
   Base::serialize( e, doc );
}

void PMHeightField::readAttributes( const PMXMLHelper& h )
{
   m_hfType = stringToType( h.stringAttribute( "hf_type", c_defaultTypeText ) );
   m_fileName = h.stringAttribute( "file_name", c_defaultFileName );
   m_hierarchy = h.boolAttribute( "hierarchy", c_defaultHierarchy );
   m_smooth = h.boolAttribute( "smooth", c_defaultSmooth );
   m_waterLevel = h.doubleAttribute( "water_level", c_defaultWaterLevel );
   Base::readAttributes( h );
}

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

void PMHeightField::setHeightFieldType( PMHeightField::HeightFieldType t )
{
   if( t != m_hfType )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTHeightField, PMHeightFieldTypeID, m_hfType );
      m_hfType = t;
   }
}

void PMHeightField::setFileName( const QString& f )
{
   if( f != m_fileName )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTHeightField, PMFileNameID, m_fileName );
      m_fileName = f;
   }
}

void PMHeightField::setHierarchy( bool h )
{
   if( h != m_hierarchy )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTHeightField, PMHierarchyID, m_hierarchy );
      m_hierarchy = h;
   }
}

void PMHeightField::setSmooth( bool s )
{
   if( s != m_smooth )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTHeightField, PMSmoothID, m_smooth );
      m_smooth = s;
   }
}

void PMHeightField::setWaterLevel( double wl )
{
   if( wl < 0.0 )
   {
      kdError( PMArea ) << "Water level < 0.0 in PMHeightField::setWaterLevel\n";
      wl = 0.0;
   }
   if( wl > 1.0 )
   {
      kdError( PMArea ) << "Water level > 1.0 in PMHeightField::setWaterLevel\n";
      wl = 1.0;
   }
   
   if( wl != m_waterLevel )
   {
      if( m_pMemento )
         m_pMemento->addData( PMTHeightField, PMWaterLevelID, m_waterLevel );
      m_waterLevel = wl;
      setViewStructureChanged( );
   }
}

PMDialogEditBase* PMHeightField::editWidget( QWidget* parent ) const
{
   return new PMHeightFieldEdit( parent );
}

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

   for( ; it.current( ); ++it )
   {
      data = it.current( );
      if( data->objectType( ) == PMTHeightField )
      {
         switch( data->valueID( ) )
         {
            case PMHeightFieldTypeID:
               m_hfType = ( HeightFieldType ) data->intData( );
               break;
            case PMFileNameID:
               m_fileName = data->stringData( );
               break;
            case PMHierarchyID:
               m_hierarchy = data->boolData( );
               break;
            case PMSmoothID:
               m_smooth = data->boolData( );
               break;
            case PMWaterLevelID:
               m_waterLevel = data->doubleData( );
               break;
            default:
               kdError( PMArea ) << "Wrong ID in PMHeightField::restoreMemento\n";
               break;
         }
      }
   }
   Base::restoreMemento( s );
}


bool PMHeightField::isDefault( )
{
   return ( m_waterLevel == c_defaultWaterLevel );
}

void PMHeightField::createViewStructure( )
{
   if( !m_pViewStructure )
   {
      m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
      m_pViewStructure->points( ).detach( );
   }

   PMPointArray& points = m_pViewStructure->points( );

   points[4][1] = m_waterLevel;
   points[5][1] = m_waterLevel;
   points[6][1] = m_waterLevel;
   points[7][1] = m_waterLevel;
}

PMViewStructure* PMHeightField::defaultViewStructure( ) const
{
   if( !s_pDefaultViewStructure )
   {
      s_pDefaultViewStructure = new PMViewStructure( 12, 20 );
      PMPointArray& points = s_pDefaultViewStructure->points( );
      PMLineArray& lines = s_pDefaultViewStructure->lines( );

      points[ 0] = PMPoint( 0.0, 0.0, 0.0 );
      points[ 1] = PMPoint( 1.0, 0.0, 0.0 );
      points[ 2] = PMPoint( 1.0, 0.0, 1.0 );
      points[ 3] = PMPoint( 0.0, 0.0, 1.0 );
      points[ 4] = PMPoint( 0.0, c_defaultWaterLevel, 0.0 );
      points[ 5] = PMPoint( 1.0, c_defaultWaterLevel, 0.0 );
      points[ 6] = PMPoint( 1.0, c_defaultWaterLevel, 1.0 );
      points[ 7] = PMPoint( 0.0, c_defaultWaterLevel, 1.0 );
      points[ 8] = PMPoint( 0.0, 1.0, 0.0 );
      points[ 9] = PMPoint( 1.0, 1.0, 0.0 );
      points[10] = PMPoint( 1.0, 1.0, 1.0 );
      points[11] = PMPoint( 0.0, 1.0, 1.0 );
      
      lines[ 0] = PMLine( 0, 1 );
      lines[ 1] = PMLine( 1, 2 );
      lines[ 2] = PMLine( 2, 3 );
      lines[ 3] = PMLine( 0, 3 );
      
      lines[ 4] = PMLine( 0, 4 );
      lines[ 5] = PMLine( 1, 5 );
      lines[ 6] = PMLine( 2, 6 );
      lines[ 7] = PMLine( 3, 7 );
      
      lines[ 8] = PMLine( 4, 5 );
      lines[ 9] = PMLine( 5, 6 );
      lines[10] = PMLine( 6, 7 );
      lines[11] = PMLine( 4, 7 );
      
      lines[12] = PMLine( 4, 8 );
      lines[13] = PMLine( 5, 9 );
      lines[14] = PMLine( 6, 10 );
      lines[15] = PMLine( 7, 11 );
      
      lines[16] = PMLine( 8, 9 );
      lines[17] = PMLine( 9, 10 );
      lines[18] = PMLine( 10, 11 );
      lines[19] = PMLine( 8, 11 );
   }
   return s_pDefaultViewStructure;
}

QString PMHeightField::typeToString( PMHeightField::HeightFieldType t )
{
   QString s;
   switch( t )
   {
      case HFgif:
         s = QString( "gif" );
         break;
      case HFtga:
         s = QString( "tga" );
         break;
      case HFpot:
         s = QString( "pot" );
         break;
      case HFpng:
         s = QString( "png" );
         break;
      case HFpgm:
         s = QString( "pgm" );
         break;
      case HFppm:
         s = QString( "ppm" );
         break;
      case HFsys:
         s = QString( "sys" );
         break;
   }
   return s;
}

PMHeightField::HeightFieldType PMHeightField::stringToType( QString str )
{
   HeightFieldType t = HFgif;
   if( str == "gif" )
      t = HFgif;
   else if( str == "tga" )
      t = HFtga;
   else if( str == "pot" )
      t = HFpot;
   else if( str == "png" )
      t = HFpng;
   else if( str == "pgm" )
      t = HFpgm;
   else if( str == "ppm" )
      t = HFppm;
   else if( str == "sys" )
      t = HFsys;
   return t;
}

void PMHeightField::cleanUp( ) const
{
   if( s_pDefaultViewStructure )
      delete s_pDefaultViewStructure;
   s_pDefaultViewStructure = 0;
   Base::cleanUp( );
}
