
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//           Application Programming Interface           //
//                                                       //
//                  Library: SAGA_API                    //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                       tool.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 "saga_api.h"
#include "data_manager.h"
#include "tool.h"
#include "tool_chain.h"

#include <wx/string.h>
#include <wx/cmdline.h>


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

//---------------------------------------------------------
CSG_Tool::CSG_Tool(void)
{
	m_ID      = "-1";
	m_Version = "1.0";

	m_bError_Ignore = false;
	m_bExecutes     = false;

	m_bGUI = SG_UI_Get_Application_Name().Cmp("saga_gui") == 0;
	m_bCMD = SG_UI_Get_Application_Name().Cmp("saga_cmd") == 0;

	Parameters.Create(this, SG_T("Tool"));
	Parameters.Set_Callback_On_Parameter_Changed(&_On_Parameter_Changed);
	Parameters.Set_Tool(this);

	Set_Show_Progress(true);

	m_References.Set_Name(_TL("References"));
	m_References.Add_Field("Authors"  , SG_DATATYPE_String);
	m_References.Add_Field("Date"     , SG_DATATYPE_String);
	m_References.Add_Field("Title"    , SG_DATATYPE_String);
	m_References.Add_Field("Source"   , SG_DATATYPE_String);
	m_References.Add_Field("Link"     , SG_DATATYPE_String);
	m_References.Add_Field("LinkText" , SG_DATATYPE_String);

	m_Editors   .Set_Name(_TL("References"));
	m_Editors   .Add_Field("Editors"  , SG_DATATYPE_String);
	m_Editors   .Add_Field("Comment"  , SG_DATATYPE_String);
}

//---------------------------------------------------------
CSG_Tool::~CSG_Tool(void)
{
	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		delete(Get_Parameters(i));
	}

	Destroy();
}


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

//---------------------------------------------------------
void CSG_Tool::Destroy(void)
{
	m_bError_Ignore	= false;

	History_Supplement.Destroy();

	Del_References();
}


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

//---------------------------------------------------------
const CSG_String & CSG_Tool::Get_Library(void) const
{
	return( m_Library );
}

//---------------------------------------------------------
const CSG_String & CSG_Tool::Get_File_Name(void) const
{
	return( m_File_Name );
}

//---------------------------------------------------------
void CSG_Tool::Set_Name(const CSG_String &String)
{
	Parameters.Set_Name(String);
}

const CSG_String & CSG_Tool::Get_Name(void) const
{
	return( Parameters.Get_Name() );
}

//---------------------------------------------------------
void CSG_Tool::Set_Author(const CSG_String &String)
{
	m_Author = String;
}

const CSG_String & CSG_Tool::Get_Author(void) const
{
	return( m_Author );
}

//---------------------------------------------------------
void CSG_Tool::Set_Version(const CSG_String &String)
{
	m_Version = String;
}

const CSG_String & CSG_Tool::Get_Version(void) const
{
	return( m_Version );
}

//---------------------------------------------------------
void CSG_Tool::Set_Description(const CSG_String &String)
{
	Parameters.Set_Description(String);
}

void CSG_Tool::Add_Description(const CSG_String &String, bool bNewLine)
{
	CSG_String Description(Get_Description());

	if( bNewLine ) { Description += "\n"; }

	Set_Description(Description + String);
}

const CSG_String & CSG_Tool::Get_Description(void) const
{
	return( Parameters.Get_Description().is_Empty() ? Get_Name() : Parameters.Get_Description() );
}

//---------------------------------------------------------
void CSG_Tool::Set_Dynamic_Description(const CSG_String &String)
{
	m_Dynamic_Description = String;
}

void CSG_Tool::Add_Dynamic_Description(const CSG_String &String, bool bNewLine)
{
	if( bNewLine ) { m_Dynamic_Description += "\n"; }

	m_Dynamic_Description += String;
}

const CSG_String & CSG_Tool::Get_Dynamic_Description(void) const
{
	return( m_Dynamic_Description );
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::Get_MenuPath(bool bSolved)
{
	if( !bSolved )
	{
		return( Get_MenuPath() );
	}

	CSG_Strings Menu = SG_String_Tokenize(Get_MenuPath(), ";"); if( !Menu.Get_Count() ) { Menu += ""; }

	for(int i=0; i<Menu.Get_Count(); i++)
	{
		if( Menu[i].Length() > 1 && Menu[i][1] == ':' )
		{
			if( Menu[i][0] == 'A' || Menu[i][0] == 'a' ) // absolute menu path, overwrites library's default menu path
			{
				Menu[i] = Menu[i].AfterFirst(':');

				continue;
			}

			Menu[i] = Menu[i].AfterFirst(':'); // Menu[0] == 'R' || Menu[0] == 'r' // menu path explicitly declared as relative to library's default menu path
		}

		if( !m_Library_Menu.is_Empty() )
		{
			if( Menu[i].is_Empty() )
			{
				Menu[i] = m_Library_Menu;
			}
			else
			{
				Menu[i] = m_Library_Menu + "|" + Menu[i];
			}
		}
	}

	CSG_String Menus; 

	for(int i=0; i<Menu.Get_Count(); i++)
	{
		if( i > 0 )
		{
			Menus += ";";
		}

		Menus += Menu[i];
	}

	return( Menus );
}


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

//---------------------------------------------------------
bool CSG_Tool::has_GUI(void) const
{
	return( m_bGUI );
}

//---------------------------------------------------------
bool CSG_Tool::has_CMD(void) const
{
	return( m_bCMD );
}


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

//---------------------------------------------------------
/**
  * Add a full reference to the list of references.
*/
void CSG_Tool::Add_Reference(const CSG_String &Authors, const CSG_String &Date, const CSG_String &Title, const CSG_String &Source, const CSG_String &Link, const CSG_String &LinkText)
{
	CSG_Table_Record &Reference = *m_References.Add_Record();

	Reference.Set_Value(0, Authors );
	Reference.Set_Value(1, Date    );
	Reference.Set_Value(2, Title   );
	Reference.Set_Value(3, Source  );
	Reference.Set_Value(4, Link    );
	Reference.Set_Value(5, LinkText);

	m_References.Sort(0);
}

//---------------------------------------------------------
/**
  * Add a link to the list of references.
*/
void CSG_Tool::Add_Reference(const CSG_String &Link, const CSG_String &Link_Text)
{
	Add_Reference("", "", "", "", Link, Link_Text);
}

//---------------------------------------------------------
/**
* Clear references list.
*/
bool CSG_Tool::Del_References(void)
{
	return( m_References.Del_Records() );
}

//---------------------------------------------------------
/**
* Get all references as list of nicely formatted strings.
*/
CSG_Strings CSG_Tool::Get_References(bool bHTML) const
{
	CSG_Strings References;

	for(int i=0; i<m_References.Get_Count(); i++)
	{
		CSG_String Reference,
			Authors(m_References[i].asString(0)),
			Date   (m_References[i].asString(1)),
			Title  (m_References[i].asString(2)),
			Source (m_References[i].asString(3)),
			Link   (m_References[i].asString(4)),
			LinkTxt(m_References[i].asString(5));

		if( !Authors.is_Empty() )
		{
			if( Date.is_Empty() ) { Date = "n.d."; }

			Reference += bHTML ? "<b>" + Authors + " (" + Date + "):</b>" : Authors + " (" + Date + "):";
		}
		else if( !Date.is_Empty() ) // date only
		{
			Reference += bHTML ? "<b>(" + Date + "):</b>" : "(" + Date + "):";
		}

		if( !Title.is_Empty() ) // title
		{
			if( Title[Title.Length() - 1] != '.' ) { Title += '.'; }

			if( !Reference.is_Empty() ) { Reference += " "; }

			Reference += bHTML ? "<i>" + Title + "</i>" : Title;
		}

		if( !Source.is_Empty() ) // title
		{
			if( Source[Source.Length() - 1] != '.' ) { Source += '.'; }

			if( !Reference.is_Empty() ) { Reference += " "; }

			Reference += Source;
		}

		if( !Link.is_Empty() )
		{
			if( !Reference.is_Empty() ) { Reference += " "; }

			Reference += bHTML ? "<a href=\"" + Link + "\">" + (LinkTxt.is_Empty() ? Link : LinkTxt) + "</a>" : "[" + LinkTxt + "](" + Link + ")";
		}

		if( !Reference.is_Empty() )
		{
			References += Reference;
		}
	}

	return( References );
}


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

//---------------------------------------------------------
CSG_Table CSG_Tool::Get_Parameters_Table(void) const
{
	CSG_Table Table;

	Table.Add_Field("Id"         , SG_DATATYPE_String);
	Table.Add_Field("Name"       , SG_DATATYPE_String);
	Table.Add_Field("Description", SG_DATATYPE_String);

	_Add_Parameters(Table, &Parameters);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		_Add_Parameters(Table, Get_Parameters(i), Get_Parameters(i)->Get_Identifier() + ".");
	}

	return( Table );
}

