
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//           Application Programming Interface           //
//                                                       //
//                  Library: SAGA_API                    //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                     parameter.cpp                     //
//                                                       //
//          Copyright (C) 2005 by Olaf Conrad            //
//                                                       //
//-------------------------------------------------------//
//                                                       //
// This file is part of 'SAGA - System for Automated     //
// Geoscientific Analyses'.                              //
//                                                       //
// This library is free software; you can redistribute   //
// it and/or modify it under the terms of the GNU Lesser //
// General Public License as published by the Free       //
// Software Foundation, either version 2.1 of the        //
// License, or (at your option) any later version.       //
//                                                       //
// This library is distributed in the hope that it will  //
// be useful, but WITHOUT ANY WARRANTY; without even the //
// implied warranty of MERCHANTABILITY or FITNESS FOR A  //
// PARTICULAR PURPOSE. See the GNU Lesser General Public //
// License for more details.                             //
//                                                       //
// You should have received a copy of the GNU Lesser     //
// General Public License along with this program; if    //
// not, see <http://www.gnu.org/licenses/>.              //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//    contact:    Olaf Conrad                            //
//                Institute of Geography                 //
//                University of Goettingen               //
//                Germany                                //
//                                                       //
//    e-mail:     oconrad@saga-gis.org                   //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#include "parameters.h"
#include "data_manager.h"
#include "tool.h"
#include "tool_library.h"


///////////////////////////////////////////////////////////
//                                                       //
//                                                       //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Parameter::CSG_Parameter(CSG_Parameters *pParameters, CSG_Parameter *pParent, const CSG_String &Identifier, const CSG_String &Name, const CSG_String &Description, int Constraint)
{
	m_pParameters	= pParameters;
	m_pParent		= pParent;
	m_Identifier	= Identifier;
	m_Name			= Name;
	m_Description	= Description;
	m_Constraint	= Constraint;

	m_bEnabled		= true;

	//-----------------------------------------------------
	m_nChildren		= 0;
	m_Children		= NULL;

	if( m_pParent )
	{
		m_pParent->_Add_Child(this);
	}
}

