
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                     Tool Library                      //
//                      grid_tools                       //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//              Grid_Value_Extract_Bits.cpp              //
//                                                       //
//                 Copyrights (C) 2025                   //
//                     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_Value_Extract_Bits.h"


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

//---------------------------------------------------------
CGrid_Value_Extract_Bits::CGrid_Value_Extract_Bits(void)
{
	Set_Name		(_TL("Extract Bits from Grid Values"));

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

	Set_Description	(_TW(
		"Use this tool to extract single bits from grid values. "
	));

	//-----------------------------------------------------
	Parameters.Add_Grid     ("", "GRID"     , _TL("Grid"     ), _TL(""), PARAMETER_INPUT );
	Parameters.Add_Grid_List("", "BITS"     , _TL("Bits"     ), _TL(""), PARAMETER_OUTPUT);
	Parameters.Add_Grid     ("", "COUNT"    , _TL("Count"    ), _TL(""), PARAMETER_OUTPUT, true, SG_DATATYPE_Byte);

	Parameters.Add_Choice   ("", "OUTPUT"   , _TL("Output"   ), _TL(""), CSG_String::Format("%s|%s|%s", _TL("bits"), _TL("bits and count"), _TL("count")), 1);
	Parameters.Add_Choice   ("", "DATATYPE" , _TL("Data Type"), _TL(""), CSG_String::Format("%s|%s"   , _TL("bit"), _TL("unsigned 1 byte integer")), 0);
	Parameters.Add_Choice   ("", "SELECTION", _TL("Extract"  ), _TL(""), CSG_String::Format("%s|%s"   , _TL("all bits"), _TL("selected bits")), 0);

	for(int i=1; i<=64; i++)
	{
		Parameters.Add_Bool("SELECTION", CSG_String::Format("BIT%02d", i), CSG_String::Format("%s %2d", _TL("Bit"), i), _TL(""), false);
	}
}


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

//---------------------------------------------------------
int CGrid_Value_Extract_Bits::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
{
	if( pParameter->Cmp_Identifier("OUTPUT") )
	{
		pParameters->Set_Enabled("COUNT"   , pParameter->asInt() >= 1);
		pParameters->Set_Enabled("DATATYPE", pParameter->asInt() <= 1);
	}

	if(	pParameter->Cmp_Identifier("GRID") || pParameter->Cmp_Identifier("SELECTION") )
	{
		CSG_Grid *pGrid = (*pParameters)["GRID"].asGrid(); CSG_Parameter &Selection = (*pParameters)["SELECTION"]; 

		if( pGrid == NULL || Selection.asInt() == 0 )
		{
			Selection.Set_Children_Enabled(false);
		}
		else
		{
			for(int i=0, n=8*(int)SG_Data_Type_Get_Size(pGrid->Get_Type()); i<Selection.Get_Children_Count(); i++)
			{
				Selection.Get_Child(i)->Set_Enabled(i < n);
			}
		}
	}

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


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

//---------------------------------------------------------
bool CGrid_Value_Extract_Bits::On_Execute(void)
{
	CSG_Grid *pGrid = Parameters["GRID"].asGrid(), *pCount = NULL; CSG_Parameter_Grid_List *pBits = NULL;

	if( Parameters["OUTPUT"].asInt() <= 1 )
	{
		pBits = Parameters["BITS"].asGridList(); pBits->Del_Items();
	}

	if( Parameters["OUTPUT"].asInt() >= 1 )
	{
		pCount = Parameters["COUNT"].asGrid();
	}

	//-----------------------------------------------------
	CSG_Array_Int Bits;

	for(int i=0, n=8*(int)SG_Data_Type_Get_Size(pGrid->Get_Type()); i<n; i++)
	{
		if( Parameters["SELECTION"].asInt() == 0 || Parameters["SELECTION"].Get_Child(i)->asBool() )
		{
			Bits += 1 << i;

			if( pBits )
			{
				CSG_Grid *pBit = SG_Create_Grid(Get_System(), Parameters["DATATYPE"].asInt() == 0 ? SG_DATATYPE_Bit : SG_DATATYPE_Byte);

				pBit->Fmt_Name("%s [%s %02d]", pGrid->Get_Name(), _TL("Bit"), i + 1);

				pBits->Add_Item(pBit);
			}
		}
	}

	if( Bits.Get_Size() < 1 )
	{
		Error_Fmt("%s\n%s", _TL("Nothing to do!"), _TL("no bits in selection."));

		return( false );
	}

	//-----------------------------------------------------
	for(int y=0; y<Get_NY() && Set_Progress(y); y++)
	{
		#pragma omp parallel for
		for(int x=0; x<Get_NX(); x++)
		{
			sLong Value = pGrid->asLong(x, y); int Count = 0;

			for(int i=0; i<(int)Bits.Get_Size(); i++)
			{
				bool bOn = Value & Bits[i];

				if( bOn )
				{
					Count++;
				}

				if( pBits->Get_Grid(i) )
				{
					pBits->Get_Grid(i)->Set_Value(x, y, bOn ? 1 : 0);
				}
			}

			if( pCount )
			{
				pCount->Set_Value(x, y, Count);
			}
		}
	}

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


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

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