//---------------------------------------------------------
bool CSG_Tool::_Add_Parameters(CSG_Table &Table, const CSG_Parameters *pParameters, const CSG_String &IDprefix) const
{
	for(int i=0; i<pParameters->Get_Count(); i++)
	{
		CSG_Parameter &P = *pParameters->Get_Parameter(i);

		if( P.asParameters() )
		{
			_Add_Parameters(Table, P.asParameters(), IDprefix + P.Get_Identifier() + ".");
		}
		else
		{
			CSG_Table_Record &Record = *Table.Add_Record();

			Record.Set_Value(0, IDprefix + P.Get_Identifier ());
			Record.Set_Value(1,            P.Get_Name       ());
			Record.Set_Value(2,            P.Get_Description());
		}
	}

	return( true );
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::m_Description_Source;

//---------------------------------------------------------
bool CSG_Tool::Set_Description_Source(const CSG_String &Source)
{
	m_Description_Source = Source;

	return( true );
}

const CSG_String & CSG_Tool::Get_Description_Source(void)
{
	return( m_Description_Source );
}

//---------------------------------------------------------
bool CSG_Tool::Load_Description(void)
{
	CSG_String Folder(SG_File_Make_Path(Get_Description_Source(), Get_Library()));

	if( SG_Dir_Exists(Folder) )
	{
		CSG_String Name(Get_Library() + "_" + Get_ID()), Description; CSG_File Stream; CSG_Table Table;

		if( Stream.Open(SG_File_Make_Path(Folder, Name, "txt"), SG_FILE_R, true, SG_FILE_ENCODING_UTF8) && Stream.Read(Description) > 0 )
		{
			Description = CSG_Text_Format_Converter::Markdown_to_Html(Description, true);

			Set_Description(CSG_Text_Format_Converter::Html_Absolute_Image_Paths(Description, Folder, true));
		}

		SG_UI_ProgressAndMsg_Lock(true);

		m_References.Del_Records();

		if( Table.Create(SG_File_Make_Path(Folder, Name + "_references", "txt")) && Table.Get_Field_Count() == 6 )
		{
			for(int i=0; i<Table.Get_Field_Count(); i++) { Table.Set_Field_Type(i, SG_DATATYPE_String); }

			for(sLong i=0; i<Table.Get_Count(); i++)
			{
				Add_Reference(Table[i].asString(0), Table[i].asString(1), Table[i].asString(2), Table[i].asString(3), Table[i].asString(4), Table[i].asString(5));
			}
		}

		if( Table.Create(SG_File_Make_Path(Folder, Name + "_parameters", "txt")) && Table.Get_Field_Count() == 3 )
		{
			for(int i=0; i<Table.Get_Field_Count(); i++) { Table.Set_Field_Type(i, SG_DATATYPE_String); }

			for(sLong i=0; i<Table.Get_Count(); i++)
			{
				CSG_Parameter *pParameter = Get_Parameter(Table[i].asString(0));

				if( pParameter )
				{
					pParameter->Set_Name       (Table[i].asString(1));
					pParameter->Set_Description(Table[i].asString(2));
				}
			}
		}

		m_Editors.Del_Records();

		if( Table.Create(SG_File_Make_Path(Folder, Name + "_editors"   , "txt")) && Table.Get_Field_Count() == 2 )
		{
			for(int i=0; i<Table.Get_Field_Count(); i++) { Table.Set_Field_Type(i, SG_DATATYPE_String); }

			for(sLong i=0; i<Table.Get_Count(); i++)
			{
				m_Editors.Add_Record(Table.Get_Record(i));
			}
		}

		SG_UI_ProgressAndMsg_Lock(false);

		return( true );
	}

	return( false );
}

//---------------------------------------------------------
CSG_String CSG_Tool::Get_Description_Editors(bool bHTML)
{
	CSG_String Editors;

	for(sLong i=0; i<m_Editors.Get_Count(); i++)
	{
		if( !m_Editors[i].is_NoData(0) )
		{
			if( !Editors.is_Empty() ) { Editors += ", "; }

			Editors += m_Editors[i].asString(0);

			if( !m_Editors[i].is_NoData(1) )
			{
				Editors += CSG_String::Format(" (%s)", m_Editors[i].asString(1));
			}
		}
	}

	if( !Editors.is_Empty() && bHTML )
	{
		Editors = CSG_String::Format("<hr><small><small>%s: <i>%s</i>.</small></small>", _TL("Description editor(s)"), Editors.c_str());
	}

	return( Editors );
}


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

//---------------------------------------------------------
bool CSG_Tool::Execute(bool bAddHistory)
{
	#define ADD_MESSAGE_EXECUTION(Text, Style) { SG_UI_Msg_Add(Text, true, Style); if( has_GUI() ) { SG_UI_Msg_Add_Execution(Text, true, Style); } }

	//-----------------------------------------------------
	if( m_bExecutes )
	{
		return( false );
	}

	m_bExecutes     = true;

	m_bError_Ignore	= false;

	bool bResult    = false;

	m_Execution_Info.Clear();

	History_Supplement.Destroy();

	//-----------------------------------------------------
	if( Parameters.Get_Manager() == &SG_Get_Data_Manager() )
	{
		ADD_MESSAGE_EXECUTION(CSG_String::Format("[%s] %s...", Get_Name().c_str(), _TL("Execution started")), SG_UI_MSG_STYLE_SUCCESS);
	}

	Update_Parameter_States();

	if( Parameters.DataObjects_Create() == false )
	{
		_Synchronize_DataObjects();	// not all, but some objects might have been created!

		ADD_MESSAGE_EXECUTION(CSG_String::Format("[%s] %s", Get_Name().c_str(), _TL("Execution failed")), SG_UI_MSG_STYLE_FAILURE);
	}
	else
	{
		Parameters.Msg_String(false);

	//	SG_UI_Process_Set_Busy(true, CSG_String::Format("%s: %s...", _TL("Executing"), Get_Name().c_str()));
		CSG_DateTime Started(CSG_DateTime::Now());

///////////////////////////////////////////////////////////
//#if !defined(_DEBUG)
#define _TOOL_EXCEPTION
	try
	{
//#endif
///////////////////////////////////////////////////////////

		bResult = On_Execute();

///////////////////////////////////////////////////////////
#ifdef _TOOL_EXCEPTION
	}	// try
	catch(const std::exception &Exception)
	{
		Message_Dlg(Exception.what()            , CSG_String::Format("%s | %s", Get_Name().c_str(), _TL("Access violation!")));
	}
	catch(...)
	{
		Message_Dlg(_TL("unspecified exception"), CSG_String::Format("%s | %s", Get_Name().c_str(), _TL("Access violation!")));
	}
	#endif
///////////////////////////////////////////////////////////

		CSG_TimeSpan Span = CSG_DateTime::Now() - Started;
	//	SG_UI_Process_Set_Busy(false);

		_Synchronize_DataObjects();

		if( !Process_Get_Okay(false) )
		{
			SG_UI_Msg_Add(_TL("Execution has been stopped by user!"), true, SG_UI_MSG_STYLE_BOLD);

			bResult	= false;
		}

		if( bResult && bAddHistory )
		{
			_Set_Output_History();
		}

		//-------------------------------------------------
		if( is_Interactive() )
		{
			if( bResult )
			{
				CSG_String Text(CSG_String::Format("\n%s...", _TL("Interactive tool started and is waiting for user input.")));

				SG_UI_Msg_Add          (Text, false, SG_UI_MSG_STYLE_BOLD);
				SG_UI_Msg_Add_Execution(Text, false, SG_UI_MSG_STYLE_BOLD);
			}
			else
			{
				ADD_MESSAGE_EXECUTION(_TL("Interactive tool initialization failed."), SG_UI_MSG_STYLE_FAILURE);
			}
		}
		else
		{
			CSG_String Time =
				  Span.Get_Hours       () >= 1 ? (Span.Format("%Hh %Mm %Ss"))
				: Span.Get_Minutes     () >= 1 ? (Span.Format(    "%Mm %Ss"))
				: Span.Get_Seconds     () >= 1 ? (Span.Format(        "%Ss"))
				: Span.Get_Milliseconds() >= 1 ? (Span.Format("%l ") + _TL("milliseconds"))
				: CSG_String(_TL("less than 1 millisecond"));

			if( Parameters.Get_Manager() != &SG_Get_Data_Manager() )
			{
				SG_UI_Msg_Add_Execution(CSG_String::Format("\n[%s] %s: %s", Get_Name().c_str(),
					_TL("execution time"), Time.c_str()),
					false, SG_UI_MSG_STYLE_NORMAL
				);
			}
			else
			{
				SG_UI_Msg_Add_Execution(CSG_String::Format("\n__________\n%s %s: %lld %s (%s)\n", _TL("total"),
					_TL("execution time"), Span.Get_Milliseconds(), _TL("milliseconds"), Time.c_str()),
					false, SG_UI_MSG_STYLE_BOLD
				);

				ADD_MESSAGE_EXECUTION(CSG_String::Format("[%s] %s (%s)", Get_Name().c_str(),
					bResult ? _TL("Execution succeeded") : _TL("Execution failed"), Time.c_str()),
					bResult ? SG_UI_MSG_STYLE_SUCCESS : SG_UI_MSG_STYLE_FAILURE
				);
			}
		}
	}

	//-----------------------------------------------------
	History_Supplement.Destroy();

	m_bExecutes	= false;

	SG_UI_Process_Set_Okay ();
	SG_UI_Process_Set_Ready();

	return( bResult );
}


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

//---------------------------------------------------------
bool CSG_Tool::_Synchronize_DataObjects(void)
{
	Parameters.DataObjects_Synchronize();

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->DataObjects_Synchronize();
	}

	CSG_Projection Projection;

	if( do_Sync_Projections() && Get_Projection(Projection) )
	{
		Parameters.DataObjects_Set_Projection(Projection);

		for(int i=0; i<Get_Parameters_Count(); i++)
		{
			Get_Parameters(i)->DataObjects_Set_Projection(Projection);
		}

		return( true );
	}

	return( false );
}

//---------------------------------------------------------
bool CSG_Tool::Get_Projection(CSG_Projection &Projection)	const
{
	Projection.Destroy();

	Parameters.DataObjects_Get_Projection(Projection);

	for(int i=0; i<Get_Parameters_Count() && !Projection.is_Okay(); i++)
	{
		Get_Parameters(i)->DataObjects_Get_Projection(Projection);
	}

	return( Projection.is_Okay() );
}


///////////////////////////////////////////////////////////
//                                                       //
//						Parameters						 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
int CSG_Tool::_On_Parameter_Changed(CSG_Parameter *pParameter, int Flags)
{
	CSG_Parameters *pParameters = pParameter  ? pParameter ->Get_Parameters() : NULL;
	CSG_Tool       *pTool       = pParameters ? pParameters->Get_Tool      () : NULL;

	if( pTool )
	{
		if( Flags & PARAMETER_CHECK_VALUES )
		{
			pTool->On_Parameter_Changed(pParameters, pParameter);
		}

		if( Flags & PARAMETER_CHECK_ENABLE )
		{
			pTool->On_Parameters_Enable(pParameters, pParameter);
		}

		return( 1 );
	}

	return( 0 );
}

//---------------------------------------------------------
int CSG_Tool::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	return( 1 );
}

//---------------------------------------------------------
int CSG_Tool::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	return( 1 );
}


///////////////////////////////////////////////////////////
//                                                       //
//					Extra Parameters					 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_Parameters * CSG_Tool::Add_Parameters(const CSG_String &Identifier, const CSG_String &Name, const CSG_String &Description)
{
	CSG_Parameters *pParameters = new CSG_Parameters(); // (Name, Description, Identifier);

	pParameters->Create(this, Name, Description, Identifier);
	pParameters->Set_Callback_On_Parameter_Changed(&_On_Parameter_Changed);
	pParameters->m_pTool = this;

	m_pParameters.Add(pParameters);

	return( pParameters );
}

//---------------------------------------------------------
CSG_Parameters * CSG_Tool::Get_Parameters(const CSG_String &Identifier) const
{
	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		if( Get_Parameters(i)->Cmp_Identifier(Identifier) )
		{
			return( Get_Parameters(i) );
		}
	}

	return( NULL );
}

//---------------------------------------------------------
bool CSG_Tool::Dlg_Parameters(const CSG_String &Identifier)
{
	CSG_Parameters *pParameters = Get_Parameters(Identifier);

	if( pParameters && (!pParameters->is_Managed() || Dlg_Parameters(pParameters, Get_Name())) )
	{
		pParameters->Set_History(History_Supplement);

		return( true );
	}

	return( false );
}


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

//---------------------------------------------------------
bool CSG_Tool::Dlg_Parameters(CSG_Parameters *pParameters, const CSG_String &Caption)
{
	return( pParameters ? Dlg_Parameters(*pParameters, Caption) : false );
}

bool CSG_Tool::Dlg_Parameters(CSG_Parameters &Parameters, const CSG_String &Caption)
{
	return( SG_UI_Dlg_Parameters(&Parameters, Caption.is_Empty() ? Get_Name() : Caption) );
}


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

//---------------------------------------------------------
void CSG_Tool::Set_Callback(bool bActive)
{
	Parameters.Set_Callback(bActive);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Set_Callback(bActive);
	}
}

//---------------------------------------------------------
bool CSG_Tool::Set_Manager(CSG_Data_Manager *pManager)
{
	Parameters.Set_Manager(pManager);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Set_Manager(pManager);
	}

	return( true );
}

//---------------------------------------------------------
CSG_Data_Manager * CSG_Tool::Get_Manager(void)	const
{
	return( Parameters.Get_Manager() );
}

//---------------------------------------------------------
CSG_Data_Manager * CSG_Tool::Create_Manager(void)
{
	Set_Manager(new CSG_Data_Manager());

	return( Get_Manager() );
}

//---------------------------------------------------------
bool CSG_Tool::Delete_Manager(bool bDetachData, bool bReset)
{
	CSG_Data_Manager *pManager = Get_Manager();

	if( pManager && pManager != &SG_Get_Data_Manager() )
	{
		pManager->Delete(bDetachData);

		delete(pManager);

		return( bReset ? Set_Manager(&SG_Get_Data_Manager()) : Set_Manager(NULL) );
	}

	return( false );
}


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