//---------------------------------------------------------
CSG_Parameter::~CSG_Parameter(void)
{
	if( m_Children )
	{
		SG_Free(m_Children);
	}
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Parameters * CSG_Parameter::Get_Parameters(void)	const
{
	return( m_pParameters );	
}

//---------------------------------------------------------
CSG_Parameter * CSG_Parameter::Get_Parent(void)	const
{
	return( m_pParent );
}

//---------------------------------------------------------
CSG_Data_Manager * CSG_Parameter::Get_Manager(void)	const
{
	return( m_pParameters ? m_pParameters->Get_Manager() : NULL );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_String CSG_Parameter::Get_Type_Identifier(void)	const
{
	return( SG_Parameter_Type_Get_Identifier(Get_Type()) );
}

//---------------------------------------------------------
CSG_String CSG_Parameter::Get_Type_Name(void)	const
{
	return( SG_Parameter_Type_Get_Name(Get_Type()) );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameter::Set_Collapsed(bool bOn)
{
	if( bOn )
	{
		m_Constraint |=  PARAMETER_GUI_COLLAPSED;
	}
	else
	{
		m_Constraint &= ~PARAMETER_GUI_COLLAPSED;
	}

	return( is_Collapsed() );
}

//---------------------------------------------------------
void CSG_Parameter::Set_UseInGUI(bool bOn)
{
	if( bOn )
	{
		m_Constraint &= ~PARAMETER_NOT_FOR_GUI;
	}
	else
	{
		m_Constraint |=  PARAMETER_NOT_FOR_GUI;
	}
}

//---------------------------------------------------------
void CSG_Parameter::Set_UseInCMD(bool bOn)
{
	if( bOn )
	{
		m_Constraint &= ~PARAMETER_NOT_FOR_CMD;
	}
	else
	{
		m_Constraint |=  PARAMETER_NOT_FOR_CMD;
	}
}

//---------------------------------------------------------
bool CSG_Parameter::do_UseInGUI(void)	const
{
	return( !(m_Constraint & PARAMETER_NOT_FOR_GUI) && (Get_Parent() == NULL || Get_Parent()->do_UseInGUI()) );
}

//---------------------------------------------------------
bool CSG_Parameter::do_UseInCMD(void)	const
{
	return( !(m_Constraint & PARAMETER_NOT_FOR_CMD) && (Get_Parent() == NULL || Get_Parent()->do_UseInCMD()) );
}

//---------------------------------------------------------
void CSG_Parameter::ignore_Projection(bool bIgnore)
{
	if( bIgnore )
	{
		m_Constraint	&= ~PARAMETER_IGNORE_PROJECTION;
	}
	else
	{
		m_Constraint	|=  PARAMETER_IGNORE_PROJECTION;
	}
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameter::Set_Enabled(bool bEnabled)
{
	if( m_bEnabled != bEnabled )
	{
		m_bEnabled	= bEnabled;

		return( !bEnabled );
	}

	return( bEnabled );
}

//---------------------------------------------------------
bool CSG_Parameter::is_Enabled(bool bCheckEnv) const
{
	if( bCheckEnv )
	{
		if( !do_UseInGUI() &&  m_pParameters->has_GUI() )
		{
			return( false );
		}

		if( !do_UseInCMD() && !m_pParameters->has_GUI() )
		{
			return( false );
		}
	}

	return( m_bEnabled && (m_pParent == NULL || m_pParent->is_Enabled()) );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Children_Enabled(bool bEnabled)
{
	for(int i=0; i<Get_Children_Count(); i++)
	{
		Get_Child(i)->Set_Enabled(bEnabled);
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::is_Option(void)	const
{
	if( !is_Information() )
	{
		switch( Get_Type() )
		{
		case PARAMETER_TYPE_Bool        :
		case PARAMETER_TYPE_Int         :
		case PARAMETER_TYPE_Double      :
		case PARAMETER_TYPE_Degree      :
		case PARAMETER_TYPE_Date        :
		case PARAMETER_TYPE_Range       :
		case PARAMETER_TYPE_Data_Type   :
		case PARAMETER_TYPE_Choice      :
		case PARAMETER_TYPE_Choices     :
		case PARAMETER_TYPE_String      :
		case PARAMETER_TYPE_Text        :
		case PARAMETER_TYPE_FilePath    :
		case PARAMETER_TYPE_Font        :
		case PARAMETER_TYPE_Color       :
		case PARAMETER_TYPE_Colors      :
		case PARAMETER_TYPE_FixedTable  :
		case PARAMETER_TYPE_Grid_System :
		case PARAMETER_TYPE_Table_Field :
		case PARAMETER_TYPE_Table_Fields:
		case PARAMETER_TYPE_Parameters  :
			return( true );

		default:
			return( false );
		}
	}

	return( false );
}

//---------------------------------------------------------
bool CSG_Parameter::is_DataObject(void)	const
{
	switch( Get_Type() )
	{
	case PARAMETER_TYPE_DataObject_Output:
	case PARAMETER_TYPE_Grid             :
	case PARAMETER_TYPE_Grids            :
	case PARAMETER_TYPE_Table            :
	case PARAMETER_TYPE_Shapes           :
	case PARAMETER_TYPE_TIN              :
	case PARAMETER_TYPE_PointCloud       :
		return( true );

	default:
		return( false );
	}
}

//---------------------------------------------------------
bool CSG_Parameter::is_DataObject_List(void)	const
{
	switch( Get_Type() )
	{
	case PARAMETER_TYPE_Grid_List      :
	case PARAMETER_TYPE_Grids_List     :
	case PARAMETER_TYPE_Table_List     :
	case PARAMETER_TYPE_Shapes_List    :
	case PARAMETER_TYPE_TIN_List       :
	case PARAMETER_TYPE_PointCloud_List:
		return( true );

	default:
		return( false );
	}
}

//---------------------------------------------------------
bool CSG_Parameter::is_Parameters(void)	const
{
	return( Get_Type() == PARAMETER_TYPE_Parameters );
}

//---------------------------------------------------------
bool CSG_Parameter::is_Serializable(void)	const
{
	switch( Get_Type() )
	{
	case PARAMETER_TYPE_Undefined        :
	case PARAMETER_TYPE_Node             :
	case PARAMETER_TYPE_DataObject_Output:
		return( false );

	case PARAMETER_TYPE_String           :
		return( ((CSG_Parameter_String *)this)->is_Password() == false );

	default:
		return( !is_Information() );
	}
}

//---------------------------------------------------------
bool CSG_Parameter::is_Compatible(CSG_Parameter *pParameter)	const
{
	if( pParameter && pParameter->Get_Type() == Get_Type() )
	{
		switch( Get_Type() )
		{
		//-------------------------------------------------
		case PARAMETER_TYPE_Data_Type        :
		case PARAMETER_TYPE_Choice           :
			{
				bool	bResult	= pParameter->asChoice()->Get_Count() == asChoice()->Get_Count();

				for(int i=0; bResult && i<asChoice()->Get_Count(); i++)
				{
					bResult	= SG_STR_CMP(pParameter->asChoice()->Get_Item(i), asChoice()->Get_Item(i)) == 0;
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_Choices          :
			{
				bool	bResult	= pParameter->asChoices()->Get_Item_Count() == asChoices()->Get_Item_Count();

				for(int i=0; bResult && i<asChoices()->Get_Item_Count(); i++)
				{
					bResult	= SG_STR_CMP(pParameter->asChoices()->Get_Item(i), asChoices()->Get_Item(i)) == 0;
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_FixedTable       :	return( pParameter->asTable()->is_Compatible(asTable()) );

		//-------------------------------------------------
		case PARAMETER_TYPE_Parameters       :
			{
				bool	bResult	= pParameter->asParameters()->Get_Count() == asParameters()->Get_Count();

				for(int i=0; bResult && i<asParameters()->Get_Count(); i++)
				{
					bResult	= pParameter->asParameters()->Get_Parameter(i)->is_Compatible(asParameters()->Get_Parameter(i));
				}

				return( bResult );
			}

		//-------------------------------------------------
		default:
			return( true );
		}
	}

	return( false );
}

//---------------------------------------------------------
bool CSG_Parameter::is_Value_Equal(CSG_Parameter *pParameter)	const
{
	if( pParameter && pParameter->Get_Type() == Get_Type() )
	{
		switch( Get_Type() )
		{
		case PARAMETER_TYPE_Node             :	return( true );

		//-------------------------------------------------
		case PARAMETER_TYPE_Bool             :	return( pParameter->asBool  () == asBool  () );
		case PARAMETER_TYPE_Table_Field      :
		case PARAMETER_TYPE_Data_Type        :
		case PARAMETER_TYPE_Choice           :
		case PARAMETER_TYPE_Color            :
		case PARAMETER_TYPE_Int              :	return( pParameter->asInt   () == asInt   () );
		case PARAMETER_TYPE_Date             :
		case PARAMETER_TYPE_Degree           :
		case PARAMETER_TYPE_Double           :	return( pParameter->asDouble() == asDouble() );

		case PARAMETER_TYPE_Table_Fields     :
		case PARAMETER_TYPE_Font             :
		case PARAMETER_TYPE_Text             :
		case PARAMETER_TYPE_FilePath         :
		case PARAMETER_TYPE_String           :	return( SG_STR_CMP(pParameter->asString(), asString()) == 0 );

		case PARAMETER_TYPE_Range            :	return( pParameter->asRange()->Get_Min() == asRange()->Get_Min()
													&&  pParameter->asRange()->Get_Max() == asRange()->Get_Max() );

		case PARAMETER_TYPE_Grid_System      :	return( pParameter->asGrid_System()->is_Equal(*asGrid_System()) );

		//-------------------------------------------------
		case PARAMETER_TYPE_Choices          :
			{
				bool	bResult	= pParameter->asChoices()->Get_Selection_Count() == asChoices()->Get_Selection_Count();

				for(int i=0; bResult && i<asChoices()->Get_Selection_Count(); i++)
				{
					bResult	= pParameter->asChoices()->Get_Selection_Index(i) == asChoices()->Get_Selection_Index(i);
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_Colors           :
			{
				bool	bResult	= pParameter->asColors()->Get_Count() == asColors()->Get_Count();

				for(int i=0; bResult && i<asColors()->Get_Count(); i++)
				{
					bResult	= pParameter->asColors()->Get_Color(i) == asColors()->Get_Color(i);
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_FixedTable       :
			{
				bool	bResult	= pParameter->asTable()->is_Compatible(asTable()) && pParameter->asTable()->Get_Count() == asTable()->Get_Count();

				for(int i=0; bResult && i<asTable()->Get_Count(); i++)
				{
					CSG_Table_Record *pA = pParameter->asTable()->Get_Record(i), *pB = asTable()->Get_Record(i);

					for(int j=0; bResult && j<asTable()->Get_Field_Count(); j++)
					{
						bResult	= SG_STR_CMP(pA->asString(j), pB->asString(j)) == 0;
					}
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_DataObject_Output:
		case PARAMETER_TYPE_Grid             :
		case PARAMETER_TYPE_Grids            :
		case PARAMETER_TYPE_Table            :
		case PARAMETER_TYPE_Shapes           :
		case PARAMETER_TYPE_TIN              :
		case PARAMETER_TYPE_PointCloud       :	return( pParameter->asDataObject() == asDataObject() );

		//-------------------------------------------------
		case PARAMETER_TYPE_Grid_List        :
		case PARAMETER_TYPE_Grids_List       :
		case PARAMETER_TYPE_Table_List       :
		case PARAMETER_TYPE_Shapes_List      :
		case PARAMETER_TYPE_TIN_List         :
		case PARAMETER_TYPE_PointCloud_List  :
			{
				bool	bResult	= pParameter->asList()->Get_Item_Count() == asList()->Get_Item_Count();

				for(int i=0; bResult && i<asList()->Get_Item_Count(); i++)
				{
					bResult	= pParameter->asList()->Get_Item(i) == asList()->Get_Item(i);
				}

				return( bResult );
			}

		//-------------------------------------------------
		case PARAMETER_TYPE_Parameters       :
			{
				bool	bResult	= pParameter->asParameters()->Get_Count() == asParameters()->Get_Count();

				for(int i=0; bResult && i<asParameters()->Get_Count(); i++)
				{
					bResult	= pParameter->asParameters()->Get_Parameter(i)->is_Value_Equal(asParameters()->Get_Parameter(i));
				}

				return( bResult );
			}

		//-------------------------------------------------
		default:	break;
		}
	}

	return( false );
}

//---------------------------------------------------------
TSG_Data_Object_Type CSG_Parameter::Get_DataObject_Type(void)	const
{
	switch( Get_Type() )
	{
	default                              :	return( SG_DATAOBJECT_TYPE_Undefined  );
	case PARAMETER_TYPE_Grid             :
	case PARAMETER_TYPE_Grid_List        :	return( SG_DATAOBJECT_TYPE_Grid       );
	case PARAMETER_TYPE_Grids            :
	case PARAMETER_TYPE_Grids_List       :	return( SG_DATAOBJECT_TYPE_Grids      );
	case PARAMETER_TYPE_Table            :
	case PARAMETER_TYPE_Table_List       :	return( SG_DATAOBJECT_TYPE_Table      );
	case PARAMETER_TYPE_Shapes           :
	case PARAMETER_TYPE_Shapes_List      :	return( SG_DATAOBJECT_TYPE_Shapes     );
	case PARAMETER_TYPE_TIN              :
	case PARAMETER_TYPE_TIN_List         :	return( SG_DATAOBJECT_TYPE_TIN        );
	case PARAMETER_TYPE_PointCloud       :
	case PARAMETER_TYPE_PointCloud_List  :	return( SG_DATAOBJECT_TYPE_PointCloud );
	case PARAMETER_TYPE_DataObject_Output:
		return( ((CSG_Parameter_Data_Object_Output *)this)->Get_DataObject_Type() );
	}
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
const SG_Char * CSG_Parameter::Get_Identifier(void)	const
{
	return( m_Identifier );
}

//---------------------------------------------------------
bool CSG_Parameter::Cmp_Identifier(const CSG_String &Identifier)	const
{
	return( !m_Identifier.Cmp(Identifier) || !m_Identifier.Cmp(Identifier + ".Default") );
}

//---------------------------------------------------------
/**
* Constructs a command line parser conform identifier.
*/
//---------------------------------------------------------
CSG_String CSG_Parameter::Get_CmdID(void)	const
{
	CSG_String ID(Get_Parameters()->Get_Identifier());

	if( ID.Length() > 0 )
	{
		ID += "_";
	}

	ID += Get_Identifier();

	ID.Replace(".", "_");
	ID.Replace("|", "_");
	ID.Replace(" ", "_");

	return( ID );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Name(const CSG_String &Name)
{
	m_Name	= Name;

	return( true );
}

const SG_Char * CSG_Parameter::Get_Name(void)	const
{
	return( m_Name );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Description(const CSG_String &Description)
{
	m_Description = Description;

	return( true );
}

const SG_Char * CSG_Parameter::Get_Description(void)	const
{
	return( m_Description );
}

//---------------------------------------------------------
CSG_String CSG_Parameter::Get_Description(int Flags)	const
{
	return( Get_Description(Flags, SG_T("\n")) );
}

//---------------------------------------------------------
CSG_String CSG_Parameter::Get_Description(int Flags, const SG_Char *Separator)	const
{
	#define SEPARATE if( !s.is_Empty() ) { s.Append(Separator); }

	if( !Separator || !Separator[0] )
	{
		return( Get_Description(Flags) );
	}

	CSG_String s;

	//-----------------------------------------------------
	if( (Flags & PARAMETER_DESCRIPTION_NAME) != 0 )
	{
		SEPARATE; s += CSG_String::Format("%s", Get_Name());
	}

	//-----------------------------------------------------
	if( (Flags & PARAMETER_DESCRIPTION_TYPE) != 0 )
	{
		SEPARATE;

		if( is_DataObject() && Get_Type() == PARAMETER_TYPE_DataObject_Output )
		{
			s += CSG_String::Format("%s %s", Get_Type_Name().c_str(), SG_Get_DataObject_Name(Get_DataObject_Type()).c_str());
		}
		else
		{
			s += CSG_String::Format("%s", Get_Type_Name().c_str());
		}

		if( is_DataObject() || is_DataObject_List() )
		{
			s += CSG_String::Format(", %s", is_Input() ? _TL("input") : _TL("output"));

			if( is_Optional() )
			{
				s += CSG_String::Format(", %s", _TL("optional"));
			}
		}

		if( do_UseInGUI() != do_UseInCMD() )
		{
			if( m_pParameters->has_GUI() || do_UseInGUI() )
			{
				s += CSG_String::Format("\n[%s]", do_UseInGUI() ? SG_T("GUI") : SG_T("CMD"));
			}
		}
	}

	//-----------------------------------------------------
	if( (Flags & PARAMETER_DESCRIPTION_OPTIONAL) != 0 && is_Optional() )
	{
		SEPARATE; s += CSG_String::Format("%s", _TL("optional"));
	}

	//-----------------------------------------------------
	if( (Flags & PARAMETER_DESCRIPTION_PROPERTIES) != 0 )
	{
		switch( Get_Type() )
		{
		default:
			break;

		case PARAMETER_TYPE_Data_Type  :
			SEPARATE; s += CSG_String::Format("%s:", _TL("Available Choices"));

			for(int i=0; i<asChoice()->Get_Count(); i++)
			{
				s += CSG_String::Format("%s[%d] %s", Separator, i, asChoice()->Get_Item(i));
			}
			break;

		case PARAMETER_TYPE_Choice     :
			if( do_UseInCMD() || asChoice()->Get_Count() < 32 )
			{
				SEPARATE; s += CSG_String::Format("%s:", _TL("Available Choices"));

				for(int i=0; i<asChoice()->Get_Count(); i++)
				{
					s += CSG_String::Format("%s[%d] %s", Separator, i, asChoice()->Get_Item(i));
				}
			}
			else
			{
				SEPARATE; s += CSG_String::Format("%d %s:", asChoice()->Get_Count(), _TL("Choices"));
			}
			break;

		case PARAMETER_TYPE_Choices   :
			if( do_UseInCMD() || asChoices()->Get_Item_Count() < 32 )
			{
				SEPARATE; s += CSG_String::Format("%s:", _TL("Available Choices"));

				for(int i=0; i<asChoices()->Get_Item_Count(); i++)
				{
					s += CSG_String::Format("%s[%d] %s", Separator, i, asChoices()->Get_Item(i).c_str());
				}
			}
			else
			{
				SEPARATE; s += CSG_String::Format("%d %s:", asChoices()->Get_Item_Count(), _TL("Choices"));
			}
			break;

		case PARAMETER_TYPE_Int       :
			if( asValue()->has_Minimum() )
			{
				SEPARATE; s += CSG_String::Format("%s: %d", _TL("Minimum"), (int)asValue()->Get_Minimum());
			}

			if( asValue()->has_Maximum() )
			{
				SEPARATE; s += CSG_String::Format("%s: %d", _TL("Maximum"), (int)asValue()->Get_Maximum());
			}
			break;

		case PARAMETER_TYPE_Double    :
		case PARAMETER_TYPE_Degree    :
//		case PARAMETER_TYPE_Range     :
			if( asValue()->has_Minimum() )
			{
				SEPARATE; s += CSG_String::Format("%s: %f", _TL("Minimum"), asValue()->Get_Minimum());
			}

			if( asValue()->has_Maximum() )
			{
				SEPARATE; s += CSG_String::Format("%s: %f", _TL("Maximum"), asValue()->Get_Maximum());
			}
			break;

		case PARAMETER_TYPE_FixedTable:
			SEPARATE; s += CSG_String::Format("%d %s:%s", asTable()->Get_Field_Count(), _TL("Fields"), Separator);

			for(int i=0; i<asTable()->Get_Field_Count(); i++)
			{
				s += CSG_String::Format("- %d. [%s] %s%s", i + 1, SG_Data_Type_Get_Name(asTable()->Get_Field_Type(i)).c_str(), asTable()->Get_Field_Name(i), Separator);
			}
			break;

		case PARAMETER_TYPE_Parameters:
			SEPARATE; s += CSG_String::Format("%d %s", asParameters()->Get_Count(), _TL("Parameters"));

			if( do_UseInCMD() )
			{
				s += CSG_String::Format(":%s", Separator);

				for(int i=0; i<asParameters()->Get_Count(); i++)
				{
					s += CSG_String::Format("- %d. %s%s", i + 1, asParameters()->Get_Parameter(i)->Get_Description(Flags, Separator).c_str(), Separator);
				}
			}
			break;
		}

		if( !m_Default.is_Empty() )
		{
			SEPARATE; s += CSG_String::Format("%s: %s", _TL("Default"), m_Default.c_str());
		}
	}

	//-----------------------------------------------------
	if( (Flags & PARAMETER_DESCRIPTION_TEXT) != 0 && m_Description.Length() > 0 )
	{
		SEPARATE; s += m_Description;
	}

	//-----------------------------------------------------
	#undef SEPARATE

	return( s );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
int CSG_Parameter::_Set_Value(int                 Value) { return( SG_PARAMETER_DATA_SET_FALSE ); }
int CSG_Parameter::_Set_Value(double              Value) { return( SG_PARAMETER_DATA_SET_FALSE ); }
int CSG_Parameter::_Set_Value(CSG_Grid_Resampling Value) { return( SG_PARAMETER_DATA_SET_FALSE ); }
int CSG_Parameter::_Set_Value(const CSG_String   &Value) { return( SG_PARAMETER_DATA_SET_FALSE ); }
int CSG_Parameter::_Set_Value(void               *Value) { return( SG_PARAMETER_DATA_SET_FALSE ); }

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(int Value)
{
	switch( _Set_Value(Value) )
	{
	case SG_PARAMETER_DATA_SET_FALSE:
		return( false );

	case SG_PARAMETER_DATA_SET_CHANGED:
		has_Changed();
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(double Value)
{
	switch( _Set_Value(Value) )
	{
	case SG_PARAMETER_DATA_SET_FALSE:
		return( false );

	case SG_PARAMETER_DATA_SET_CHANGED:
		has_Changed();
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(CSG_Grid_Resampling Value)
{
	switch( _Set_Value(Value) )
	{
	case SG_PARAMETER_DATA_SET_FALSE:
		return( false );

	case SG_PARAMETER_DATA_SET_CHANGED:
		has_Changed();
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(const char       *Value)	{	return( Set_Value(CSG_String(Value)) );	}
bool CSG_Parameter::Set_Value(const wchar_t    *Value)	{	return( Set_Value(CSG_String(Value)) );	}
bool CSG_Parameter::Set_Value(const CSG_String &Value)
{
	switch( _Set_Value(Value) )
	{
	case SG_PARAMETER_DATA_SET_FALSE:
		return( false );

	case SG_PARAMETER_DATA_SET_CHANGED:
		has_Changed();
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(void *Value)
{
	switch( _Set_Value(Value) )
	{
	case SG_PARAMETER_DATA_SET_FALSE:
		return( false );

	case SG_PARAMETER_DATA_SET_CHANGED:
		has_Changed();
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Value(CSG_Parameter *Value)
{
	if( Value )
	{
		switch( Value->Get_Type() )
		{
		default:
			break;

		case PARAMETER_TYPE_Data_Type:
		case PARAMETER_TYPE_Choice:
			return( Set_Value(Value->asInt()) );
		}
	}

	return( Assign(Value) );
}

//---------------------------------------------------------
bool CSG_Parameter::Toggle_Value(void)
{
	return( false );
}

//---------------------------------------------------------
bool CSG_Parameter::has_Changed(int Check_Flags)
{
	_Set_String();

	return( m_pParameters && m_pParameters->_On_Parameter_Changed(this, Check_Flags) );
}

//---------------------------------------------------------
void CSG_Parameter::_Set_String(void)
{
	// nop
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameter::Set_Default(int Value)
{
	m_Default.Printf("%d", Value);

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Default(double Value)
{
	m_Default.Printf("%f", Value);

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Set_Default(const CSG_String &Value)
{
	m_Default = Value;

	return( true );
}

//---------------------------------------------------------
const CSG_String & CSG_Parameter::Get_Default(void) const
{
	return( m_Default );
}

//---------------------------------------------------------
bool CSG_Parameter::is_Default(void) const
{
	return( m_Default.Cmp(asString()) == 0 );
}

//---------------------------------------------------------
bool CSG_Parameter::Restore_Default(void)
{
	return( Set_Value(m_Default) );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameter::Check(bool bSilent)
{
	if( Get_Type() == PARAMETER_TYPE_Parameters )
	{
		return( asParameters()->DataObjects_Check(bSilent) );
	}

	//-----------------------------------------------------
	if( Get_Type() == PARAMETER_TYPE_Grid_System )
	{
		if( m_pParameters->Get_Manager() )
		{
			bool bExists = false; CSG_Data_Manager &Manager = *m_pParameters->Get_Manager();

			for(size_t i=0; !bExists && i<Manager.Grid ().Count(); i++)
			{
				bExists = Manager.Grid (i).Get_System() == *asGrid_System();
			}

			for(size_t i=0; !bExists && i<Manager.Grids().Count(); i++)
			{
				bExists = Manager.Grids(i).Get_System() == *asGrid_System();
			}

			if( bExists == false )
			{
				Set_Value((void *)NULL);
			}
		}

		return( true );	// ( false );
	}

	//-----------------------------------------------------
	if( is_DataObject() )
	{
		if( is_Input() || (is_Output() && asDataObject() != DATAOBJECT_CREATE) )
		{
			if( m_pParameters->Get_Manager() && !m_pParameters->Get_Manager()->Exists(asDataObject()) )
			{
				Set_Value(DATAOBJECT_NOTSET);
			}
		}

		return( is_Optional() || !is_Enabled() || asDataObject() );
	}

	//-----------------------------------------------------
	else if( is_DataObject_List() )
	{
		for(int j=asList()->Get_Item_Count()-1; j>=0; j--)
		{
			CSG_Data_Object *pDataObject = asList()->Get_Item(j);

			if( !pDataObject || (m_pParameters->Get_Manager() && !m_pParameters->Get_Manager()->Exists(pDataObject)) )
			{
				asList()->Del_Item(j, false);
			}
		}

		_Set_String();

		asList()->Update_Data();

		return( is_Optional() || !is_Enabled() || is_Output() || asList()->Get_Item_Count() > 0 );
	}

	//-----------------------------------------------------
	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
int                             CSG_Parameter::_asInt            (void) const { return( 0        ); }
double                          CSG_Parameter::_asDouble         (void) const { return( 0.       ); }
void                          * CSG_Parameter::_asPointer        (void) const { return( NULL     ); }
const SG_Char                 * CSG_Parameter::_asString         (void) const { return( m_String ); }

//---------------------------------------------------------
CSG_Colors                    * CSG_Parameter::asColors          (void) const { return( Get_Type() != PARAMETER_TYPE_Colors      ? NULL : (CSG_Colors      *)asPointer() ); }
const SG_Char                 * CSG_Parameter::asFont            (void) const { return( Get_Type() != PARAMETER_TYPE_Font        ? NULL : (const SG_Char   *)asPointer() ); }
CSG_Parameters                * CSG_Parameter::asParameters      (void) const { return( Get_Type() != PARAMETER_TYPE_Parameters  ? NULL : (CSG_Parameters  *)asPointer() ); }
CSG_Grid_System               * CSG_Parameter::asGrid_System     (void) const { return( Get_Type() != PARAMETER_TYPE_Grid_System ? NULL : (CSG_Grid_System *)asPointer() ); }

//---------------------------------------------------------
CSG_Grid_Resampling             CSG_Parameter::asGrid_Resampling (void) const
{
	int Method;

	if( Get_Type() == PARAMETER_TYPE_Choice && asChoice()->Get_Data(Method) )
	{
		switch( Method )
		{
		case (int)CSG_Grid_Resampling::NearestNeighbour: return( CSG_Grid_Resampling::NearestNeighbour );
		case (int)CSG_Grid_Resampling::Bilinear        : return( CSG_Grid_Resampling::Bilinear         );
		case (int)CSG_Grid_Resampling::Bicubic_1       : return( CSG_Grid_Resampling::Bicubic_1        );
		case (int)CSG_Grid_Resampling::Bicubic_2       : return( CSG_Grid_Resampling::Bicubic_2        );
		case (int)CSG_Grid_Resampling::Mean_Nodes      : return( CSG_Grid_Resampling::Mean_Nodes       );
		case (int)CSG_Grid_Resampling::Mean_Cells      : return( CSG_Grid_Resampling::Mean_Cells       );
		case (int)CSG_Grid_Resampling::Minimum         : return( CSG_Grid_Resampling::Minimum          );
		case (int)CSG_Grid_Resampling::Maximum         : return( CSG_Grid_Resampling::Maximum          );
		case (int)CSG_Grid_Resampling::Majority        : return( CSG_Grid_Resampling::Majority         );
		}
	}

	return( CSG_Grid_Resampling::Undefined );
}

//---------------------------------------------------------
CSG_Data_Object               * CSG_Parameter::asDataObject    (void) const { return( !is_DataObject() ? NULL : (CSG_Data_Object *)asPointer() ); }
CSG_Grid                      * CSG_Parameter::asGrid          (void) const { CSG_Data_Object *pObject = asDataObject(); return( !pObject || pObject == DATAOBJECT_CREATE || pObject->Get_ObjectType() != SG_DATAOBJECT_TYPE_Grid       ? NULL : (CSG_Grid       *)pObject ); }
CSG_Grids                     * CSG_Parameter::asGrids         (void) const { CSG_Data_Object *pObject = asDataObject(); return( !pObject || pObject == DATAOBJECT_CREATE || pObject->Get_ObjectType() != SG_DATAOBJECT_TYPE_Grids      ? NULL : (CSG_Grids      *)pObject ); }
CSG_TIN                       * CSG_Parameter::asTIN           (void) const { CSG_Data_Object *pObject = asDataObject(); return( !pObject || pObject == DATAOBJECT_CREATE || pObject->Get_ObjectType() != SG_DATAOBJECT_TYPE_TIN        ? NULL : (CSG_TIN        *)pObject ); }
CSG_PointCloud                * CSG_Parameter::asPointCloud    (void) const { CSG_Data_Object *pObject = asDataObject(); return( !pObject || pObject == DATAOBJECT_CREATE || pObject->Get_ObjectType() != SG_DATAOBJECT_TYPE_PointCloud ? NULL : (CSG_PointCloud *)pObject ); }

//---------------------------------------------------------
CSG_Shapes                    * CSG_Parameter::asShapes        (void) const
{
	CSG_Data_Object	*pObject	= asDataObject();

	if( pObject && pObject != DATAOBJECT_CREATE
	&& (pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_Shapes
	 || pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_PointCloud) )
	{
		return( (CSG_Shapes *)pObject );
	}

	return( NULL );
}

//---------------------------------------------------------
CSG_Table                     * CSG_Parameter::asTable         (void) const
{
	switch( Get_Type() )
	{
	default:	{
		CSG_Data_Object	*pObject	= asDataObject();

		if( pObject && pObject != DATAOBJECT_CREATE
		&& (pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_Table
		 || pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_Shapes
		 || pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_TIN
		 || pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_PointCloud) )
		{
			return( (CSG_Table *)pObject );
		}
	}	break;

	case PARAMETER_TYPE_Grids     :
		return( asGrids() ? asGrids()->Get_Attributes_Ptr() : NULL );

	case PARAMETER_TYPE_FixedTable:
		return( (CSG_Table *)asPointer() );
	}

	return( NULL );
}

//---------------------------------------------------------
CSG_Parameter_Value           * CSG_Parameter::asValue         (void) const
{
	if( Get_Type() == PARAMETER_TYPE_Double
	||  Get_Type() == PARAMETER_TYPE_Degree
	||  Get_Type() == PARAMETER_TYPE_Int
	||  Get_Type() == PARAMETER_TYPE_Color
	||  Get_Type() == PARAMETER_TYPE_Table_Field )
	{
		return( (CSG_Parameter_Value *)this );
	}

	return( NULL );
}

CSG_Parameter_Date            * CSG_Parameter::asDate          (void) const {	return( Get_Type() != PARAMETER_TYPE_Date            ? NULL : (CSG_Parameter_Date            *)this );	}
CSG_Parameter_Data_Type       * CSG_Parameter::asDataType      (void) const {	return( Get_Type() != PARAMETER_TYPE_Data_Type       ? NULL : (CSG_Parameter_Data_Type       *)this );	}
CSG_Parameter_Choice          * CSG_Parameter::asChoice        (void) const {	return( Get_Type() != PARAMETER_TYPE_Choice
                                                                                     && Get_Type() != PARAMETER_TYPE_Data_Type       ? NULL : (CSG_Parameter_Choice          *)this );	}
CSG_Parameter_Choices         * CSG_Parameter::asChoices       (void) const {	return( Get_Type() != PARAMETER_TYPE_Choices         ? NULL : (CSG_Parameter_Choices         *)this );	}
CSG_Parameter_Range           * CSG_Parameter::asRange         (void) const {	return( Get_Type() != PARAMETER_TYPE_Range           ? NULL : (CSG_Parameter_Range           *)this );	}
CSG_Parameter_File_Name       * CSG_Parameter::asFilePath      (void) const {	return( Get_Type() != PARAMETER_TYPE_FilePath        ? NULL : (CSG_Parameter_File_Name       *)this );	}
CSG_Parameter_Table_Fields    * CSG_Parameter::asTableFields   (void) const {	return( Get_Type() != PARAMETER_TYPE_Table_Fields    ? NULL : (CSG_Parameter_Table_Fields    *)this );	}

//---------------------------------------------------------
CSG_Parameter_List            * CSG_Parameter::asList          (void) const {	return( !is_DataObject_List()                        ? NULL : (CSG_Parameter_List            *)this );	}
CSG_Parameter_Grid_List       * CSG_Parameter::asGridList      (void) const {	return( Get_Type() != PARAMETER_TYPE_Grid_List       ? NULL : (CSG_Parameter_Grid_List       *)this );	}
CSG_Parameter_Grids_List      * CSG_Parameter::asGridsList     (void) const {	return( Get_Type() != PARAMETER_TYPE_Grids_List      ? NULL : (CSG_Parameter_Grids_List      *)this );	}
CSG_Parameter_Table_List      * CSG_Parameter::asTableList     (void) const {	return( Get_Type() != PARAMETER_TYPE_Table_List      ? NULL : (CSG_Parameter_Table_List      *)this );	}
CSG_Parameter_Shapes_List     * CSG_Parameter::asShapesList    (void) const {	return( Get_Type() != PARAMETER_TYPE_Shapes_List     ? NULL : (CSG_Parameter_Shapes_List     *)this );	}
CSG_Parameter_TIN_List        * CSG_Parameter::asTINList       (void) const {	return( Get_Type() != PARAMETER_TYPE_TIN_List        ? NULL : (CSG_Parameter_TIN_List        *)this );	}
CSG_Parameter_PointCloud_List * CSG_Parameter::asPointCloudList(void) const {	return( Get_Type() != PARAMETER_TYPE_PointCloud_List ? NULL : (CSG_Parameter_PointCloud_List *)this );	}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
void CSG_Parameter::_Add_Child(CSG_Parameter *pChild)
{
	m_Children	= (CSG_Parameter **)SG_Realloc(m_Children, (m_nChildren + 1) * sizeof(CSG_Parameter *));
	m_Children[m_nChildren++]	= pChild;
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameter::Assign(CSG_Parameter *pSource)
{
	if( pSource && Get_Type() == pSource->Get_Type() )
	{
		m_bEnabled = pSource->m_bEnabled;
		m_Default  = pSource->m_Default;

		Set_Collapsed(pSource->is_Collapsed());

		if( _Assign(pSource) )
		{
			_Set_String();

			return( true );
		}
	}

	return( false );
}

bool CSG_Parameter::_Assign(CSG_Parameter *pSource)
{
	return( true );
}

//---------------------------------------------------------
bool CSG_Parameter::Serialize(CSG_MetaData &MetaData, bool bSave)
{
	if( bSave )
	{
		if( is_Information() || Get_Type() == PARAMETER_TYPE_Node || Get_Type() == PARAMETER_TYPE_Undefined )
		{
			return( true );
		}

		CSG_MetaData	&Child	= *MetaData.Add_Child(
			is_Option         () ? "OPTION"    :
			is_DataObject     () ? "DATA"      :
			is_DataObject_List() ? "DATA_LIST" : "PARAMETER"
		);

		Child.Add_Property("type" , Get_Type_Identifier             ());
		Child.Add_Property("id"   , Get_Identifier                  ());
		Child.Add_Property("name" , Get_Name                        ());
		Child.Add_Property("parms", Get_Parameters()->Get_Identifier());

		_Serialize(Child, bSave);

		return( true );
	}
	else if( MetaData.Cmp_Property("type", Get_Type_Identifier())
		&&	 MetaData.Cmp_Property("id"  , Get_Identifier     ()) 
		&&	_Serialize(MetaData, bSave) )
	{
		_Set_String();

		return( true );
	}

	return( false );
}

bool CSG_Parameter::_Serialize(CSG_MetaData &Entry, bool bSave)
{
	Entry.Set_Content("-");

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
//         Coordinate System Reference Picker            //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Parameters_CRSPicker::CSG_Parameters_CRSPicker(void)
{
	// nop...
}

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::Create(CSG_Parameters &Parameters, const CSG_String &ParentID)
{
	m_pParameters = &Parameters;

	Parameters.Add_String(ParentID, "CRS_STRING", _TL("Coordinate System Definition"),
		_TL("Supported formats comprise PROJ and WKT strings, object codes (e.g. \"EPSG:4326\")."), ""
	)->Set_UseInGUI(false);

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::Activate_GUI(bool bReset)
{
	if( !m_pParameters || !m_pParameters->has_GUI() || m_pCRS )
	{
		return( false );
	}

	m_pCRS = SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 15, true); // CCRS_Picker

	if( !m_pCRS )
	{
		return( false );
	}

	m_pCRS->Set_Parameter("CRS_STRING", (*m_pParameters)["CRS_STRING"].asString());

	m_pParameters->Add_Parameters((*m_pParameters)("CRS_STRING")->Get_Parent(),
		"CRS_PICKER", _TL("Coordinate Reference System"), _TL("")
	)->asParameters()->Create(*m_pCRS->Get_Parameters());

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::Deactivate_GUI(void)
{
	if( m_pCRS )
	{
		m_pParameters->Del_Parameter("CRS_PICKER");

		SG_Get_Tool_Library_Manager().Delete_Tool(m_pCRS);

		m_pCRS = NULL;

		return( true );
	}

	return( false );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	if( pParameter->Cmp_Identifier("CRS_PICKER") )
	{
		pParameters->Set_Parameter("CRS_STRING", (*pParameter->asParameters())("CRS_WKT")->asString());
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameters_CRSPicker::Get_CRS(CSG_Projection &Projection, bool bMessage) const
{
	if( Projection.Create((*m_pParameters)["CRS_STRING"].asString()) )
	{
		if( bMessage )
		{
			SG_UI_Msg_Add_Execution(CSG_String::Format("\n%s: %s\n", _TL("CRS"), Projection.Get_PROJ().c_str()), false);
		}

		return( true );
	}

	if( bMessage )
	{
		SG_UI_Msg_Add_Execution(CSG_String::Format("\n%s: %s\n", _TL("Warning"), _TL("undefined coordinate reference system")), false);
	}

	return( false );
}


///////////////////////////////////////////////////////////
//                                                       //
//                Grid Target Selector                   //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Parameters_Grid_Target::CSG_Parameters_Grid_Target(void)
{
	m_pParameters = NULL;
}

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::Create(CSG_Parameters *pParameters, bool bAddDefaultGrid, CSG_Parameter *pParent, const CSG_String &Prefix)
{
	return( Create(pParameters, bAddDefaultGrid, pParent ? pParent->Get_Identifier() : SG_T(""), Prefix) );
}

bool CSG_Parameters_Grid_Target::Create(CSG_Parameters *pParameters, bool bAddDefaultGrid, const CSG_String &ParentID, const CSG_String &Prefix)
{
	if( pParameters == NULL )
	{
		return( false );
	}

	m_pParameters = pParameters;
	m_Prefix      = Prefix;

	//-----------------------------------------------------
	CSG_String TargetID(m_Prefix + "DEFINITION");

	m_pParameters->Add_Choice(
		ParentID, TargetID, _TL("Target Grid System"),
		_TL(""),
		CSG_String::Format("%s|%s",
			_TL("user defined"),
			_TL("grid or grid system")
		), 0
	);

	//-----------------------------------------------------
	m_pParameters->Add_Double(TargetID, m_Prefix + "USER_SIZE", _TL("Cellsize"), _TL(""), 1., 0., true);
	m_pParameters->Add_Double(TargetID, m_Prefix + "USER_XMIN", _TL("West"    ), _TL(""),   0.);
	m_pParameters->Add_Double(TargetID, m_Prefix + "USER_XMAX", _TL("East"    ), _TL(""), 100.);
	m_pParameters->Add_Double(TargetID, m_Prefix + "USER_YMIN", _TL("South"   ), _TL(""),   0.);
	m_pParameters->Add_Double(TargetID, m_Prefix + "USER_YMAX", _TL("North"   ), _TL(""), 100.);
	m_pParameters->Add_Int   (TargetID, m_Prefix + "USER_COLS", _TL("Columns" ), _TL("Number of cells in East-West direction."  ), 101, 1, true);
	m_pParameters->Add_Int   (TargetID, m_Prefix + "USER_ROWS", _TL("Rows"    ), _TL("Number of cells in North-South direction."), 101, 1, true);
	m_pParameters->Add_Bool  (TargetID, m_Prefix + "USER_FLAT", _TL("Rounding"), _TL("Round bounding coordinates to multiples of cell size. Ignored if cell size has decimal places."), true);
	m_pParameters->Add_Choice(TargetID, m_Prefix + "USER_FITS", _TL("Fit"     ), _TL(""),
		CSG_String::Format("%s|%s",
			_TL("nodes"),
			_TL("cells")
		), 0
	);

	//-----------------------------------------------------
	m_pParameters->Add_Grid_System(TargetID, m_Prefix + "SYSTEM", _TL("Grid System"), _TL(""));

	m_pParameters->Add_Grid(m_Prefix + "SYSTEM", m_Prefix + "TEMPLATE", _TL("Target System"),
		_TL("use this grid's system for output grids"), PARAMETER_INPUT_OPTIONAL, false
	)->Set_UseInGUI(false);

	//-----------------------------------------------------
	if( bAddDefaultGrid )
	{
		Add_Grid(m_Prefix + "OUT_GRID", _TL("Target Grid"), false);
	}

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	return( pParameter && pParameters && m_pParameters && m_pParameters->Cmp_Identifier(pParameters->Get_Identifier())
		&& On_Parameter_Changed(pParameters, pParameter, m_Prefix)
	);
}

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter, const CSG_String Prefix)
{
	if( !pParameters || !pParameter )
	{
		return( false );
	}

	if( !pParameter->Cmp_Identifier(Prefix + "USER_SIZE")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_XMIN")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_XMAX")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_YMIN")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_YMAX")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_ROWS")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_COLS")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_FLAT")
	&&  !pParameter->Cmp_Identifier(Prefix + "USER_FITS") )
	{
		return( true );
	}

	CSG_Parameter *pSize = (*pParameters)(Prefix + "USER_SIZE");
	CSG_Parameter *pXMin = (*pParameters)(Prefix + "USER_XMIN");
	CSG_Parameter *pXMax = (*pParameters)(Prefix + "USER_XMAX");
	CSG_Parameter *pYMin = (*pParameters)(Prefix + "USER_YMIN");
	CSG_Parameter *pYMax = (*pParameters)(Prefix + "USER_YMAX");
	CSG_Parameter *pRows = (*pParameters)(Prefix + "USER_ROWS");
	CSG_Parameter *pCols = (*pParameters)(Prefix + "USER_COLS");
	CSG_Parameter *pFlat = (*pParameters)(Prefix + "USER_FLAT");
	CSG_Parameter *pFits = (*pParameters)(Prefix + "USER_FITS");

	double Size = pSize->asDouble();

	double xMin = pXMin->asDouble(), xMax = pXMax->asDouble();
	double yMin = pYMin->asDouble(), yMax = pYMax->asDouble();

	//-----------------------------------------------------
	bool bChanged = true;

	if(      pParameter->Cmp_Identifier(pFits->Get_Identifier()) )
	{
		if( pFits->asInt() == 0 ) // fit cells >> fit nodes
		{
			xMin += 0.5 * Size; xMax -= 0.5 * Size;
			yMin += 0.5 * Size; yMax -= 0.5 * Size;
		}
	}
	else
	{
		if( pFits->asInt() == 1 ) // fit cells >> fit nodes
		{
			xMin += 0.5 * Size; xMax -= 0.5 * Size;
			yMin += 0.5 * Size; yMax -= 0.5 * Size;
		}

		if( pParameter->Cmp_Identifier(pSize->Get_Identifier()) && Size > 0. )
		{
			xMax  = xMin + Size * (int)(0.5 + (xMax - xMin) / Size);
			yMax  = yMin + Size * (int)(0.5 + (yMax - yMin) / Size);
		}
		else if( pParameter->Cmp_Identifier(pCols->Get_Identifier()) && pCols->asInt() > 0 )
		{
			xMax  = xMin + Size * (pCols->asInt() - 1);
		}
		else if( pParameter->Cmp_Identifier(pXMin->Get_Identifier()) )
		{
			xMax  = xMin + Size * (xMin > xMax ? (pCols->asInt() - 1) : (int)(0.5 + (xMax - xMin) / Size));
		}
		else if( pParameter->Cmp_Identifier(pXMax->Get_Identifier()) )
		{
			xMin  = xMax - Size * (xMin > xMax ? (pCols->asInt() - 1) : (int)(0.5 + (xMax - xMin) / Size));
		}
		else if( pParameter->Cmp_Identifier(pRows->Get_Identifier()) && pRows->asInt() > 0 )
		{
			yMax  = yMin + Size * (pRows->asInt() - 1);
		}
		else if( pParameter->Cmp_Identifier(pYMin->Get_Identifier()) )
		{
			yMax  = yMin + Size * (yMin > yMax ? (pRows->asInt() - 1) : (int)(0.5 + (yMax - yMin) / Size));
		}
		else if( pParameter->Cmp_Identifier(pYMax->Get_Identifier()) )
		{
			yMin  = yMax - Size * (yMin > yMax ? (pRows->asInt() - 1) : (int)(0.5 + (yMax - yMin) / Size));
		}
		else if( pParameter->Cmp_Identifier(pFlat->Get_Identifier()) )
		{
			bChanged = pFlat->asBool();
		}
		else
		{
			bChanged = false; // none of the relevant parameters did change so far
		}
	}

	//-----------------------------------------------------
	if( bChanged )
	{
		if( (pParameter->Cmp_Identifier(pSize->Get_Identifier()) || pParameter->Cmp_Identifier(pFlat->Get_Identifier()))
		&&  pFlat->asBool() && !M_HAS_DECIMALS(Size) ) // rounding of bounds
		{
			xMin = floor(xMin / Size) * Size; xMax = ceil(xMax / Size) * Size;
			yMin = floor(yMin / Size) * Size; yMax = ceil(yMax / Size) * Size;
		}

		pCols->Set_Value(1 + (int)((xMax - xMin) / Size));
		pRows->Set_Value(1 + (int)((yMax - yMin) / Size));

		if( pFits->asInt() == 1 )
		{
			xMin -= 0.5 * Size; xMax += 0.5 * Size;
			yMin -= 0.5 * Size; yMax += 0.5 * Size;
		}

		pXMin->Set_Value(xMin);
		pXMax->Set_Value(xMax);
		pYMin->Set_Value(yMin);
		pYMax->Set_Value(yMax);

		return( true );
	}

	//-----------------------------------------------------
	CSG_Parameter *pZSize = (*pParameters)(Prefix + "USER_ZSIZE");
	CSG_Parameter *pZMin  = (*pParameters)(Prefix + "USER_ZMIN" );
	CSG_Parameter *pZMax  = (*pParameters)(Prefix + "USER_ZMAX" );
	CSG_Parameter *pZNum  = (*pParameters)(Prefix + "USER_ZNUM" );

	if( pZSize && pZMin && pZMax && pZNum )
	{
		double zSize = pZSize->asDouble(), zMin = pZMin ->asDouble(), zMax = pZMax ->asDouble();

		bChanged = true;

		if     ( pParameter->Cmp_Identifier(pZSize->Get_Identifier()) && zSize > 0. )
		{
			zMax = zMin + zSize * (int)(0.5 + (zMax - zMin) / zSize);
		}
		else if( pParameter->Cmp_Identifier(pZNum->Get_Identifier()) && pZNum->asInt() > 0 )
		{
			zMax = zMin + zSize * pZNum->asInt();
		}
		else if( pParameter->Cmp_Identifier(pZMin->Get_Identifier()) )
		{
			zMax = zMin + zSize * (zMin > zMax ? pZNum->asInt() : (int)(0.5 + (zMax - zMin) / zSize));
		}
		else if( pParameter->Cmp_Identifier(pZMax->Get_Identifier()) )
		{
			zMin = zMax - zSize * (zMin > zMax ? pZNum->asInt() : (int)(0.5 + (zMax - zMin) / zSize));
		}
		else
		{
			bChanged = false;
		}

		if( bChanged )
		{
			pZNum->Set_Value(1 + (int)((zMax - zMin) / zSize));

			pZMin->Set_Value(zMin);
			pZMax->Set_Value(zMax);
		}
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	return( pParameter && pParameters && m_pParameters && m_pParameters->Get_Identifier().Cmp(pParameters->Get_Identifier()) == 0
		&& On_Parameters_Enable(pParameters, pParameter, m_Prefix)
	);
}

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter, const CSG_String Prefix)
{
	if( !pParameter || !pParameters || !(pParameter = (*pParameters)(Prefix + "DEFINITION")) )
	{
		return( false );
	}

	pParameters->Set_Enabled(Prefix + "SYSTEM"   , pParameter->asInt() == 1);
	pParameters->Set_Enabled(Prefix + "TEMPLATE" , pParameter->asInt() == 1);

	pParameters->Set_Enabled(Prefix + "USER_SIZE", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_XMIN", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_XMAX", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_YMIN", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_YMAX", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_ROWS", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_COLS", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_FLAT", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_FITS", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_OPTS", pParameter->asInt() == 0);
	pParameters->Set_Enabled(Prefix + "USER_Z"   , pParameter->asInt() == 0);

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
/**
  * Initializes the grid system from extent and number of rows.
  * Extent calculation is done for grid nodes and will automatically
  * become adjusted to match the grid cells if necessary. If Rounding is
  * greater than zero it specifies the number of significant figures to which
  * the cell size is rounded and also adjusts the extent coordinates
  * to be a multiple of cell size.
*/
bool CSG_Parameters_Grid_Target::Set_User_Defined(CSG_Parameters *pParameters, const TSG_Rect &Extent, int Rows, int Rounding)
{
	if( !m_pParameters->Get_Tool() || !m_pParameters->Get_Tool()->has_GUI() ) // no cancel button, so set parameters directly
	{
		pParameters = m_pParameters;
	}

	if( !m_pParameters || !pParameters || m_pParameters->Get_Identifier().Cmp(pParameters->Get_Identifier()) )
	{
		return( false );
	}

	if( Rows < 1 && (Rows = (*m_pParameters)(m_Prefix + "USER_ROWS")->asInt()) < 1 )
	{
		Rows = 100;
	}

	//-----------------------------------------------------
	CSG_Rect r(Extent);

	if( r.Get_XRange() == 0. && r.Get_YRange() == 0. )
	{
		r.Inflate(0.5 * Rows, false); // assume cellsize = 1.
	}
	else if( r.Get_XRange() == 0. )
	{
		double d = 0.5 * r.Get_YRange() / Rows; r.xMin -= d; r.xMax += d;	// inflate by half cellsize
	}
	else if( r.Get_YRange() == 0. )
	{
		double d = 0.5 * r.Get_XRange() / Rows; r.yMin -= d; r.yMax += d;	// inflate by half cellsize
	}

	//-----------------------------------------------------
	double Size = r.Get_YRange() / (Rows - 1);

	int    Cols = 1 + (int)(0.5 + r.Get_XRange() / Size);

	if( Rounding > 0 ) // rounding of cell size!
	{
		Size = SG_Get_Rounded_To_SignificantFigures(Size, Rounding);

		r.xMin = r.Get_XCenter() - Size * Cols / 2.;
		r.yMin = r.Get_YCenter() - Size * Rows / 2.;
		r.yMax = r.Get_YMin   () + Size * (Rows - 1);
	}

	r.xMax = r.Get_XMin() + Size * (Cols - 1);

	//-----------------------------------------------------
	if( (*pParameters)(m_Prefix + "USER_FLAT")->asBool() && !M_HAS_DECIMALS(Size) ) // rounding of bounds
	{
		r.xMin = floor(r.xMin / Size) * Size; r.xMax = ceil(r.xMax / Size) * Size;
		r.yMin = floor(r.yMin / Size) * Size; r.yMax = ceil(r.yMax / Size) * Size;
	}

	//-----------------------------------------------------
	if( (*pParameters)(m_Prefix + "USER_FITS")->asInt() == 1 ) // fit to cells
	{
		r.Inflate(0.5 * Size, false);
	}

	bool bCallback = pParameters->Set_Callback(false);

	pParameters->Set_Parameter(m_Prefix + "USER_SIZE", Size        );
	pParameters->Set_Parameter(m_Prefix + "USER_XMIN", r.Get_XMin());
	pParameters->Set_Parameter(m_Prefix + "USER_XMAX", r.Get_XMax());
	pParameters->Set_Parameter(m_Prefix + "USER_YMIN", r.Get_YMin());
	pParameters->Set_Parameter(m_Prefix + "USER_YMAX", r.Get_YMax());
	pParameters->Set_Parameter(m_Prefix + "USER_COLS", Cols        );
	pParameters->Set_Parameter(m_Prefix + "USER_ROWS", Rows        );

	pParameters->Set_Callback(bCallback);

	return( true );
}

//---------------------------------------------------------
/**
  * Initializes the grid system from 'pPoints' extent and fits number of columns/rows to the average point density.
  * Number of columns/rows can be increased if 'Scale' is greater than 1.
*/
bool CSG_Parameters_Grid_Target::Set_User_Defined(CSG_Parameters *pParameters, CSG_Shapes *pPoints, int Scale, int Rounding)
{
	if( !pPoints || pPoints->Get_Count() <= 0 || pPoints->Get_Extent().Get_Area() <= 0. )
	{
		return( false );
	}

	CSG_Rect r(pPoints->Get_Extent());

	double Size = sqrt(r.Get_Area() / pPoints->Get_Count()) / (Scale > 1 ? Scale : 1);	// edge length of a square given as average area per point (cell size)

	if( Size >= 1. && Rounding > 0 )
	{
		Size   = SG_Get_Rounded_To_SignificantFigures(Size, Rounding);

		r.xMin = Size * floor(r.xMin / Size);
		r.xMax = Size * ceil (r.xMax / Size);
		r.yMin = Size * floor(r.yMin / Size);
		r.yMax = Size * ceil (r.yMax / Size);
	}

	int Rows = 1 + (int)(0.5 + r.Get_YRange() / Size);

	return( Set_User_Defined(pParameters, r, Rows, 0) );
}

//---------------------------------------------------------
/**
  * Initializes the grid system from 'System', if it represents a valid grid system.
*/
bool CSG_Parameters_Grid_Target::Set_User_Defined(CSG_Parameters *pParameters, const CSG_Grid_System &System)
{
	return( System.is_Valid() && Set_User_Defined(pParameters, System.Get_Extent(), System.Get_NY(), 0) );
}

//---------------------------------------------------------
/**
  * Initializes the grid system from lower left cell center coordinate, cell size and number of columns and rows (nx, ny).
*/
bool CSG_Parameters_Grid_Target::Set_User_Defined(CSG_Parameters *pParameters, double xMin, double yMin, double Cellsize, int nx, int ny)
{
	return( Set_User_Defined(pParameters, CSG_Grid_System(Cellsize, xMin, yMin, nx, ny)) );
}

//---------------------------------------------------------
/**
* Initializes the grid collection's z level arrangement.
*/
bool CSG_Parameters_Grid_Target::Set_User_Defined_ZLevels(CSG_Parameters *pParameters, double zMin, double zMax, int nLevels, int Rounding)
{
	if( !m_pParameters->Get_Tool()->has_GUI() )	// no cancel button, so set parameters directly
	{
		pParameters	= m_pParameters;
	}

	if( !m_pParameters || !pParameters || m_pParameters->Get_Identifier().Cmp(pParameters->Get_Identifier()) )
	{
		return( false );
	}

	if( nLevels < 1 )
	{
		nLevels	= 100;
	}

	//-----------------------------------------------------
	if( zMin > zMax )
	{
		double z = zMin; zMin = zMax; zMax = z;
	}

	if( zMax - zMin <= 0. )
	{
		zMin -= 0.5 * nLevels;
		zMax += 0.5 * nLevels;	// assume cellsize = 1.
	}

	//-----------------------------------------------------
	double Size = (zMax - zMin) / (nLevels - 1.);

	if( Rounding > 0 )
	{
		Size = SG_Get_Rounded_To_SignificantFigures(Size, Rounding);

		zMin = Size * floor(zMin / Size);
		zMax = Size * ceil (zMax / Size);
	}

	//-----------------------------------------------------
	if( (*pParameters)(m_Prefix + "USER_FITS")->asInt() == 1 )
	{
		zMin -= 0.5 * Size;
		zMax += 0.5 * Size;
	}

	bool bCallback = pParameters->Set_Callback(false);

	pParameters->Set_Parameter(m_Prefix + "USER_ZSIZE", Size   );
	pParameters->Set_Parameter(m_Prefix + "USER_ZMIN" , zMin   );
	pParameters->Set_Parameter(m_Prefix + "USER_ZMAX" , zMax   );
	pParameters->Set_Parameter(m_Prefix + "USER_ZNUM" , nLevels);

	pParameters->Set_Callback(bCallback);

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::Add_Grid(const CSG_String &Identifier, const CSG_String &Name, bool bOptional)
{
	if( !m_pParameters || Identifier.Length() == 0 || (*m_pParameters)(Identifier) != NULL )
	{
		return( false );
	}

	CSG_Parameter *pTarget = (*m_pParameters)(m_Prefix + "DEFINITION");
	CSG_Parameter *pSystem = NULL;

	for(int i=0; i<pTarget->Get_Children_Count() && !pSystem; i++)
	{
		if( pTarget->Get_Child(i)->Get_Type() == PARAMETER_TYPE_Grid_System )
		{
			pSystem = pTarget->Get_Child(i);
		}
	}

	m_pParameters->Add_Grid(pSystem ? pSystem->Get_Identifier() : SG_T(""), Identifier, Name, _TL(""), bOptional ? PARAMETER_OUTPUT_OPTIONAL : PARAMETER_OUTPUT, false);

	if( bOptional && m_pParameters->Get_Tool()->has_GUI() )
	{
		CSG_Parameter *pNode = (*m_pParameters)(m_Prefix + "USER_OPTS");

		if( !pNode )
		{
			pNode = m_pParameters->Add_Node(pTarget->Get_Identifier(), m_Prefix + "USER_OPTS", _TL("Optional Target Grids"), _TL(""));
		}

		m_pParameters->Add_Bool(pNode->Get_Identifier(), Identifier + "_CREATE", Name, _TL(""), false);
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Parameters_Grid_Target::Add_Grids(const CSG_String &Identifier, const CSG_String &Name, bool bOptional, bool bZLevels)
{
	if( !m_pParameters || Identifier.Length() == 0 || (*m_pParameters)(Identifier) != NULL )
	{
		return( false );
	}

	CSG_Parameter *pTarget = (*m_pParameters)(m_Prefix + "DEFINITION");
	CSG_Parameter *pSystem = NULL;

	for(int i=0; i<pTarget->Get_Children_Count() && !pSystem; i++)
	{
		if( pTarget->Get_Child(i)->Get_Type() == PARAMETER_TYPE_Grid_System )
		{
			pSystem = pTarget->Get_Child(i);
		}
	}

	m_pParameters->Add_Grids(pSystem ? pSystem->Get_Identifier() : SG_T(""), Identifier, Name, _TL(""), bOptional ? PARAMETER_OUTPUT_OPTIONAL : PARAMETER_OUTPUT, false);

	if( bOptional && m_pParameters->Get_Tool()->has_GUI() )
	{
		CSG_Parameter *pNode = (*m_pParameters)(m_Prefix + "USER_OPTS");

		if( !pNode )
		{
			pNode = m_pParameters->Add_Node(pTarget->Get_Identifier(), m_Prefix + "USER_OPTS", _TL("Optional Target Grids"), _TL(""));
		}

		m_pParameters->Add_Bool(pNode->Get_Identifier(), Identifier + "_CREATE", Name, _TL(""), false);
	}

	if( bZLevels )
	{
		pTarget = m_pParameters->Add_Node(pTarget, "USER_Z", _TL("Z Levels"), _TL(""));

		m_pParameters->Add_Double(pTarget, m_Prefix + "USER_ZSIZE", _TL("Cellsize"), _TL(""), 1., 0., true);
		m_pParameters->Add_Double(pTarget, m_Prefix + "USER_ZMIN" , _TL("Bottom"  ), _TL(""),   0.);
		m_pParameters->Add_Double(pTarget, m_Prefix + "USER_ZMAX" , _TL("Top"     ), _TL(""), 100.);
		m_pParameters->Add_Int   (pTarget, m_Prefix + "USER_ZNUM" , _TL("Levels"  ), _TL(""), 101, 1, true);
	}

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Grid_System CSG_Parameters_Grid_Target::Get_System(void) const
{
	return( Get_System(m_pParameters) );
}

//---------------------------------------------------------
CSG_Grid_System CSG_Parameters_Grid_Target::Get_System(CSG_Parameters *pParameters) const
{
	CSG_Grid_System System;

	if( pParameters && (*pParameters)(m_Prefix + "DEFINITION") )
	{
		if( (*pParameters)(m_Prefix + "DEFINITION")->asInt() == 0 )	// user defined
		{
			if( (*pParameters)(m_Prefix + "USER_SIZE")
			&&  (*pParameters)(m_Prefix + "USER_XMIN")
			&&  (*pParameters)(m_Prefix + "USER_YMIN")
			&&  (*pParameters)(m_Prefix + "USER_XMAX")
			&&  (*pParameters)(m_Prefix + "USER_YMAX")
			&&  (*pParameters)(m_Prefix + "USER_FITS") )
			{
				double Size = (*pParameters)(m_Prefix + "USER_SIZE")->asDouble();

				CSG_Rect r(
					(*pParameters)(m_Prefix + "USER_XMIN")->asDouble(),
					(*pParameters)(m_Prefix + "USER_YMIN")->asDouble(),
					(*pParameters)(m_Prefix + "USER_XMAX")->asDouble(),
					(*pParameters)(m_Prefix + "USER_YMAX")->asDouble()
				);

				if( (*pParameters)(m_Prefix + "USER_FITS")->asInt() == 1 )
				{
					r.Deflate(0.5 * Size, false);
				}

				System.Assign(Size, r);
			}
		}
		else if( (*pParameters)(m_Prefix + "SYSTEM") )
		{
			CSG_Parameter *pParameter = (*pParameters)(m_Prefix + "SYSTEM");

			if( pParameter->asGrid_System() )
			{
				System.Assign(*pParameter->asGrid_System());
			}
		}
	}

	return( System );
}

//---------------------------------------------------------
CSG_Grid * CSG_Parameters_Grid_Target::Get_Grid(const CSG_String &Identifier, TSG_Data_Type Type)
{
	if( !m_pParameters )
	{
		return( NULL );
	}

	CSG_Parameter *pParameter = (*m_pParameters)(Identifier);

	if( !pParameter || pParameter->Get_Type() != PARAMETER_TYPE_Grid )
	{
		return( NULL );
	}

	CSG_Grid_System System(Get_System());

	if( !System.is_Valid() )
	{
		return( NULL );
	}

	CSG_Parameter *pSystem = pParameter->Get_Parent();

	if( pSystem->asGrid_System() && !pSystem->asGrid_System()->is_Equal(System) )
	{
		pSystem->asGrid_System()->Create(System);
	}

	CSG_Grid *pGrid = NULL;

	if( (*m_pParameters)(m_Prefix + "DEFINITION")->asInt() == 0 && m_pParameters->Get_Tool()->has_GUI() )
	{
		if( (*m_pParameters)(Identifier + "_CREATE") == NULL
		||  (*m_pParameters)(Identifier + "_CREATE")->asBool() )
		{
			pGrid = SG_Create_Grid(System, Type);
		}
	}
	else
	{
		pGrid = pParameter->asGrid();

		if( pParameter->asDataObject() == DATAOBJECT_CREATE || (!pGrid && !pParameter->is_Optional()) )
		{
			pGrid = SG_Create_Grid(System, Type);
		}
		else if( pGrid && (pGrid->Get_Type() != Type || !pGrid->Get_System().is_Equal(System)) )
		{
			pGrid->Create(System, Type);
		}
	}

	if( pGrid )
	{
		if( pGrid != pParameter->asGrid() )
		{
			pParameter->Set_Value(pGrid);
		}

		if( m_pParameters->Get_Manager() )
		{
			m_pParameters->Get_Manager()->Add(pGrid);

			if( m_pParameters->Get_Manager() == &SG_Get_Data_Manager() ) // prevent that local data manager send their data objects to gui
			{
				SG_UI_DataObject_Add(pGrid, SG_UI_DATAOBJECT_UPDATE);
			}
		}
	}

	return( pGrid );
}


///////////////////////////////////////////////////////////
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Grid * CSG_Parameters_Grid_Target::Get_Grid(TSG_Data_Type Type)
{
	return( Get_Grid(m_Prefix + "OUT_GRID", Type) );
}

//---------------------------------------------------------
CSG_Grids * CSG_Parameters_Grid_Target::Get_Grids(const CSG_String &Identifier, TSG_Data_Type Type)
{
	if( !m_pParameters )
	{
		return( NULL );
	}

	CSG_Parameter *pParameter = (*m_pParameters)(Identifier);

	if( !pParameter || pParameter->Get_Type() != PARAMETER_TYPE_Grids )
	{
		return( NULL );
	}

	CSG_Grid_System System(Get_System());

	if( !System.is_Valid() )
	{
		return( NULL );
	}

	CSG_Parameter *pSystem = pParameter->Get_Parent();

	if( pSystem->asGrid_System() && !pSystem->asGrid_System()->is_Equal(System) )
	{
		pSystem->asGrid_System()->Create(System);
	}

	CSG_Grids *pGrids = NULL;

	if( (*m_pParameters)(m_Prefix + "DEFINITION")->asInt() == 0 && m_pParameters->Get_Tool()->has_GUI() )
	{
		if( (*m_pParameters)(Identifier + "_CREATE") == NULL
		||  (*m_pParameters)(Identifier + "_CREATE")->asBool() )
		{
			pGrids = SG_Create_Grids(System, 0, 0., Type);
		}
	}
	else
	{
		pGrids = pParameter->asGrids();

		if( pParameter->asPointer() == DATAOBJECT_CREATE || (!pGrids && !pParameter->is_Optional()) )
		{
			pGrids = SG_Create_Grids(System, 0, 0., Type);
		}
		else if( pGrids && (pGrids->Get_Type() != Type || !pGrids->Get_System().is_Equal(System)) )
		{
			pGrids->Create(System, 0, 0., Type);
		}
	}

	if( pGrids && pGrids != pParameter->asGrids() )
	{
		pParameter->Set_Value(pGrids);

		if( m_pParameters->Get_Manager() )
		{
			m_pParameters->Get_Manager()->Add(pGrids);

			if( m_pParameters->Get_Manager() == &SG_Get_Data_Manager() ) // prevent that local data manager send their data objects to gui
			{
				SG_UI_DataObject_Add(pGrids, SG_UI_DATAOBJECT_UPDATE);
			}
		}
	}

	//-----------------------------------------------------
	if( pGrids
	&&  (*m_pParameters)(m_Prefix + "USER_ZSIZE")
	&&  (*m_pParameters)(m_Prefix + "USER_ZMIN" )
	&&  (*m_pParameters)(m_Prefix + "USER_ZNUM" ) )
	{
		int    nz = (*m_pParameters)(m_Prefix + "USER_ZNUM" )->asInt   ();
		double  z = (*m_pParameters)(m_Prefix + "USER_ZMIN" )->asDouble();
		double dz = (*m_pParameters)(m_Prefix + "USER_ZSIZE")->asDouble();

		pGrids->Del_Grids();

		for(int iz=0; iz<nz; iz++, z+=dz)
		{
			pGrids->Add_Grid(z);
		}
	}

	return( pGrids );
}

//---------------------------------------------------------
CSG_Grids * CSG_Parameters_Grid_Target::Get_Grids(TSG_Data_Type Type)
{
	return( Get_Grids(m_Prefix + "OUT_GRIDS", Type) );
}


///////////////////////////////////////////////////////////
//                                                       //
//                                                       //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
