#include "menu_db.h"
#include "convert_sl.h"

#include "saga_gui/saga_frame.h"
#include "saga_gui/helper.h"			// using function MSG_General_Add()
#define MSG_ADD(s)	MSG_General_Add(s, true, true);

#include <fstream>

/////////////////////////////////////////////////////////////////////////////
//
// Converting a SimpleFeature from a PostgrSQL database to SAGA Shapefile
//
/////////////////////////////////////////////////////////////////////////////
bool Cmenu_db::Create_Shape_From_SF(CSG_Shapes *pShapes)
{
	CSG_Table_Record	*pRecord;

	//-----------------------------------------------------------------
	// Set SHAPE_TYPE
	// GeoType is defined in simple_feature.h as SF_TGeometry
	//-----------------------------------------------------------------
	switch (m_pSimpleFeature->GetGeoType())
	{
		default: 
			return(false);
		// Multi-features are not yet implemented
		case 1: pShapes->Create(SHAPE_TYPE_Points,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		case 2: pShapes->Create(SHAPE_TYPE_Line,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		case 3: pShapes->Create(SHAPE_TYPE_Polygon,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		case 4: pShapes->Create(SHAPE_TYPE_Points,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		case 5: pShapes->Create(SHAPE_TYPE_Line,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		case 6: pShapes->Create(SHAPE_TYPE_Polygon,	m_pSimpleFeature->GetFeatureName().c_str()); break;
		//case 7: // SF_GeometryCollection not yet implemented
	} // end switch
	//-----------------------------------------------------------------

	//-----------------------------------------------------------------
	// Add field names and types to shapefile attribute table
	//-----------------------------------------------------------------
	string s;
	for (int x = 0; x < m_pSimpleFeature->Get_ncols(); x++)
	{
		if (x != m_pSimpleFeature->GetGeometryColumnNumber())
			pShapes->Get_Table().Add_Field(m_pSimpleFeature->GetFieldName(x).c_str(),
											g_pSAGA_Frame->db->SQLFieldTypeToSAGAFieldtype(m_pSimpleFeature->GetFieldTypeInt(x))
											,x);
	}

	//-----------------------------------------------------------------
	// Create Geometries
	// Add Simple Feature 'features' as 'parts' to shapefile
	//-----------------------------------------------------------------
	for (unsigned int feature = 0; feature < m_pSimpleFeature->GetNumFeatures(); feature++)
	{
		pShapes->Add_Shape();
		// Add coordinates to parts
		for (unsigned int point = 0; point < m_pSimpleFeature->GetNumPointsFeature(feature); point++)
			pShapes->Get_Shape(feature)->Add_Point(m_pSimpleFeature->Get_X_Value(feature,point),
												   m_pSimpleFeature->Get_Y_Value(feature,point),
												   feature);
	}

	//-----------------------------------------------------------------
	// Add data to attribute table
	//-----------------------------------------------------------------
	for (int row = 0; row < m_pSimpleFeature->Get_nrows(); row++)
	{
		pShapes->Get_Table().Add_Record();
		pRecord = pShapes->Get_Table().Get_Record(row);
		for (int col = 0; col < m_pSimpleFeature->Get_ncols(); col++)
		{
			// Ignore geometry column
			if (col != m_pSimpleFeature->GetGeometryColumnNumber())
			{
				if (g_pSAGA_Frame->db->SQLFieldTypeToSAGAFieldtype(m_pSimpleFeature->GetFieldTypeInt(col))
					== TABLE_FIELDTYPE_Int)
 					pRecord->Set_Value(col, convert_sl::StringToInt(m_pSimpleFeature->GetValue(col,row)));
				
				if (g_pSAGA_Frame->db->SQLFieldTypeToSAGAFieldtype(m_pSimpleFeature->GetFieldTypeInt(col))
					== TABLE_FIELDTYPE_Double)
					pRecord->Set_Value(col, convert_sl::StringToDouble(m_pSimpleFeature->GetValue(col,row)));
				
				if (g_pSAGA_Frame->db->SQLFieldTypeToSAGAFieldtype(m_pSimpleFeature->GetFieldTypeInt(col))
					== TABLE_FIELDTYPE_String)
					pRecord->Set_Value(col,m_pSimpleFeature->GetValue(col,row).c_str());
			}
		}
	}
	//-----------------------------------------------------------------

	return(true);
}

/////////////////////////////////////////////////////////////////////////////
//
// Copy a SAGA Shapefile as SimpleFeature to PostgreSQL/PostGIS database
//
/////////////////////////////////////////////////////////////////////////////
bool Cmenu_db::Create_SF_From_Shape(CSG_Shapes *pShapes)
{
	std::ofstream file("_CreateSF.txt");
	// cut off the file extension from Shapefile name
	string ShapeName = "";
	ShapeName.insert(0, pShapes->Get_Name());
	ShapeName = Get_Reduced_ShapeName(ShapeName);

	// Create SQL-Query: CREATE TABLE...
	string SQL_Create = Get_SQL_Create(pShapes, ShapeName);
	file << SQL_Create << endl;

	// Create SQL-Query: SELECT AddGeometryColumn
	string geometry_type;
	string SQL_SELECT_GEOM = Get_SQL_SELECT_GEOM(pShapes, ShapeName, geometry_type);
	file << SQL_SELECT_GEOM << endl;

	// Create SQL-Query: INSERT INTO...
	string SQL_INSERT ="";
	string	SRID = "31462";
	for (int row = 0; row < pShapes->Get_Table().Get_Record_Count(); row++)
	{
		SQL_INSERT = Get_SQL_INSERT_INTO(pShapes, ShapeName, row, geometry_type, SRID);
		file << SQL_INSERT << endl;
	}

	return(true);
}

//---------------------------------------------------------------------------
string Cmenu_db::Get_Reduced_ShapeName(string &ShapeName)
{
	unsigned int pos = 0;
	for (pos = 0; ShapeName[pos] != '0'; pos++)
	{
		if (ShapeName[pos] == '.')
			return(ShapeName.substr(0,pos));
	}
	return(ShapeName);
}

//---------------------------------------------------------------------------
string Cmenu_db::Get_SQL_Create(CSG_Shapes *pShapes, string ShapeName)
{
	// !!!!!!!!!!!!!!!
	// the possibility to select a column which acts as primary key is missing

	// Create SQL-Query 'CREATE TABLE...'
	string CREATE ="CREATE TABLE ";
	//ShapeName.insert(ShapeName.length(),pShapes->Get_Name());
	//CREATE += Get_Reduced_ShapeName(ShapeName);
	CREATE += ShapeName;
	CREATE += "(";
	for (int col = 0; col < pShapes->Get_Table().Get_Field_Count(); col++)
	{
		CREATE.insert(CREATE.length(), pShapes->Get_Table().Get_Field_Name(col));
		CREATE += " ";
		CREATE += Get_FieldTypeFromSAGA(pShapes->Get_Table().Get_Field_Type(col));
		if (col == 0) CREATE += " primary key";
		if (col < pShapes->Get_Table().Get_Field_Count()-1)
			CREATE += ", ";
		else CREATE += ");";
	}

	return(CREATE);
}
//---------------------------------------------------------------------------

string Cmenu_db::Get_SQL_SELECT_GEOM(CSG_Shapes *pShapes, string ShapeName, string &geometry_type)
{
	// Create SQL-Query 'SELECT AddGeometryColumn...'
	string	geometry_column_name = "geom";
	geometry_type = "POINT";
	string	geometry_dimension = "2";
	string	SRID = "31462";

	string SELECT = "SELECT AddGeometryColumn('public', '";
	//SELECT.insert(SELECT.length(), pShapes->Get_Name());
	SELECT += ShapeName;
	SELECT += "' ,'";
	SELECT += geometry_column_name;
	SELECT += "', ";
	SELECT += SRID;
	SELECT += ", '";
	SELECT += geometry_type;
	SELECT += "', ";
	SELECT += geometry_dimension;
	SELECT += ");";

	return(SELECT);
}
//---------------------------------------------------------------------------

string Cmenu_db::Get_SQL_INSERT_INTO(CSG_Shapes *pShapes, string ShapeName, int row, string geometry_type, string SRID)
{
	// Create SQL-Query 'INSERT INTO...'
	CSG_String val;
	string INSERT = "INSERT INTO ";
	INSERT += ShapeName;
	INSERT += " VALUES(";
	// Add values from attribute table
	for (int col = 0; col < pShapes->Get_Table().Get_Field_Count(); col++)
	{
		if (!is_numeric(pShapes->Get_Table().Get_Field_Type(col)))
		{
			INSERT += "'";
			if (pShapes->Get_Table().Get_Value(row,col,val))
			{
				INSERT += val;
				INSERT += "', ";
			}
		} else {
			if (pShapes->Get_Table().Get_Value(row, col, val))
			{
				INSERT += val;
				INSERT += ", ";
			}
		}// end if		
	}

	// Convert ShapeFile geometry to SimpleFeature
	INSERT += "GeometryFromText('";
	INSERT += geometry_type;
	INSERT += "(";
	for (int point = 0; point < pShapes->Get_Shape(row)->Get_Point_Count(); point++)
	{
		INSERT += convert_sl::Double2String(pShapes->Get_Shape(row)->Get_Point(point, row).x);
		INSERT += " ";
		INSERT += convert_sl::Double2String(pShapes->Get_Shape(row)->Get_Point(point, row).y);
		if (point <= pShapes->Get_Shape(row)->Get_Point_Count()-1)
			INSERT += ")',";
		else INSERT += ",";
	}
	INSERT += SRID;
	INSERT += "));";

	return(INSERT);
}