//---------------------------------------------------------
bool CSG_Tool::Settings_Push(CSG_Data_Manager *pManager)
{
	Parameters.Push(pManager);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Push(pManager);
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Tool::Settings_Pop(void)
{
	Parameters.Pop();

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Pop();
	}

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
//						Progress						 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
void CSG_Tool::Set_Show_Progress(bool bOn)
{
	m_bShow_Progress = bOn;
}

//---------------------------------------------------------
bool CSG_Tool::Set_Progress(int Position, int Range)	const
{
	return( Set_Progress((double)Position / (double)Range) );
}

//---------------------------------------------------------
bool CSG_Tool::Set_Progress(sLong Position, sLong Range)	const
{
	return( Set_Progress((double)Position / (double)Range) );
}

//---------------------------------------------------------
bool CSG_Tool::Set_Progress(double Position, double Range)	const
{
	return( m_bShow_Progress ? SG_UI_Process_Set_Progress(Position, Range) : Process_Get_Okay(false) );
}

//---------------------------------------------------------
bool CSG_Tool::Stop_Execution(bool bDialog)
{
	m_bExecutes = false;

	return( SG_UI_Stop_Execution(bDialog) );
}


///////////////////////////////////////////////////////////
//                                                       //
//						Message							 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
void CSG_Tool::Message_Dlg(const CSG_String &Text, const SG_Char *Caption)
{
	SG_UI_Dlg_Message(Text, Caption && Caption[0] != '\0' ? Caption : Get_Name().c_str());
}

//---------------------------------------------------------
bool CSG_Tool::Message_Dlg_Confirm(const CSG_String &Text, const SG_Char *Caption)
{
	return( SG_UI_Dlg_Continue(Text, Caption && Caption[0] != '\0' ? Caption : Get_Name().c_str()) );
}

//---------------------------------------------------------
bool CSG_Tool::Error_Set(TSG_Tool_Error Error_ID)
{
	switch( Error_ID )
	{
	default:
		return( Error_Set(_TL("Unknown Error")) );

	case TOOL_ERROR_Calculation:
		return( Error_Set(_TL("Calculation Error")) );
	}
}

//---------------------------------------------------------
bool CSG_Tool::Error_Set(const CSG_String &Text)
{
	SG_UI_Msg_Add_Error(Text);

	m_Execution_Info += "\n____\n" + Text;

	if( SG_UI_Process_Get_Okay(false) && !m_bError_Ignore )
	{
		switch( SG_UI_Dlg_Error(Text, CSG_String::Format("%s: %s?", _TL("Error"), _TL("Ignore"))) )
		{
		default:
			SG_UI_Process_Set_Okay(false);
			break;

		case  1:
			m_bError_Ignore	= true;
			break;
		}
	}

	return( SG_UI_Process_Get_Okay(false) );
}

//---------------------------------------------------------
bool CSG_Tool::Error_Fmt(const char *Format, ...)
{
	wxString	_s;

	va_list	argptr;
	
#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
#endif

	va_end(argptr);

	CSG_String	s(&_s);

	return( Error_Set(s) );
}

//---------------------------------------------------------
bool CSG_Tool::Error_Fmt(const wchar_t *Format, ...)
{
	wxString	_s;

	va_list	argptr;
	
#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
#endif

	va_end(argptr);

	CSG_String	s(&_s);

	return( Error_Set(s) );
}


///////////////////////////////////////////////////////////
//                                                       //
//			DataObjects / GUI Interaction				 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Tool::DataObject_Add(CSG_Data_Object *pDataObject, bool bShow)
{
	if( Parameters.Get_Manager() )
	{
		Parameters.Get_Manager()->Add(pDataObject);
	}

	if( Parameters.Get_Manager() == &SG_Get_Data_Manager() ) // prevent that local data manager send their data objects to gui
	{
		return( SG_UI_DataObject_Add(pDataObject, bShow ? SG_UI_DATAOBJECT_SHOW_MAP : SG_UI_DATAOBJECT_UPDATE) );
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Update_All(void)
{
	for(int i=0; i<Parameters.Get_Count(); i++)
	{
		if( Parameters(i)->is_Output() )
		{
			if( Parameters(i)->is_DataObject() )
			{
				DataObject_Update(Parameters(i)->asDataObject(), false);
			}
			else if( Parameters(i)->is_DataObject_List() )
			{
				for(int j=0; j<Parameters(i)->asList()->Get_Item_Count(); j++)
				{
					DataObject_Update(Parameters(i)->asList()->Get_Item(j), false);
				}
			}
		}
	}

	return( true );
}


///////////////////////////////////////////////////////////
//                                                       //
//		Static Data Message/Progress Functions			 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Tool::Process_Get_Okay(bool bBlink)
{
	return( SG_UI_Process_Get_Okay(bBlink) );
}

//---------------------------------------------------------
void CSG_Tool::Process_Set_Text(const CSG_String &Text)
{
	SG_UI_Process_Set_Text(Text);
}

//---------------------------------------------------------
void CSG_Tool::Process_Set_Text(const char    *Format, ...)
{
	wxString	_s;

	va_list	argptr;

	#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
	#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
	#endif

	va_end(argptr);

	CSG_String	s(&_s);

	SG_UI_Process_Set_Text(s);
}

//---------------------------------------------------------
void CSG_Tool::Process_Set_Text(const wchar_t *Format, ...)
{
	wxString	_s;

	va_list	argptr;

	#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
	#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
	#endif

	va_end(argptr);

	CSG_String	s(&_s);

	SG_UI_Process_Set_Text(s);
}

//---------------------------------------------------------
void CSG_Tool::Message_Add(const CSG_String &Text, bool bNewLine)
{
	SG_UI_Msg_Add_Execution(Text, bNewLine);

	if( bNewLine )
	{
		m_Execution_Info += "\n";
	}

	m_Execution_Info += Text;
}

//---------------------------------------------------------
void CSG_Tool::Message_Fmt(const char *Format, ...)
{
	wxString	_s;

	va_list	argptr;

	#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
	#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
	#endif

	va_end(argptr);

	CSG_String	s(&_s);

	Message_Add(s, false);
}

//---------------------------------------------------------
void CSG_Tool::Message_Fmt(const wchar_t *Format, ...)
{
	wxString	_s;

	va_list	argptr;

	#ifdef _SAGA_LINUX
	// workaround as we only use wide characters
	// since wx 2.9.4 so interpret strings as multibyte
	wxString	_Format(Format);	_Format.Replace("%s", "%ls");
	va_start(argptr, _Format);
	_s.PrintfV(_Format, argptr);
	#else
	va_start(argptr, Format);
	_s.PrintfV(Format, argptr);
	#endif

	va_end(argptr);

	CSG_String	s(&_s);

	Message_Add(s, false);
}


///////////////////////////////////////////////////////////
//                                                       //
//		Static Data Object Property Functions			 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
bool CSG_Tool::DataObject_Update(CSG_Data_Object *pDataObject, int Show)
{
	return( SG_UI_DataObject_Update(pDataObject, Show, NULL) );
}

bool CSG_Tool::DataObject_Update(CSG_Data_Object *pDataObject, double Minimum, double Maximum, int Show)
{
	CSG_Parameters P;

	return( DataObject_Get_Parameters(pDataObject, P)
		&&  P.Set_Parameter("STRETCH_DEFAULT"  , 3      ) // manual
		&&  P.Set_Parameter("METRIC_ZRANGE.MIN", Minimum)
		&&  P.Set_Parameter("METRIC_ZRANGE.MAX", Maximum)
		&&  SG_UI_DataObject_Update(pDataObject, Show, &P)
	);
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Get_Colors(CSG_Data_Object *pDataObject, CSG_Colors &Colors)
{
	return( SG_UI_DataObject_Colors_Get(pDataObject, &Colors) );
}

bool CSG_Tool::DataObject_Set_Colors(CSG_Data_Object *pDataObject, const CSG_Colors &Colors)
{
	CSG_Colors c; return( c.Create(Colors) && SG_UI_DataObject_Colors_Set(pDataObject, &c) );
}

bool CSG_Tool::DataObject_Set_Colors(CSG_Data_Object *pDataObject, int nColors, int Colors, bool bRevert)
{
	CSG_Colors c; return( c.Set_Predefined(Colors, bRevert, nColors) && SG_UI_DataObject_Colors_Set(pDataObject, &c) );
}

bool CSG_Tool::DataObject_Set_Colors(CSG_Data_Object *pDataObject, const CSG_String &Colors, int nColors, bool bRevert)
{
	CSG_Colors c; return( c.Set_Predefined(Colors, bRevert, nColors) && SG_UI_DataObject_Colors_Set(pDataObject, &c) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Get_Parameters(CSG_Data_Object *pDataObject, CSG_Parameters &Parameters)
{
	return( SG_UI_DataObject_Params_Get(pDataObject, &Parameters) );
}

bool CSG_Tool::DataObject_Set_Parameters(CSG_Data_Object *pDataObject, CSG_Parameters &Parameters)
{
	return( SG_UI_DataObject_Params_Set(pDataObject, &Parameters) );
}

bool CSG_Tool::DataObject_Set_Parameters(CSG_Data_Object *pDataObject, CSG_Data_Object *pCopy)
{
	if( pDataObject == pCopy )
	{
		return( true );
	}

	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pCopy, P) )
	{
		P.Del_Parameter("OBJECT_NODATA"  );
		P.Del_Parameter("OBJECT_Z_FACTOR");
		P.Del_Parameter("OBJECT_Z_OFFSET");

		return( DataObject_Set_Parameters(pDataObject, P) );
	}

	return( false );
}

//---------------------------------------------------------
CSG_Parameter * CSG_Tool::DataObject_Get_Parameter(CSG_Data_Object *pDataObject, const CSG_String &ID)
{
	static CSG_Parameters	P;

	return( DataObject_Get_Parameters(pDataObject, P) ? P(ID) : NULL );
}

bool CSG_Tool::DataObject_Set_Parameter(CSG_Data_Object *pDataObject, CSG_Parameter *pParameter)
{
	CSG_Parameters	P;

	return( P._Add(pParameter) != NULL && DataObject_Set_Parameters(pDataObject, P) );
}

bool CSG_Tool::DataObject_Set_Parameter(CSG_Data_Object *pDataObject, CSG_Data_Object *pCopy, const CSG_String &ID)
{
	CSG_Parameter	*pParameter	= DataObject_Get_Parameter(pCopy, ID);

	return( DataObject_Set_Parameter(pDataObject, pParameter) );
}

bool CSG_Tool::DataObject_Set_Parameter	(CSG_Data_Object *pDataObject, const CSG_String &ID, int            Value)
{
	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pDataObject, P) && P(ID) )
	{
		return( P(ID)->Set_Value(Value) && DataObject_Set_Parameter(pDataObject, P(ID)) );
	}

	return( false );
}

bool CSG_Tool::DataObject_Set_Parameter	(CSG_Data_Object *pDataObject, const CSG_String &ID, double         Value)
{
	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pDataObject, P) && P(ID) )
	{
		return( P(ID)->Set_Value(Value) && DataObject_Set_Parameter(pDataObject, P(ID)) );
	}

	return( false );
}

bool CSG_Tool::DataObject_Set_Parameter	(CSG_Data_Object *pDataObject, const CSG_String &ID, void          *Value)
{
	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pDataObject, P) && P(ID) )
	{
		return( P(ID)->Set_Value(Value) && DataObject_Set_Parameter(pDataObject, P(ID)) );
	}

	return( false );
}

bool CSG_Tool::DataObject_Set_Parameter	(CSG_Data_Object *pDataObject, const CSG_String &ID, const SG_Char *Value)
{
	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pDataObject, P) && P(ID) )
	{
		return( P(ID)->Set_Value(Value) && DataObject_Set_Parameter(pDataObject, P(ID)) );
	}

	return( false );
}

bool CSG_Tool::DataObject_Set_Parameter	(CSG_Data_Object *pDataObject, const CSG_String &ID, double loVal, double hiVal)	// Range Parameter
{
	CSG_Parameters	P;

	if( DataObject_Get_Parameters(pDataObject, P) && P(ID) && P(ID)->Get_Type() == PARAMETER_TYPE_Range )
	{
		return( P(ID)->asRange()->Set_Range(loVal, hiVal) && DataObject_Set_Parameter(pDataObject, P(ID)) );
	}

	return( false );
}


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

