
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                     Tool Library                      //
//                     Grid_Tools                        //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                    Grid_Tiling.cpp                    //
//                                                       //
//                 Copyright (C) 2010 by                 //
//                      Olaf Conrad                      //
//                                                       //
//-------------------------------------------------------//
//                                                       //
// This file is part of 'SAGA - System for Automated     //
// Geoscientific Analyses'. SAGA is free software; you   //
// can redistribute it and/or modify it under the terms  //
// of the GNU General Public License as published by the //
// Free Software Foundation, either version 2 of the     //
// License, or (at your option) any later version.       //
//                                                       //
// SAGA 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 General Public        //
// License for more details.                             //
//                                                       //
// You should have received a copy of the GNU General    //
// Public License along with this program; if not, see   //
// <http://www.gnu.org/licenses/>.                       //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//    e-mail:     oconrad@saga-gis.org                   //
//                                                       //
//    contact:    Olaf Conrad                            //
//                Institute of Geography                 //
//                University of Hamburg                  //
//                Germany                                //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#include "Grid_Tiling.h"


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

//---------------------------------------------------------
CGrid_Tiling::CGrid_Tiling(void)
{
	Set_Name		(_TL("Tiling"));

	Set_Author		("O.Conrad (c) 2010");

	Set_Description	(_TW(
		""
	));

	//-----------------------------------------------------
	Parameters.Add_Grid("",
		"GRID"       , _TL("Grid"),
		_TL(""),
		PARAMETER_INPUT
	);

	Parameters.Add_Grid_List("",
		"TILES"      , _TL("Tiles"),
		_TL(""),
		PARAMETER_OUTPUT, false
	);

	//-----------------------------------------------------
	Parameters.Add_Bool("",
		"TILES_SAVE" , _TL("Save Tiles to Disk"),
		_TL("Save tiles to disk individually"),
		false
	);

	Parameters.Add_FilePath("TILES_SAVE",
		"TILES_PATH" , _TL("Output Directory"),
		_TL(""),
		NULL, NULL, true, true
	);

	Parameters.Add_String("TILES_SAVE",
		"TILES_NAME" , _TL("Base Name"),
		_TL("The base name of the tiles"),
		"tile"
	);

	//-----------------------------------------------------
	Parameters.Add_Int("",
		"OVERLAP"    , _TL("Overlapping Cells"),
		_TL(""),
		0, 0, true
	);

	Parameters.Add_Choice("OVERLAP",
		"OVERLAP_SYM", _TL("Add Cells"),
		_TL(""),
		CSG_String::Format("%s|%s|%s",
			_TL("symmetric"),
			_TL("bottom / left"),
			_TL("top / right")
		), 0
	);

	//-----------------------------------------------------
	Parameters.Add_Choice("",
		"METHOD"     , _TL("Tile Size Definition"),
		_TL(""),
		CSG_String::Format("%s|%s",
			_TL("number of grid cells per tile"),
			_TL("coordinates (offset, range, cell size, tile size)")
		), 0
	);

	//-----------------------------------------------------
	Parameters.Add_Int   ("METHOD", "NX"    , _TL("Number of Column Cells"), _TL(""), 100, 1, true);
	Parameters.Add_Int   ("METHOD", "NY"    , _TL("Number of Row Cells"   ), _TL(""), 100, 1, true);

	Parameters.Add_Range ("METHOD", "XRANGE", _TL("Offset and Range (X)"  ), _TL(""), 0., 1000.);
	Parameters.Add_Range ("METHOD", "YRANGE", _TL("Offset and Range (Y)"  ), _TL(""), 0., 1000.);

	Parameters.Add_Double("METHOD", "DCELL" , _TL("Cell Size"             ), _TL(""), 1., 0., true);

	Parameters.Add_Double("METHOD", "DX"    , _TL("Tile Size (X)"         ), _TL(""), 100., 0., true);
	Parameters.Add_Double("METHOD", "DY"    , _TL("Tile Size (Y)"         ), _TL(""), 100., 0., true);
}


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

//---------------------------------------------------------
int CGrid_Tiling::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	if(	pParameter == pParameters->Get_Grid_System_Parameter() )
	{
		CSG_Grid_System	System(1., 0., 0., 101, 101);

		if( pParameter->asGrid_System() && pParameter->asGrid_System()->is_Valid() )
		{
			System = *pParameter->asGrid_System();
		}

		pParameters->Set_Parameter("NX"        , System.Get_NX() / 2     );
		pParameters->Set_Parameter("NY"        , System.Get_NX() / 2     );
		pParameters->Set_Parameter("XRANGE.MIN", System.Get_XMin()       );
		pParameters->Set_Parameter("XRANGE.MAX", System.Get_XMax()       );
		pParameters->Set_Parameter("YRANGE.MIN", System.Get_YMin()       );
		pParameters->Set_Parameter("YRANGE.MAX", System.Get_YMax()       );
		pParameters->Set_Parameter("DCELL"     , System.Get_Cellsize()   );
		pParameters->Set_Parameter("DX"        , System.Get_XRange() / 2.);
		pParameters->Set_Parameter("DY"        , System.Get_YRange() / 2.);
	}

	//-----------------------------------------------------
	return( CSG_Tool_Grid::On_Parameter_Changed(pParameters, pParameter) );
}