//---------------------------------------------------------
#define INIT_STRETCH_OPTIONS(method) { if( !pDataObject || (pDataObject->asTable(true) && (Field < 0 || Field >= pDataObject->asTable(true)->Get_Field_Count())) ) { return( false ); }\
	if( Colors >= 0 ) { DataObject_Set_Colors(pDataObject, -1, Colors); }\
	DataObject_Set_Parameter(pDataObject, "COLORS_TYPE"      , 3); /* graduated colors */\
	DataObject_Set_Parameter(pDataObject, "STRETCH_DEFAULT"  , method);\
	DataObject_Set_Parameter(pDataObject, "METRIC_SCALE_MODE", Interval_Mode);\
	DataObject_Set_Parameter(pDataObject, "METRIC_SCALE_LOG" , Interval_Log );\
	if( pDataObject->asTable(true) )\
	{	DataObject_Set_Parameter(pDataObject, "METRIC_FIELD" , Field);\
		DataObject_Set_Parameter(pDataObject, "METRIC_MORMAL", pDataObject->asTable(true)->Get_Field_Count());\
	}\
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Set_Stretch_Linear(CSG_Data_Object *pDataObject, int Field, double Minimum, double Maximum, int Interval_Mode, double Interval_Log, int Colors, bool bUpdateNow)
{
	INIT_STRETCH_OPTIONS(0);

	DataObject_Set_Parameter(pDataObject, "STRETCH_LINEAR.MIN", Minimum);
	DataObject_Set_Parameter(pDataObject, "STRETCH_LINEAR.MAX", Maximum);

	return( bUpdateNow ? DataObject_Update(pDataObject) : true );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Set_Stretch_StdDev(CSG_Data_Object *pDataObject, int Field, double StdDev, bool bKeepInRange, int Interval_Mode, double Interval_Log, int Colors, bool bUpdateNow)
{
	INIT_STRETCH_OPTIONS(1);

	DataObject_Set_Parameter(pDataObject, "STRETCH_STDDEV" , StdDev      );
	DataObject_Set_Parameter(pDataObject, "STRETCH_INRANGE", bKeepInRange);
	DataObject_Update(pDataObject);

	return( bUpdateNow ? DataObject_Update(pDataObject) : true );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Set_Stretch_Percentile(CSG_Data_Object *pDataObject, int Field, double Minimum, double Maximum, int Interval_Mode, double Interval_Log, int Colors, bool bUpdateNow)
{
	INIT_STRETCH_OPTIONS(2);

	DataObject_Set_Parameter(pDataObject, "STRETCH_PCTL.MIN", Minimum);
	DataObject_Set_Parameter(pDataObject, "STRETCH_PCTL.MAX", Maximum);

	return( bUpdateNow ? DataObject_Update(pDataObject) : true );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Set_Stretch(CSG_Data_Object *pDataObject, int Field, double Minimum, double Maximum, int Interval_Mode, double Interval_Log, int Colors, bool bUpdateNow)
{
	INIT_STRETCH_OPTIONS(3);

	DataObject_Set_Parameter(pDataObject, "METRIC_ZRANGE.MIN", Minimum);
	DataObject_Set_Parameter(pDataObject, "METRIC_ZRANGE.MAX", Maximum);

	return( bUpdateNow ? DataObject_Update(pDataObject) : true );
}


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

//---------------------------------------------------------
#define INIT_CLASSIFY_OPTIONS(method) if( !pDataObject || (pDataObject->asTable(true) && (Field < 0 || Field >= pDataObject->asTable(true)->Get_Field_Count())) ) { return( false ); }\
	CSG_MetaData Options; Options.Add_Child("METHOD", method); Options.Add_Child("COLORS", Colors); Options.Add_Child("FIELD", Field);

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Unique(CSG_Data_Object *pDataObject, int Field, int maxClasses, int Colors)
{
	INIT_CLASSIFY_OPTIONS(0);

	Options.Add_Child("MAXCLASSES", maxClasses);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Equal(CSG_Data_Object *pDataObject, int Field, int Classes, int Colors)
{
	INIT_CLASSIFY_OPTIONS(1);

	Options.Add_Child("CLASSES", Classes);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Defined(CSG_Data_Object *pDataObject, int Field, double Interval, bool bOffset, double Offset, int Colors)
{
	INIT_CLASSIFY_OPTIONS(2);

	Options.Add_Child("INTERVAL", Interval); if( bOffset ) { Options.Add_Child("OFFSET", Offset); }

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Quantile(CSG_Data_Object *pDataObject, int Field, int Classes, bool bHistogram, int Colors)
{
	INIT_CLASSIFY_OPTIONS(3);

	Options.Add_Child("CLASSES", Classes); Options.Add_Child("HISTOGRAM", bHistogram ? 1 : 0);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Geometric(CSG_Data_Object *pDataObject, int Field, int Classes, bool bIncreasing, int Colors)
{
	INIT_CLASSIFY_OPTIONS(4);

	Options.Add_Child("CLASSES", Classes); Options.Add_Child("INCREASING", bIncreasing ? 1 : 0);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_Natural(CSG_Data_Object *pDataObject, int Field, int Classes, int Colors)
{
	INIT_CLASSIFY_OPTIONS(5);

	Options.Add_Child("CLASSES", Classes);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Classify_StdDev(CSG_Data_Object *pDataObject, int Field, double StdDev, double StdDev_Max, int Colors)
{
	INIT_CLASSIFY_OPTIONS(6);

	Options.Add_Child("STDDEV", StdDev); Options.Add_Child("STDDEV_MAX", StdDev_Max);

	return( SG_UI_DataObject_Classify(pDataObject, Options) );
}


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

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
CSG_Parameter * CSG_Tool::Get_Parameter(const char       *ID) const { return( Get_Parameter(CSG_String(ID)) ); }
CSG_Parameter * CSG_Tool::Get_Parameter(const wchar_t    *ID) const { return( Get_Parameter(CSG_String(ID)) ); }
CSG_Parameter * CSG_Tool::Get_Parameter(const CSG_String &ID) const
{
	CSG_Parameter *pParameter = Parameters(ID);

	for(int i=0; !pParameter && i<Get_Parameters_Count(); i++)
	{
		pParameter = Get_Parameters(i)->Get_Parameter(ID);
	}

	return( pParameter );
}

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, CSG_Parameter *pValue) { return( Parameters.Set_Parameter(ID, pValue) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, CSG_Parameter *pValue) { return( Parameters.Set_Parameter(ID, pValue) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, CSG_Parameter *pValue) { return( Parameters.Set_Parameter(ID, pValue) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, int               Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, int               Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, int               Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, double            Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, double            Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, double            Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, void             *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, void             *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, void             *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, const CSG_String &Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, const CSG_String &Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, const CSG_String &Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, const char       *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, const char       *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, const char       *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }

//---------------------------------------------------------
/**
  * Direct 'set a value' access to this tool's default parameters list.
*/
//---------------------------------------------------------
bool CSG_Tool::Set_Parameter(const CSG_String &ID, const wchar_t    *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const char       *ID, const wchar_t    *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }
bool CSG_Tool::Set_Parameter(const wchar_t    *ID, const wchar_t    *Value, int Type) { return( Parameters.Set_Parameter(ID, Value, Type) ); }


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

//---------------------------------------------------------
/**
* Resets the tools' parameters list. All input and output
* data objects and object lists are cleared and parameter
* defaults are restored.
*/
bool CSG_Tool::Reset(bool bManager)
{
	Reset_Grid_System();

	if( bManager )
	{
		Reset_Manager();
	}

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Restore_Defaults(true);
	}

	return( Parameters.Restore_Defaults(true) );
}

//---------------------------------------------------------
/**
* Resets the tools' data manager so it will be the SAGA API's
* default manager as can be requested by SG_Get_Data_Manager().
*/
bool CSG_Tool::Reset_Manager(void)
{
	return( Set_Manager(&SG_Get_Data_Manager()) );
}

//---------------------------------------------------------
/**
* Resets the tools' grid system, if it has one, which is
* typically the case for all derivatives of CSG_Tool_Grid.
*/
bool CSG_Tool::Reset_Grid_System(void)
{
	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		Get_Parameters(i)->Reset_Grid_System();
	}

	return( Parameters.Reset_Grid_System() );
}

//---------------------------------------------------------
/**
* Sets the tools' grid system, if it has one, which is
* typically the case for all derivatives of CSG_Tool_Grid.
*/
bool CSG_Tool::Set_Grid_System(const CSG_Grid_System &System)
{
	return( Parameters.Set_Grid_System(System) );
}

//---------------------------------------------------------
/**
* Gets the tools' grid system, if it has one, which is
* typically the case for all derivatives of CSG_Tool_Grid.
*/
CSG_Grid_System * CSG_Tool::Get_Grid_System(void) const
{
	return( Parameters.Get_Grid_System() );
}


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

//---------------------------------------------------------
bool CSG_Tool::Update_Parameter_States(void)
{
	_Update_Parameter_States(&Parameters);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		_Update_Parameter_States(Get_Parameters(i));
	}

	return( true );
}

//---------------------------------------------------------
void CSG_Tool::_Update_Parameter_States(CSG_Parameters *pParameters)
{
	if( pParameters )
	{
		for(int i=0; i<pParameters->Get_Count(); i++)
		{
			CSG_Parameter	*pParameter	= pParameters->Get_Parameter(i);

			if( pParameter->Get_Type() == PARAMETER_TYPE_Parameters )
			{
				_Update_Parameter_States(pParameter->asParameters());
			}
			else
			{
				On_Parameters_Enable(pParameters, pParameter);
			}
		}
	}
}


///////////////////////////////////////////////////////////
//                                                       //
//						Script							 //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
CSG_String CSG_Tool::Get_Script(Script_Format Format, bool bHeader, int Arguments, bool bWrapArgs)
{
	switch( Format )
	{
	case Script_Format::CMD_Shell                    : return( _Get_Script_CMD           (      bHeader, Arguments > 0, bWrapArgs, false    ) );
	case Script_Format::CMD_Batch                    : return( _Get_Script_CMD           (      bHeader, Arguments > 0, bWrapArgs, true     ) );
	case Script_Format::CMD_Usage                    : return( _Get_Script_CMD_Usage     (                                                  ) );

	case Script_Format::Toolchain                    : return( CSG_Tool_Chain::Get_Script(this, bHeader, Arguments > 0                      ) );

	case Script_Format::Python                       : return( _Get_Script_Python        (      bHeader, Arguments > 0                      ) );

	case Script_Format::Python_Wrapper_Func_Name     : return( _Get_Script_Python_Wrap   (      bHeader, true , false,         1, bWrapArgs ) );
	case Script_Format::Python_Wrapper_Func_ID       : return( _Get_Script_Python_Wrap   (      bHeader, false, false,         1, bWrapArgs ) );

	case Script_Format::Python_Wrapper_Call_Name     : return( _Get_Script_Python_Wrap   (      bHeader, true , true , Arguments, bWrapArgs ) );
	case Script_Format::Python_Wrapper_Call_ID       : return( _Get_Script_Python_Wrap   (      bHeader, false, true , Arguments, bWrapArgs ) );

	case Script_Format::Markdown_Table               : return( _Get_Script_Markdown      (      bHeader, Arguments                          ) );
	}

	return( "" );
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::_Get_Script_CMD(bool bHeader, bool bAllArguments, bool bWrapArgs, bool bBatch)
{
	CSG_String Script;

	if( bHeader )
	{
		if( bBatch ) // DOS/Windows Batch Script
		{
			Script += "@ECHO OFF\n\n";
			Script += "PUSHD %~dp0\n\n";
			Script += "REM SET SAGA_TLB=C:\\MyTools\n\n";
			Script += "SET SAGA_CMD=" + SG_UI_Get_Application_Path(true) + "saga_cmd.exe\n\n";
			Script += "REM Tool: " + Get_Name() + "\n\n";
			Script += "%SAGA_CMD%";
		}
		else         // Bash Shell Script
		{
			Script += "#!/bin/bash\n\n";
			Script += "# export SAGA_TLB=~/mytools\n\n";
			Script += "# tool: " + Get_Name() + "\n\n";
			Script += "saga_cmd";
		}
	}
	else
	{
		Script += "saga_cmd";
	}

	//-----------------------------------------------------
	Script += Get_Library().Contains(" ")	// white space? use quotation marks!
		? " \"" + Get_Library() + "\""
		: " "   + Get_Library();

	Script += Get_ID().Contains     (" ")	// white space? use quotation marks!
		? " \"" + Get_ID     () + "\""
		: " "   + Get_ID     ();

	_Get_Script_CMD(Script, Get_Parameters(), bAllArguments, bWrapArgs, bBatch);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		_Get_Script_CMD(Script, Get_Parameters(i), bAllArguments, bWrapArgs, bBatch);
	}

	//-----------------------------------------------------
	if( bHeader )
	{
		Script += bBatch ? "\n\nPAUSE\n" : "\n";
	}

	return( Script );
}

//---------------------------------------------------------
void CSG_Tool::_Get_Script_CMD(CSG_String &Script, CSG_Parameters *pParameters, bool bAllArguments, bool bWrapArgs, bool bBatch)
{
	#define GET_ID1(p) (p->Get_Parameters()->Get_Identifier().Length() > 0 \
		? CSG_String::Format("%s_%s", p->Get_Parameters()->Get_Identifier().c_str(), p->Get_Identifier()) \
		: CSG_String::Format(p->Get_Identifier())).c_str()

	#define GET_ID2(p, s) CSG_String::Format("%s_%s", GET_ID1(p), s).c_str()

	const char *Prefix = !bWrapArgs ? " -" : bBatch ? " ^\n -" : " \\\n -";
	const char *StrFmt = bBatch ? "%s=\"%s\"" : "%s=\\\"\"%s\"\\\"";

	//-----------------------------------------------------
	for(int iParameter=0; iParameter<pParameters->Get_Count(); iParameter++)
	{
		CSG_Parameter *p = pParameters->Get_Parameter(iParameter);

		if( !bAllArguments && (!p->is_Enabled(false) || p->is_Information() || !p->do_UseInCMD()) )
		{
			continue;
		}

		switch( p->Get_Type() )
		{
		default:
			break;

		case PARAMETER_TYPE_Bool             :
			Script += Prefix + CSG_String::Format("%s=%d", GET_ID1(p), p->asBool() ? 1 : 0);
			break;

		case PARAMETER_TYPE_Int              :
		case PARAMETER_TYPE_Data_Type        :
		case PARAMETER_TYPE_Choice           :
		case PARAMETER_TYPE_Table_Field      :
			Script += Prefix + CSG_String::Format("%s=%d", GET_ID1(p), p->asInt());
			break;

		case PARAMETER_TYPE_Choices          :
		case PARAMETER_TYPE_Table_Fields     :
			if( p->asString() && *p->asString() )
			{
				Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), p->asString());
			}
			break;

        case PARAMETER_TYPE_Color            :
            Script += Prefix + CSG_String::Format("%s=\"%s\"", GET_ID1(p), SG_Color_To_Text(p->asColor()).c_str());
            break;

		case PARAMETER_TYPE_Double           :
		case PARAMETER_TYPE_Degree           :
			Script += Prefix + CSG_String::Format("%s=%g", GET_ID1(p), p->asDouble());
			break;

		case PARAMETER_TYPE_Range            :
			Script += Prefix + CSG_String::Format("%s=%g", GET_ID2(p, SG_T("MIN")), p->asRange()->Get_Min());
			Script += Prefix + CSG_String::Format("%s=%g", GET_ID2(p, SG_T("MAX")), p->asRange()->Get_Max());
			break;

		case PARAMETER_TYPE_String           :
			if( ((CSG_Parameter_String *)p)->is_Password() )
			{
				Script += Prefix + CSG_String::Format("%s=\"***\"", GET_ID1(p));
				break;
			}

		case PARAMETER_TYPE_Date             :
		case PARAMETER_TYPE_Text             :
		case PARAMETER_TYPE_FilePath         :
			Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), p->asString());
			break;

		case PARAMETER_TYPE_FixedTable       :
			Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), p->asString());
			break;

		case PARAMETER_TYPE_Grid_System      :
			if( p->Get_Children_Count() == 0 )
			{
				Script += Prefix + CSG_String::Format("%s=%d", GET_ID2(p, SG_T("NX")), p->asGrid_System()->Get_NX      ());
				Script += Prefix + CSG_String::Format("%s=%d", GET_ID2(p, SG_T("NY")), p->asGrid_System()->Get_NY      ());
				Script += Prefix + CSG_String::Format("%s=%g", GET_ID2(p, SG_T( "X")), p->asGrid_System()->Get_XMin    ());
				Script += Prefix + CSG_String::Format("%s=%g", GET_ID2(p, SG_T( "Y")), p->asGrid_System()->Get_YMin    ());
				Script += Prefix + CSG_String::Format("%s=%g", GET_ID2(p, SG_T( "D")), p->asGrid_System()->Get_Cellsize());
			}
			break;

		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       :
			if( p->is_Input() )
			{
				Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), SG_Get_Data_Manager().Exists(p->asDataObject()) && p->asDataObject()->Get_File_Name() ? p->asDataObject()->Get_File_Name() : SG_T("input file"));
			}
			else
			{
				CSG_String File(p->Get_Name());

				switch( p->Get_DataObject_Type() )
				{
				case SG_DATAOBJECT_TYPE_Grid      : File += ".sg-grd-z"; break;
				case SG_DATAOBJECT_TYPE_Grids     : File += ".sg-gds-z"; break;
				case SG_DATAOBJECT_TYPE_Table     : File += ".txt"     ; break;
				case SG_DATAOBJECT_TYPE_Shapes    : File += ".geojson" ; break;
				case SG_DATAOBJECT_TYPE_PointCloud: File += ".sg-pts-z"; break;
				case SG_DATAOBJECT_TYPE_TIN       : File += ".geojson" ; break;
				default                           : File += ".dat"     ; break;
				}

				Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), File.c_str());
			}
			break;

		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  :
			if( p->is_Input() )
			{
				Script += Prefix + CSG_String::Format("%s=", GET_ID1(p));

				if( p->asList()->Get_Item_Count() == 0 )
				{
					Script += "file(s)";
				}
				else
				{
					Script += SG_File_Exists(p->asList()->Get_Item(0)->Get_File_Name())
						? p->asList()->Get_Item(0)->Get_File_Name() : _TL("memory");

					for(int iObject=1; iObject<p->asList()->Get_Item_Count(); iObject++)
					{
						Script += ";";
						Script += SG_File_Exists(p->asList()->Get_Item(iObject)->Get_File_Name())
							? p->asList()->Get_Item(iObject)->Get_File_Name() : _TL("memory");
					}
				}
			}
			else
			{
				Script += Prefix + CSG_String::Format(StrFmt, GET_ID1(p), p->Get_Name());
			}
			break;
		}
	}
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::_Get_Script_CMD_Usage(void)
{
	wxCmdLineParser Parser; Parser.SetSwitchChars("-");

	_Get_Script_CMD_Usage(Get_Parameters(), Parser);

	for(int i=0; i<Get_Parameters_Count(); i++)
	{
		_Get_Script_CMD_Usage(Get_Parameters(i), Parser);
	}

	wxString Usage = wxString::Format("\nUsage: saga_cmd %s %s %s", Get_Library().c_str(), Get_ID().c_str(),
		Parser.GetUsageString().AfterFirst(' ').AfterFirst(' ')
	);

	CSG_String _Usage(&Usage);

	return( _Usage );
}

//---------------------------------------------------------
void CSG_Tool::_Get_Script_CMD_Usage(CSG_Parameters *pParameters, wxCmdLineParser &Parser)
{
	for(int i=0; i<pParameters->Get_Count(); i++)
	{
		CSG_Parameter *pParameter = pParameters->Get_Parameter(i);

		//-------------------------------------------------
		if( pParameter->is_DataObject() )	// reset data object parameters, avoids problems when tool is called more than once without un-/reloading
		{
			pParameter->Set_Value(DATAOBJECT_NOTSET);
		}
		else if( pParameter->is_DataObject_List() )
		{
			pParameter->asList()->Del_Items();
		}

		//-------------------------------------------------
		if( pParameter->do_UseInCMD() == false )
		{
			continue;
		}

		wxString Description = pParameter->Get_Description(
			PARAMETER_DESCRIPTION_NAME|PARAMETER_DESCRIPTION_TYPE|PARAMETER_DESCRIPTION_PROPERTIES, SG_T("\n\t")
		).c_str();

		Description.Replace("\xb", "");	// unicode problem: quick'n'dirty bug fix, to be replaced

		wxString ID(pParameter->Get_CmdID().c_str());

		if( pParameter->is_Input() || pParameter->is_Output() )
		{
			Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR|wxCMD_LINE_PARAM_OPTIONAL);
		}

		//-------------------------------------------------
		else if( pParameter->is_Option() && !pParameter->is_Information() )
		{
			switch( pParameter->Get_Type() )
			{
			case PARAMETER_TYPE_Parameters  :
				_Get_Script_CMD_Usage(pParameter->asParameters(), Parser);
				break;

			case PARAMETER_TYPE_Bool        :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Int         :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Data_Type   :
			case PARAMETER_TYPE_Choice      :
			case PARAMETER_TYPE_Choices     :
			case PARAMETER_TYPE_Table_Field :
			case PARAMETER_TYPE_Table_Fields:
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Double      :
			case PARAMETER_TYPE_Degree      :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Date        :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_DATE  , wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Range       :
				Parser.AddOption(ID + "_MIN", wxEmptyString, Description, wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
				Parser.AddOption(ID + "_MAX", wxEmptyString, Description, wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Color       :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Colors      :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_String      :
			case PARAMETER_TYPE_Text        :
			case PARAMETER_TYPE_FilePath    :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_FixedTable  :
				Parser.AddOption(ID, wxEmptyString, Description, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				break;

			case PARAMETER_TYPE_Grid_System :
				if( pParameter->Get_Children_Count() == 0 )
				{
					Parser.AddOption(ID + "_D"   , wxEmptyString, _TL("Cell Size"                          ), wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
					Parser.AddOption(ID + "_X"   , wxEmptyString, _TL("Lower Left Center Cell X-Coordinate"), wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
					Parser.AddOption(ID + "_Y"   , wxEmptyString, _TL("Lower Left Center Cell Y-Coordinate"), wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL);
					Parser.AddOption(ID + "_NX"  , wxEmptyString, _TL("Number of Columns"                  ), wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL);
					Parser.AddOption(ID + "_NY"  , wxEmptyString, _TL("Number of Rows"                     ), wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL);
					Parser.AddOption(ID + "_FILE", wxEmptyString, _TL("Grid File"                          ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
				}
				break;

			default:
				break;
			}
		}
	}
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::_Get_Script_Python(bool bHeader, bool bAllArguments)
{
	CSG_String	Script, Name(Get_Name());

	Name.Replace(" ", "_");
	Name.Replace("(", "");
	Name.Replace(")", "");
	Name.Replace("[", "");
	Name.Replace("]", "");
	Name.Replace(".", "");
	Name.Replace(",", "");
	Name.Replace("/", "");
	Name.Replace("-", "");

	//-----------------------------------------------------
	if( bHeader )
	{
		Script += "#! /usr/bin/env python\n";
		Script += "\n";
		Script += "#_________________________________________\n";
		Script += "##########################################\n";
		Script += "\n";
#ifdef _SAGA_MSW
		CSG_String AppPath = SG_UI_Get_Application_Path(true); AppPath.Replace("\\", "/");
		Script += "# Initialize the environment...\n";
		Script += "\n";
		Script += "# Windows: Let the 'SAGA_PATH' environment variable point to\n";
		Script += "# the SAGA installation folder before importing 'saga_api'!\n";
		Script += "# This can be defined globally in the Windows system or\n";
		Script += "# user environment variable settings, in the 'PySAGA/__init__.py'\n";
		Script += "# file, or in the individual Python script itself. To do the latter\n";
		Script += "# just uncomment the following line and adjust the path accordingly:\n";
		Script += "###import os; os.environ['SAGA_PATH'] = '" + AppPath + "'\n";
		Script += "\n";
		Script += "# Windows: The most convenient way to make PySAGA available to all your\n";
		Script += "# Python scripts is to copy the PySAGA folder to the 'Lib/site-packages/'\n";
		Script += "# folder of your Python installation. If don't want to do this or if you\n";
		Script += "# don't have the rights to do so, you can also copy it to the folder with\n";
		Script += "# the Python scripts in which you want to use PySAGA, or alternatively\n";
		Script += "# you can add the path containing the PySAGA folder (e.g. the path to your\n";
		Script += "# SAGA installation) to the PYTHONPATH environment variable. To do this\n";
		Script += "# from within your script you can also take the following command (just\n";
		Script += "# uncomment the following line and adjust the path accordingly):\n";
		Script += "###import sys; sys.path.insert(1, '" + AppPath + "')\n";
		Script += "\n";
#endif // _SAGA_MSW
		Script += "# Import saga_api from PySAGA:\n";
		Script += "from PySAGA import saga_api\n";
		Script += "\n";
		Script += "\n";
		Script += "#_________________________________________\n";
		Script += "##########################################\n";
		Script += "def Run_" + Name + "(Results):\n";
	}

	//-----------------------------------------------------
	if( bHeader ) Script += "    # Get the tool:\n";
	Script += "    Tool = saga_api.SG_Get_Tool_Library_Manager().Get_Tool('" + Get_Library() + "', '" + Get_ID() + "')\n";
	Script += "    if not Tool:\n";
	Script += "        saga_api.SG_UI_Msg_Add_Error('Failed to request tool: " + Get_Name() + "')\n";
	Script += "        return False\n";
	Script += "\n";
	if( bHeader ) Script += "    # Set the parameter interface:\n";
	Script += "    Tool.Reset()\n";

	//-------------------------------------------------
	_Get_Script_Python(Script, Get_Parameters(), bAllArguments);

	for(int iParameters=0; iParameters<Get_Parameters_Count(); iParameters++)
	{
		_Get_Script_Python(Script, Get_Parameters(iParameters), bAllArguments, Get_Parameters(iParameters)->Get_Identifier());
	}

	//-------------------------------------------------
	Script += "\n";
	if( bHeader ) Script += "    # Execute the tool:\n";
	Script += "    if not Tool.Execute():\n";
	Script += "        saga_api.SG_UI_Msg_Add_Error('failed to execute tool: ' + Tool.Get_Name().c_str())\n";
	Script += "        return False\n";
	Script += "\n";
	if( bHeader ) Script += "    # Request the results:\n";

	for(int iParameter=0; iParameter<Get_Parameters()->Get_Count(); iParameter++)
	{
		CSG_Parameter *p = Get_Parameters()->Get_Parameter(iParameter);

		if( p->is_Output() )
		{
			CSG_String id(p->Get_Identifier()), type, ext;

			switch( p->Get_DataObject_Type() )
			{
			case SG_DATAOBJECT_TYPE_Grid      : type = "Grid"      ; ext = "sg-grd-z"; break;
			case SG_DATAOBJECT_TYPE_Grids     : type = "Grids"     ; ext = "sg-gds-z"; break;
			case SG_DATAOBJECT_TYPE_Table     : type = "Table"     ; ext = "txt"     ; break;
			case SG_DATAOBJECT_TYPE_Shapes    : type = "Shapes"    ; ext = "geojson" ; break;
			case SG_DATAOBJECT_TYPE_PointCloud: type = "PointCloud"; ext = "sg-pts-z"; break;
			case SG_DATAOBJECT_TYPE_TIN       : type = "TIN"       ; ext = "geojson" ; break;
			default                           : type = ""          ; ext = ""        ; break;
			}

			if( p->is_DataObject() )
			{
				Script += "    Data = Tool.Get_Parameter('" +  id + "').as" + type + "()\n";

				if( bHeader )
				{
					Script += "    Data.Save('{:s}/{:s}.{:s}'.format(Results, Data.Get_Name(), '" + ext + "'))\n\n";
				}
			}
			else if( p->is_DataObject_List() )
			{
				Script += "    List = Tool.Get_Parameter('" +  id + "').as" + type + "List()\n";
				Script += "    for i in range(0, List.Get_Item_Count()):\n";

				if( bHeader )
				{
					Script += "        List.Get_Item(i).Save('{:s}/{:s}_{:d}.{:s}'.format(Results, List.Get_Name(), i, '" + ext + "'))\n\n";
				}
				else
				{
					Script += "        Data = List.Get_Item(i)\n";
				}
			}
		}
	}

	//-----------------------------------------------------
	if( bHeader )
	{
		Script += "\n";
		Script += "    return True\n";
		Script += "\n";
		Script += "\n";
		Script += "#_________________________________________\n";
		Script += "##########################################\n";
        Script += "print('This is a simple template for using a SAGA tool through Python.')\n";
        Script += "print('Please edit the script to make it work properly before using it!')\n";
		Script += "\n";
		Script += "# Run_" + Name + "('.')\n";
		Script += "\n";
		Script += "# job is done, free memory resources:\n";
		Script += "saga_api.SG_Get_Data_Manager().Delete()\n";
	}

	return( Script );
}

//---------------------------------------------------------
void CSG_Tool::_Get_Script_Python(CSG_String &Script, CSG_Parameters *pParameters, bool bAllArguments, const CSG_String &Prefix)
{
	for(int iParameter=0; iParameter<pParameters->Get_Count(); iParameter++)
	{
		CSG_Parameter *p = pParameters->Get_Parameter(iParameter);

		if( !bAllArguments && (!p->is_Enabled(false) || p->is_Information() || !p->do_UseInCMD()) )
		{
			continue;
		}

		CSG_String ID(p->Get_Identifier());

		if( !Prefix.is_Empty() )
		{
			ID.Prepend(Prefix + ".");
		}

		switch( p->Get_Type() )
		{
		default:
			break;

		case PARAMETER_TYPE_Bool           :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', %s)\n", ID.c_str(), p->asBool() ? SG_T("True") : SG_T("False"));
			break;

		case PARAMETER_TYPE_Int            :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', %d)\n", ID.c_str(), p->asInt());
			break;

		case PARAMETER_TYPE_Data_Type      :
		case PARAMETER_TYPE_Choice         :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', %d) # '%s'\n", ID.c_str(), p->asInt(), p->asString());
			break;

		case PARAMETER_TYPE_Choices        :
		case PARAMETER_TYPE_Table_Field    :
		case PARAMETER_TYPE_Table_Fields   :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', '%s')\n", ID.c_str(), p->asString());
			break;

        case PARAMETER_TYPE_Color          :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', '%s')\n", ID.c_str(), SG_Color_To_Text(p->asColor()).c_str());
            break;

		case PARAMETER_TYPE_Double         :
		case PARAMETER_TYPE_Degree         :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', %g)\n", ID.c_str(), p->asDouble());
			break;

		case PARAMETER_TYPE_Range          :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s.MIN', %g)\n", ID.c_str(), p->asRange()->Get_Min());
			Script += CSG_String::Format("    Tool.Set_Parameter('%s.MAX', %g)\n", ID.c_str(), p->asRange()->Get_Max());
			break;

		case PARAMETER_TYPE_String         :
			if( ((CSG_Parameter_String *)p)->is_Password() )
			{
				Script += CSG_String::Format("    Tool.Set_Parameter('%s', '***')\n", ID.c_str());
				break;
			}

		case PARAMETER_TYPE_Date           :
		case PARAMETER_TYPE_Text           :
		case PARAMETER_TYPE_FilePath       :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', '%s')\n", ID.c_str(), p->asString());
			break;

		case PARAMETER_TYPE_FixedTable     :
			Script += CSG_String::Format("    Tool.Set_Parameter('%s', saga_api.SG_Create_Table('table.txt'))\n", ID.c_str());
			break;

		case PARAMETER_TYPE_Grid_System    :
			if( p->Get_Children_Count() == 0 )
			{
				Script += CSG_String::Format("    Tool.Set_Parameter('%s', saga_api.CSG_Grid_System(%g, %g, %g, %d, %d))\n", ID.c_str(),
					p->asGrid_System()->Get_Cellsize(),
					p->asGrid_System()->Get_XMin(), p->asGrid_System()->Get_YMin(),
					p->asGrid_System()->Get_NX  (), p->asGrid_System()->Get_NY  ()
				);
			}
			break;

		case PARAMETER_TYPE_Grid           :
		case PARAMETER_TYPE_Grids          :
		case PARAMETER_TYPE_Table          :
		case PARAMETER_TYPE_Shapes         :
		case PARAMETER_TYPE_TIN            :
		case PARAMETER_TYPE_PointCloud     :
			if( p->is_Input() )
			{
				Script += CSG_String::Format("    Tool.Set_Parameter('%s', saga_api.SG_Get_Data_Manager().Add('%s input file%s'))\n", ID.c_str(),
					SG_Get_DataObject_Name(p->Get_DataObject_Type()).c_str(), p->is_Optional() ? SG_T(", optional") : SG_T("")
				);
			}
			else if( p->is_Output() && p->is_Optional() )
			{
				Script += CSG_String::Format("    Tool.Set_Parameter('%s', saga_api.SG_Get_Create_Pointer()) # optional output, remove this line, if you don't want to create it\n", ID.c_str());
			}
			break;

		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:
			if( p->is_Input() )
			{
				Script += CSG_String::Format("    Tool.Get_Parameter('%s').asList().Add_Item('%s input list%s')\n", ID.c_str(),
					SG_Get_DataObject_Name(p->Get_DataObject_Type()).c_str(), p->is_Optional() ? SG_T(", optional") : SG_T("")
				);
			}
			break;

		case PARAMETER_TYPE_Parameters     :
			_Get_Script_Python(Script, p->asParameters(), bAllArguments, ID);
			break;
		}
	}
}


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

//---------------------------------------------------------
CSG_String CSG_Tool::_Get_Script_Python_Wrap(bool bHeader, bool bName, bool bCall, int AllArguments, bool bWrapArgs)
{
	CSG_String Arguments, Description, Code;

	if( AllArguments >= 0 ) // if( AllArguments < 0 ) => skip arguments list
	{
		for(int i=0; i<Parameters.Get_Count(); i++)	// add input that is not optional in 1st place
		{
			_Get_Script_Python_Wrap(Parameters[i], PARAMETER_INPUT         , Arguments, Description, Code, bCall && bHeader, AllArguments == 0, bWrapArgs);
		}

		for(int i=0; i<Parameters.Get_Count(); i++) // add optional input in 2nd place
		{
			_Get_Script_Python_Wrap(Parameters[i], PARAMETER_INPUT_OPTIONAL, Arguments, Description, Code, bCall && bHeader, AllArguments == 0, bWrapArgs);
		}

		for(int i=0; i<Parameters.Get_Count(); i++) // add output
		{
			_Get_Script_Python_Wrap(Parameters[i], PARAMETER_OUTPUT        , Arguments, Description, Code, bCall && bHeader, AllArguments == 0, bWrapArgs);
		}

		for(int i=0; i<Parameters.Get_Count(); i++) // add options
		{
			_Get_Script_Python_Wrap(Parameters[i], 0                       , Arguments, Description, Code, bCall           , AllArguments == 0, bWrapArgs);
		}
	}

	//---------------------------------------------------------
	CSG_String Name, Expected(Get_Name()); Expected.Replace("'", "\\'");
	
	if( bName )
	{
		Name = Get_Name();

		if( isdigit(Name[0]) ) // ...in case first letter is a numeric character, what is not allowed for Python function names!
		{
			Name.Prepend("_");
		}
	
		Name.Replace(" ", "_");
		Name.Replace("(", "");
		Name.Replace(")", "");
		Name.Replace("[", "");
		Name.Replace("]", "");
		Name.Replace(".", "");
		Name.Replace(",", "");
		Name.Replace("/", "");
		Name.Replace("-", "");
		Name.Replace("'", "");
		Name.Replace("&", "and");
	}
	else
	{
		Name = "run_tool_" + Get_Library() + "_" + Get_ID();

		Name.Replace(" ", "_");
	}

	//---------------------------------------------------------
	CSG_String Script;

	if( bCall )
	{
		if( bHeader )
		{
			Script += "from PySAGA.tools import " + Get_Library() + "\n\n";

			if( !Code.is_Empty() )
			{
				Script += Code + "\n";
			}
		}

		Script += Get_Library() + '.' + Name + "(" + Arguments + ")\n";
	}
	else
	{
		CSG_Strings _Description = SG_String_Tokenize(CSG_Text_Format_Converter::Html_to_SimpleText(Get_Description()), "\n");

		if( bHeader )
		{
			Script += "#! /usr/bin/env python\n";
			Script += "from PySAGA.helper import Tool_Wrapper\n\n";
		}

		Script += "def " + Name + "(" + Arguments + ", Verbose=2):\n";
		Script += "    '''\n";
		Script += "    " + Get_Name() + "\n";
		Script += "    ----------\n";
		Script += "    [" + Get_Library() + "." + Get_ID() + "]\\n\n";
		for(int i=0; i<_Description.Get_Count(); i++)
		{
			_Description[i].Trim_Both(); Script += "    " + _Description[i] + "\\n\n";
		}
		Script += "    Arguments\n";
		Script += "    ----------\n";
		Script += Description + "\n";
		Script += "    - Verbose [`integer number`] : Verbosity level, 0=silent, 1=tool name and success notification, 2=complete tool output.\\n\n";
		Script += "    Returns\n";
		Script += "    ----------\n";
		Script += "    `boolean` : `True` on success, `False` on failure.\n";
		Script += "    '''\n";
		Script += "    Tool = Tool_Wrapper('" + Get_Library() + "', '" + Get_ID() + "', '" + Expected + "')\n";
		Script += "    if Tool.is_Okay():\n";
		Script += Code;
		Script += "        return Tool.Execute(Verbose)\n";
		Script += "    return False\n\n";
	}

	return( Script );
}

//---------------------------------------------------------
bool CSG_Tool::_Get_Script_Python_Wrap(const CSG_Parameter &Parameter, int Constraint, CSG_String &Arguments, CSG_String &Description, CSG_String &Code, bool bCall, bool bOnlyNonDefaults, bool bWrapArgs, const CSG_String &Prefix)
{
	if( Parameter.do_UseInCMD() == false
	||  Parameter.is_Information()
	||  Parameter.Get_Type() == PARAMETER_TYPE_Node
	||  Parameter.Cmp_Identifier("PARAMETERS_GRID_SYSTEM") )
	{
		return( false );
	}

	if( bCall && !Parameter.is_Enabled() && !(Parameter.is_Output() && Parameter.Get_Parent() && Parameter.Get_Parent()->Cmp_Identifier("TARGET_SYSTEM")) )
	{
		return( false );
	}

	//-----------------------------------------------------
	CSG_String ID(Parameter.Get_Identifier());

	if( !Prefix.is_Empty() )
	{
		ID.Prepend(Prefix + ".");
	}

	CSG_String Argument(ID);

	if( Argument[0] >= '0' && Argument[0] <= '9' )
	{
		Argument.Prepend('_');
	}

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

	if( Argument.Length() > 2 )
	{
		Argument.Make_Upper();
	}

	//-----------------------------------------------------
	if( Parameter.asParameters() ) // PARAMETER_TYPE_Parameters
	{
		bool bResult = false;

		for(int i=0; i<(*Parameter.asParameters()).Get_Count(); i++)
		{
			if( _Get_Script_Python_Wrap((*Parameter.asParameters())[i], Constraint, Arguments, Description, Code, bCall, bOnlyNonDefaults, bWrapArgs, ID) )
			{
				bResult = true;
			}
		}

		return( bResult );
	}

	//-----------------------------------------------------
	if( Parameter.is_Input () && !Parameter.is_Optional() && Constraint != PARAMETER_INPUT          ) { return( false ); }
	if( Parameter.is_Input () &&  Parameter.is_Optional() && Constraint != PARAMETER_INPUT_OPTIONAL ) { return( false ); }
	if( Parameter.is_Output() &&                             Constraint != PARAMETER_OUTPUT         ) { return( false ); }
	if( Parameter.is_Option() &&                             Constraint != 0                        ) { return( false ); }

	//-----------------------------------------------------
	if( bCall )
	{
		CSG_String Value;

		if( Parameter.is_DataObject() )
		{
			Value = Parameter.Get_Identifier(); Value.Make_Lower();

			if( Parameter.is_Input() )
			{
				if( (bOnlyNonDefaults && !Parameter.asDataObject()) && Parameter.is_Optional() ) // don't add optional input that has not been set
				{
					return( false );
				}

				CSG_String File(Parameter.asDataObject() && Parameter.asDataObject()->Get_File_Name(false)
					? Parameter.asDataObject()->Get_File_Name(false) : SG_T("data object file")
				); File.Replace("\\", "/");

				Code += Value + " = saga_api.SG_Get_Data_Manager().Add_" + SG_Get_DataObject_Class_Name(Parameter.Get_DataObject_Type()).AfterFirst('_') + "('" + File + "') # input data object\n";
			}
			else // if( Parameter.is_Output() )
			{
				if( (bOnlyNonDefaults && !Parameter.asDataObject()) && Parameter.is_Optional() ) // don't add optional output that has not been requested
				{
					return( false );
				}

				Code += Value + " = saga_api.SG_Get_Data_Manager().Add_" + SG_Get_DataObject_Class_Name(Parameter.Get_DataObject_Type()).AfterFirst('_') + "() # output data object\n";
			}
		}
		else if( Parameter.is_DataObject_List() )
		{
			Value = Parameter.Get_Identifier(); Value.Make_Lower();

			if( Parameter.is_Input() )
			{
				if( (bOnlyNonDefaults && Parameter.asList()->Get_Item_Count() < 1) && Parameter.is_Optional() ) // don't add optional input that has not been set
				{
					return( false );
				}

				Code += Value + " = [] # Python list with input data objects of type 'saga_api." + SG_Get_DataObject_Class_Name(Parameter.Get_DataObject_Type()) + "'\n";
			}
			else // if( Parameter.is_Output() )
			{
				Code += Value + " = [] # Python list, will become filled after successful execution with output data objects of type 'saga_api." + SG_Get_DataObject_Class_Name(Parameter.Get_DataObject_Type()) + "'\n";
			}
		}
		else if( Parameter.is_Option() )
		{
			if( bOnlyNonDefaults && Parameter.is_Default() )
			{
				return( false );
			}

			switch( Parameter.Get_Type() )
			{
			case PARAMETER_TYPE_Bool        : Value = Parameter.asBool() ? "True" : "False"; break;

			case PARAMETER_TYPE_Int         : Value.Printf("%d", Parameter.asInt()); break;

			case PARAMETER_TYPE_Double      :
			case PARAMETER_TYPE_Degree      : Value.Printf("%f", Parameter.asDouble()); break;

			case PARAMETER_TYPE_Color       : Value = SG_Color_To_Text(Parameter.asColor()); break;

			case PARAMETER_TYPE_String      :
			case PARAMETER_TYPE_Text        :
			case PARAMETER_TYPE_Date        :
			case PARAMETER_TYPE_Range       :
			case PARAMETER_TYPE_Data_Type   :
			case PARAMETER_TYPE_Choice      :
			case PARAMETER_TYPE_Choices     :
			case PARAMETER_TYPE_Table_Field :
			case PARAMETER_TYPE_Table_Fields:
			case PARAMETER_TYPE_FilePath    : Value.Printf("'%s'", Parameter.asString()); break;

			case PARAMETER_TYPE_Grid_System :
				if( !Parameter.Cmp_Identifier("TARGET_SYSTEM") )
				{
					return( false );
				}

				Value.Printf("'%s'", Parameter.asGrid_System()->asString());
				break;

			default                         : return( false );
			}
		}

		if( !Value.is_Empty() )
		{
			if( bWrapArgs )
			{
				Arguments += !Arguments.is_Empty() ? ",\n    " : "\n    ";
			}
			else if( !Arguments.is_Empty() )
			{
				Arguments += ", ";
			}

			Arguments += Argument + "=" + Value;
		}

		return( true );
	}

	//-----------------------------------------------------
	if( bWrapArgs )
	{
		Arguments += !Arguments.is_Empty() ? ",\n    " : "\n    ";
	}
	else if( !Arguments.is_Empty() )
	{
		Arguments += ", ";
	}

	Arguments += Argument + "=None";

	//-----------------------------------------------------
	Code += "        ";

	if( Parameter.is_Input () ) { Code += "Tool.Set_Input "; }
	if( Parameter.is_Output() ) { Code += "Tool.Set_Output"; }
	if( Parameter.is_Option() ) { Code += "Tool.Set_Option"; }

	Code += CSG_String::Format("('%s', %s)\n", ID.c_str(), Argument.c_str());

	//-----------------------------------------------------
	Description += "    - " + Argument + " [`";

	if( Parameter.is_Input() )
	{
		Description += Parameter.is_Optional() ? "optional input " : "input ";
	}
	else if( Parameter.is_Output() )
	{
		Description += "output ";
	}

	Description += Parameter.Get_Type_Name() + "`] : " + Parameter.Get_Name();

	CSG_String s(Parameter.Get_Description(PARAMETER_DESCRIPTION_PROPERTIES|PARAMETER_DESCRIPTION_TEXT, SG_T(" ")));

	if( !s.is_Empty() )
	{
		Description += ". " + s;
	}

	Description += "\n";

	return( true );
}

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

//---------------------------------------------------------
CSG_String CSG_Tool::_Get_Script_Markdown(bool bHeader, int iArguments)
{
	CSG_String Script;

	if( bHeader )
	{
		CSG_String            Menu = Get_MenuPath(true); Menu.Replace("|", " &rarr; ");
		CSG_Tool_Library *pLibrary = SG_Get_Tool_Library_Manager().Get_Library(this);
		CSG_String        Category = pLibrary->Get_Category() + " &rarr; " + pLibrary->Get_Name();

		Script += CSG_String::Format("**Tool:** %s  \n", Get_Name().c_str());
		Script += CSG_String::Format("**Geoprocessing** &rarr; *%s*&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp; **Tools** &rarr; *%s*\n\n", Menu.c_str(), Category.c_str());
	}

	Script += "|**Parameter**|**Setting**|\n";
	Script += "|---|---|\n";

	//-------------------------------------------------
	_Get_Script_Markdown(Script, Get_Parameters(), iArguments);

	Script.Replace("\n\n", "\n");

	return( Script );
}


//---------------------------------------------------------
void CSG_Tool::_Get_Script_Markdown(CSG_String &Script, CSG_Parameters *pParameters, int iArguments, const CSG_String &Prefix)
{	
	#define WRITE_CHILD(pChild, Prefix) Script += CSG_String::Format("|%s%s||\n", Prefix.c_str(), pChild->Get_Name().c_str());\
	for (int i=0; i<pChild->Get_Children_Count(); i++)\
	{\
		Script += CSG_String::Format("%s\n", pChild->Get_Child(i)->Get_Content().c_str());\
	}

	CSG_MetaData	Properties;
	
	for(int iParameter=0; iParameter<pParameters->Get_Count(); iParameter++)
	{
		_Format_Markdown(pParameters->Get_Parameter(iParameter), Script, Properties, iArguments, Prefix);
	}
	
	if( CSG_MetaData *pChild = Properties.Get_Child(_TL("Data Objects")) ) { WRITE_CHILD(pChild, Prefix); }

	for (int i=0; i<Properties.Get_Children_Count(); i++)
	{
		CSG_MetaData *pChild = Properties.Get_Child(i);

		if( pChild->Get_Name().Cmp(_TL("Data Objects")) && pChild->Get_Name().Cmp(_TL("Options")) )
		{
			WRITE_CHILD(pChild, Prefix);
		}
	}

	if( CSG_MetaData *pChild = Properties.Get_Child(_TL("Options")) ) { WRITE_CHILD(pChild, Prefix); }
}


//---------------------------------------------------------
void CSG_Tool::_Format_Markdown(CSG_Parameter *p, CSG_String &Script, CSG_MetaData &Properties, int iArguments, CSG_String Prefix)
{
	#define CHECK_OBJECTS_NODE() pChild = Properties.Get_Child(_TL("Options"));\
	if( !pChild )\
	{\
		pChild = Properties.Add_Child(_TL("Options"));\
	}\
	\
	pRoot = pChild;

	#define CHECK_DATA_NODE(Name) pChild = Properties.Get_Child(Name);\
	if( !pChild )\
	{\
		CSG_MetaData *pData = Properties.Get_Child(_TL("Data Objects"));\
		if( !pData )\
		{\
			Properties.Add_Child(_TL("Data Objects"));\
		}\
		pChild = Properties.Add_Child(Name);\
	}\
	\
	pRoot = pChild;

	#define GET_PARENT_NODE(prt) bool bFound = false;\
	for (int i=0; i<Properties.Get_Children_Count(); i++)\
	{\
		CSG_MetaData *pDatatype = Properties.Get_Child(i);\
		for (int j=0; j<Properties.Get_Children_Count(); j++)\
		{\
			pParent = pDatatype->Get_Child(prt);\
			if( pParent )\
			{\
				bFound = true;\
				break;\
			}\
		}\
		if( bFound )\
		{\
			break;\
		}\
	}

	#define	FORMAT_DATASET() if( p->is_Input() )\
	{\
		CSG_String Input = p->is_Optional() ? ">" : ">>";\
		CSG_String s = p->asString();\
		if( s.Contains(_TL("not set")) || s.Contains(_TL("No objects")) )	{ Bold = ""; }\
		s.Replace("<", "\\<");\
		Parameter = CSG_String::Format("|%s%s %s%s%s|%s%s%s|", Space.c_str(), Input.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());\
	}\
	else if( p->is_Output() )\
	{\
		CSG_String Output = p->is_Optional() ? "\\<" : "<<";\
		CSG_String s = p->asString();\
		if( !p->is_Optional() && s.Contains(_TL("create")) )	{ Bold = ""; }\
		else if( p->is_Optional() && (s.Contains(_TL("not set")) || s.Contains(_TL("No objects"))) )	{ Bold = ""; }\
		s.Replace("<", "\\<");\
		Parameter = CSG_String::Format("|%s%s %s%s%s|%s%s%s|", Space.c_str(), Output.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());\
	}

	if( iArguments == 0 && !p->do_UseInCMD() )
	{
		return;
	}
	else if( iArguments == 1 && !p->do_UseInGUI() )
	{
		return;
	}

	if( !p->is_Enabled(false) )
	{
		return;
	}
	
	CSG_String Name(p->Get_Name());

	CSG_String Bold;
	
	if( !p->is_Default() )
	{
		Bold = "**";
	}

	CSG_String Space = Prefix;

	if( p->Get_Parent() != NULL )
	{
		Space += "&nbsp;&nbsp;&nbsp;";
	}
	
	CSG_String   Parameter;
	CSG_MetaData *pRoot = NULL, *pChild;

	switch( p->Get_Type() )
	{
	default:
		break;

	case PARAMETER_TYPE_Grid_System    :
		{
		if( p->Get_Parent() )
		{
			CHECK_OBJECTS_NODE();
		}
		else if( p->Get_Children_Count() == 0 )
		{
			CHECK_DATA_NODE(_TL("Grids"));
		}
		else for (int i=0; i<p->Get_Children_Count() && !pRoot; i++)
		{
			if(	(p->Get_Child(i)->Get_Type() != PARAMETER_TYPE_Grid_List
			  && p->Get_Child(i)->Get_Type() != PARAMETER_TYPE_Grids_List)
			||   p->Get_Child(i)->is_Input() )
			{
				CHECK_DATA_NODE(_TL("Grids"));
			}
		}
			
		CSG_String s = p->asString();
		if( s.Contains(_TL("not set")) )
		{
			s.Replace("<", "\\<");
			Parameter += CSG_String::Format("|%s%s|%s|", Space.c_str(), Name.c_str(), s.c_str());
		}
		else
		{
			Parameter += CSG_String::Format("|%s%s%s%s|%s%g; %dx, %dy; %.0f...x %.0f...y%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(),
				p->asGrid_System()->Get_Cellsize(),
				p->asGrid_System()->Get_NX  (), p->asGrid_System()->Get_NY  (),
				p->asGrid_System()->Get_XMin(), p->asGrid_System()->Get_YMin(),
				Bold.c_str()
			);
		}
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;
		}

	case PARAMETER_TYPE_Grid_List      :
	case PARAMETER_TYPE_Grids_List     :
		if( p->is_Input() )
		{
			if( !p->Get_Parent() || (p->Get_Parent()->Get_Type() == PARAMETER_TYPE_Grid_System && !p->Get_Parent()->Get_Parent()) )
			{
				CHECK_DATA_NODE(_TL("Grids"));
			}
			else
			{
				CHECK_OBJECTS_NODE();
			}
			FORMAT_DATASET();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;

	case PARAMETER_TYPE_Grid           :
	case PARAMETER_TYPE_Grids          :
		if( !p->Get_Parent() || (p->Get_Parent()->Get_Type() == PARAMETER_TYPE_Grid_System && !p->Get_Parent()->Get_Parent()) )
		{
			CHECK_DATA_NODE(_TL("Grids"));
		}
		else
		{
			CHECK_OBJECTS_NODE();
		}
		FORMAT_DATASET();
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;
		
	case PARAMETER_TYPE_Table_List     :
		if( p->is_Input() )
		{
			if( !p->Get_Parent() )
			{
				CHECK_DATA_NODE(_TL("Tables"));
			}
			else
			{
				CHECK_OBJECTS_NODE();
			}
			FORMAT_DATASET();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;

	case PARAMETER_TYPE_Table          :
		if( !p->Get_Parent() )
		{
			CHECK_DATA_NODE(_TL("Tables"));
		}
		else
		{
			CHECK_OBJECTS_NODE();
		}
		FORMAT_DATASET();
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Shapes_List     :
		if( p->is_Input() )
		{
			if( !p->Get_Parent() )
			{
				CHECK_DATA_NODE(_TL("Shapes"));
			}
			else
			{
				CHECK_OBJECTS_NODE();
			}
			FORMAT_DATASET();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;

	case PARAMETER_TYPE_Shapes          :
		if( !p->Get_Parent() )
		{
			CHECK_DATA_NODE(_TL("Shapes"));
		}
		else
		{
			CHECK_OBJECTS_NODE();
		}
		FORMAT_DATASET();
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_TIN_List     :
		if( p->is_Input() )
		{
			if( !p->Get_Parent() )
			{
				CHECK_DATA_NODE(_TL("TIN"));
			}
			else
			{
				CHECK_OBJECTS_NODE();
			}
			FORMAT_DATASET();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;

	case PARAMETER_TYPE_TIN          :
		if( !p->Get_Parent() )
		{
			CHECK_DATA_NODE(_TL("TIN"));
		}
		else
		{
			CHECK_OBJECTS_NODE();
		}
		FORMAT_DATASET();
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_PointCloud_List:
		if( p->is_Input() )
		{
			if( !p->Get_Parent() )
			{
				CHECK_DATA_NODE(_TL("Point Clouds"));
			}
			else
			{
				CHECK_OBJECTS_NODE();
			}
			FORMAT_DATASET();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;

	case PARAMETER_TYPE_PointCloud     :
		if( !p->Get_Parent() )
		{
			CHECK_DATA_NODE(_TL("Point Clouds"));
		}
		else
		{
			CHECK_OBJECTS_NODE();
		}
		FORMAT_DATASET();
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Node           :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s||", Space.c_str(), Name.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Bool           :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), p->asBool() ? SG_T("&#x1f5f9;") : SG_T("&#x2610;"), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Int            :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%d%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), p->asInt(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Data_Type      :
	case PARAMETER_TYPE_Choice         :
		{
		CHECK_OBJECTS_NODE();
		CSG_String s = p->asString();
		if( s.Contains(_TL("no choice available")) )	{ Bold = ""; }
		s.Replace("<", "\\<");
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;
		}

	case PARAMETER_TYPE_Table_Field    :
		{
		CSG_String s = p->asString();
		if( s.Contains(_TL("no attributes")) )	{ Bold = ""; }
		s.Replace("<", "\\<");
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());
		if( p->Get_Parent() != NULL && (p->Get_Parent()->is_DataObject() || p->Get_Parent()->is_DataObject_List()) )
		{
			CSG_MetaData *pParent = NULL;
			GET_PARENT_NODE(p->Get_Parent()->Get_Identifier());
			if( pParent )
			{
				CSG_String c = pParent->Get_Content();
				c += SG_T("\n") + Parameter;
				pParent->Set_Content(c);
			}
		}
		else
		{
			CHECK_OBJECTS_NODE();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;
		}

	case PARAMETER_TYPE_Choices        :
	case PARAMETER_TYPE_Table_Fields   :
		{
		CSG_String s = p->asString();
		s.Replace("<", "\\<");
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());
		if( p->Get_Parent() != NULL && (p->Get_Parent()->is_DataObject() || p->Get_Parent()->is_DataObject_List()) )
		{
			CSG_MetaData *pParent = NULL;
			GET_PARENT_NODE(p->Get_Parent()->Get_Identifier());
			if( pParent )
			{
				CSG_String c = pParent->Get_Content();
				c += SG_T("\n") + Parameter;
				pParent->Set_Content(c);
			}
		}
		else
		{
			CHECK_OBJECTS_NODE();
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		}
		break;
		}

    case PARAMETER_TYPE_Color          :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), SG_Color_To_Text(p->asColor()).c_str(), Bold.c_str());
        if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Double         :
	case PARAMETER_TYPE_Degree         :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%g%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), p->asDouble(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Range          :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%g;%g%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), p->asRange()->Get_Min(), p->asRange()->Get_Max(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_String         :
		if( ((CSG_Parameter_String *)p)->is_Password() )
		{
			CHECK_OBJECTS_NODE();
			Parameter = CSG_String::Format("|%s%s%s%s|%s***%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), Bold.c_str());
			if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
			break;
		}

	case PARAMETER_TYPE_Date           :
	case PARAMETER_TYPE_Text           :
	case PARAMETER_TYPE_FilePath       :
		{
		CHECK_OBJECTS_NODE();
		CSG_String s = p->asString();
		s.Replace("\\", "/");
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), s.c_str(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;
		}

	case PARAMETER_TYPE_FixedTable     :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s%s%s|%s%s%s|", Space.c_str(), Bold.c_str(), Name.c_str(), Bold.c_str(), Bold.c_str(), p->asString(), Bold.c_str());
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;

	case PARAMETER_TYPE_Parameters     :
		CHECK_OBJECTS_NODE();
		Parameter = CSG_String::Format("|%s%s||\n", Space.c_str(), Name.c_str());
		CSG_String Prefix = Space + "&nbsp;&nbsp;&nbsp;";
		_Get_Script_Markdown(Parameter, p->asParameters(), iArguments, Prefix);
		if( pRoot )	{ pRoot->Add_Child(p->Get_Identifier(), Parameter); }
		break;
	}

	return;
}

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

//---------------------------------------------------------
CSG_MetaData CSG_Tool::Get_History(int Depth)
{
	CSG_MetaData History;

	History.Set_Name(SG_META_HISTORY);
	History.Add_Property("saga-version", SAGA_VERSION);

	if( Depth )
	{
		CSG_MetaData *pTool = History.Add_Child("TOOL");

		pTool->Add_Property("library", Get_Library());
		pTool->Add_Property("id"     , Get_ID     ());
		pTool->Add_Property("name"   , Get_Name   ());

		Parameters.Set_History(*pTool);

		pTool->Add_Children(History_Supplement);

		CSG_MetaData *pOutput = pTool->Add_Child("OUTPUT");
		pOutput->Add_Property("type", "");
		pOutput->Add_Property("id"  , "");
		pOutput->Add_Property("name", "");

		pTool->Del_Children(Depth, SG_T("TOOL"));
	}

	return( History );
}

//---------------------------------------------------------
bool CSG_Tool::Set_History(CSG_Data_Object *pDataObject, int Depth)
{
	if( pDataObject )
	{
		CSG_MetaData History(Get_History(Depth));

		CSG_MetaData *pOutput = History("TOOL") ? History["TOOL"]("OUTPUT") : NULL;

		if( pOutput )
		{
			pOutput->Set_Property("name", pDataObject->Get_Name());
		}

		pDataObject->Get_History() = History;

		return( true );
	}

	return( false );
}

//---------------------------------------------------------
void CSG_Tool::_Set_Output_History(void)
{
	CSG_MetaData History(Get_History(SG_Get_History_Depth()));

	for(int j=-1; j<Get_Parameters_Count(); j++)
	{
		CSG_Parameters *pParameters = j < 0 ? &Parameters : Get_Parameters(j);

		for(int i=0; i<pParameters->Get_Count(); i++)
		{
			CSG_Parameter *pParameter = pParameters->Get_Parameter(i);

			if( pParameter->is_Output() )//&& (pParameter->is_Enabled() || !has_GUI()) )
			{
				DataObject_Set_History(pParameter, &History);
			}
		}
	}
}

//---------------------------------------------------------
bool CSG_Tool::DataObject_Set_History(CSG_Parameter *pParameter, CSG_MetaData *pHistory)
{
	if( !pParameter && !((pParameter->is_DataObject() && pParameter->asDataObject()) || !(pParameter->is_DataObject_List() && pParameter->asList()->Get_Item_Count() > 0)) )
	{
		return( false );
	}

	//-----------------------------------------------------
	CSG_MetaData History;

	if( !pHistory )
	{
		History = Get_History(SG_Get_History_Depth()); pHistory = &History;
	}

	//-----------------------------------------------------
	CSG_MetaData *pOutput = pHistory->Get_Child("TOOL") ? pHistory->Get_Child("TOOL")->Get_Child("OUTPUT") : NULL;

	if( pOutput )
	{
		pOutput->Set_Property("type", pParameter->Get_Type_Identifier());
		pOutput->Set_Property("id"  , pParameter->Get_Identifier     ());
		pOutput->Set_Property("name", pParameter->Get_Name           ());
	}

	//-----------------------------------------------------
	if( pParameter->is_DataObject() && pParameter->asDataObject() )
	{
		if( pOutput )
		{
			pOutput->Set_Content(pParameter->asDataObject()->Get_Name());
		}

		pParameter->asDataObject()->Get_History().Assign(*pHistory);
	}

	//-----------------------------------------------------
	else if( pParameter->is_DataObject_List() )
	{
		for(int j=0; j<pParameter->asList()->Get_Item_Count(); j++)
		{
			if( pOutput )
			{
				pOutput->Set_Content(pParameter->asList()->Get_Item(j)->Get_Name());
			}

			pParameter->asList()->Get_Item(j)->Get_History().Assign(*pHistory);
		}
	}

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


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

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