//---------------------------------------------------------
int CGrid_Tiling::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	if( pParameter->Cmp_Identifier("TILES_SAVE") )
	{
		pParameters->Set_Enabled("TILES_PATH", pParameter->asBool());
		pParameters->Set_Enabled("TILES_NAME", pParameter->asBool());
	}

	if( pParameter->Cmp_Identifier("OVERLAP") )
	{
		pParameters->Set_Enabled("OVERLAP_SYM", pParameter->asInt() > 0);
	}

	if( pParameter->Cmp_Identifier("METHOD") )
	{
		pParameters->Set_Enabled("NX"    , pParameter->asInt() == 0);
		pParameters->Set_Enabled("NY"    , pParameter->asInt() == 0);

		pParameters->Set_Enabled("XRANGE", pParameter->asInt() == 1);
		pParameters->Set_Enabled("YRANGE", pParameter->asInt() == 1);
		pParameters->Set_Enabled("DCELL" , pParameter->asInt() == 1);
		pParameters->Set_Enabled("DX"    , pParameter->asInt() == 1);
		pParameters->Set_Enabled("DY"    , pParameter->asInt() == 1);
	}

	//-----------------------------------------------------
	return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
}


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

//---------------------------------------------------------
bool CGrid_Tiling::On_Execute(void)
{
	CSG_Grid *pGrid = Parameters("GRID")->asGrid();

	int nx, ny; double dx, dy, dCell; TSG_Rect Extent; CSG_Grid_Resampling Resampling;

	switch( Parameters("METHOD")->asInt() )
	{
	default: // number of grid cells per tile
		Extent.xMin = pGrid->Get_XMin();
		Extent.xMax = pGrid->Get_XMax();
		Extent.yMin = pGrid->Get_YMin();
		Extent.yMax = pGrid->Get_YMax();
		dCell       = pGrid->Get_Cellsize();
		nx          = Parameters("NX")->asInt();
		ny          = Parameters("NY")->asInt();
		dx          = dCell * nx;
		dy          = dCell * ny;
		Resampling  = CSG_Grid_Resampling::NearestNeighbour;
		break;

	case  1: // coordinates (offset, range, cell size, tile size)
		Extent.xMin = Parameters("XRANGE")->asRange()->Get_Min();
		Extent.xMax = Parameters("XRANGE")->asRange()->Get_Max();
		Extent.yMin = Parameters("YRANGE")->asRange()->Get_Min();
		Extent.yMax = Parameters("YRANGE")->asRange()->Get_Max();
		dCell       = Parameters("DCELL" )->asDouble();
		dx          = Parameters("DX"    )->asDouble();
		dy          = Parameters("DY"    )->asDouble();
		nx          = (int)(dx / dCell);
		ny          = (int)(dy / dCell);
		Resampling = CSG_Grid_Resampling::Undefined;
		break;
	}

	//-----------------------------------------------------
	if( dx <= 0. || dy <= 0. || dCell <= 0. )
	{
		Message_Add(_TL("no intersection with mask grid."));

		return( false );
	}

	//-----------------------------------------------------
	int	Overlap	= Parameters("OVERLAP")->asInt();

	switch( Parameters("OVERLAP_SYM")->asInt() )
	{
	default: // symmetric
		nx     += Overlap * 2;
		ny     += Overlap * 2;
		break;

	case  1:	// bottom / left
		nx     += Overlap;
		ny     += Overlap;
		break;

	case  2: // top / right
		nx     += Overlap;
		ny     += Overlap;
		Overlap = 0;
		break;
	}

	//-----------------------------------------------------
	CSG_String Tiles_Name, Tiles_Path;

	bool Tiles_bSave = Parameters("TILES_SAVE")->asBool();

	if( Tiles_bSave )
	{
		Tiles_Name = Parameters("TILES_NAME")->asString();

		if( Tiles_Name.is_Empty() )
		{
			SG_UI_Msg_Add_Error(_TL("Please provide a valid base name for the output files!"));

			return( false );
		}

		Tiles_Path = Parameters("TILES_PATH")->asString();

		if( !SG_Dir_Exists(SG_File_Get_Path(Tiles_Path)) )
		{
			SG_UI_Msg_Add_Error(_TL("Please provide a valid output directory for the output files!"));

			return( false );
		}
	}


	//-----------------------------------------------------
	CSG_Parameter_Grid_List *pTiles = Parameters("TILES")->asGridList(); pTiles->Del_Items();

	int iy = 1, nTiles = 0;

	for(double y=Extent.yMin; y<Extent.yMax && Process_Get_Okay(); y+=dy, iy++)
	{
		int	ix = 1;

		for(double x=Extent.xMin; x<Extent.xMax; x+=dx, ix++)
		{
			CSG_Grid *pTile = SG_Create_Grid(pGrid->Get_Type(), nx, ny, dCell,
				x - dCell * Overlap,
				y - dCell * Overlap
			);

			pTile->Assign(pGrid, Resampling);

			if( pTile->Get_NoData_Count() == pTile->Get_NCells() )
			{
				delete(pTile);
			}
			else
			{
				if( Tiles_bSave )
				{
					CSG_String FileName = CSG_String::Format("%s/%s_%d_%d.sgrd", Tiles_Path.c_str(), Tiles_Name.c_str(), iy, ix);

					pTile->Save(FileName);

					delete(pTile);
				}
				else
				{
					pTile->Fmt_Name("%s [%d, %d]", pGrid->Get_Name(), iy, ix);

					pTiles->Add_Item(pTile);
				}

				nTiles++;
			}
		}
	}

	SG_UI_Msg_Add(CSG_String::Format("%s: %d", _TL("Number of tiles"), nTiles), true);

	return( nTiles > 0 );
}


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

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