#ifndef _IFILESERIALISABLE_H
#define _IFILESERIALISABLE_H

#include <string>

#include <GSTenums.h>
#include <exceptions/GSTRuntimeException.h>

namespace GST
{
namespace Geometry
{

class GST_API_EXPORT IFileSerialisable
{
public:
	enum FileType
	{
		GocadFile = 1,
		DXF,
		OFF,
		OBJ,
		X3D,
		PLY2,
		SFS,
		SFSP,
		ArchiveFile,
		BIN,
		SURPAC_DTM,
		SUPRAC_STR,
		MockParse,
		KMZ,
		DAE,
		unkown,
		VTK,
		ISATIS,
		X3DOMPOP,
		I3S_SLPK,
		USDZ,
		IFC,
		SEGY,
		SGY,
		STL,
		GPKG,
		SHP,
		SHPCOLLECTION,
		GSTWEB,
		SHPPROFILE,
		GPKGPROFILE,
		GLTF,
		KML,
		CSV,
		GML,
		SURPAC,
		SHPPOINTCLOUD,
		RESQML,
		TILES3D,
		GEOTIFF,
		NETCDF,
		FDSN,
		SAXQUAKE,
		GPKGPOINTCLOUD,
		GEOH5,
		SVG,
	};

	virtual void saveToFile(const std::string &filename,
							const FileType &filetype)
		= 0;
	virtual void loadFromFile(const std::string &filename,
							  const FileType &filetype)
		= 0;
	static const char *FileTypeToExtsion(const FileType &type,
										 Geometry::GeometryTypes geomtype
										 = Geometry::unkown)
	{
		switch(type)
		{
		case GocadFile:
			switch(geomtype)
			{
			case Geometry::Multipoint3:
				return "vs";
			case Geometry::Multiline3:
				return "pl";
			case Geometry::Tin3:
				return "ts";
			case Geometry::Multipolygon3:
				return "so";
			case Geometry::Geomcollection3:
			default:
				return "gp";
			}
		case DXF:
			return "dxf";
		case OFF:
			return "off";
		case X3D:
			return "x3d";
		case PLY2:
			return "ply2";
		case SFS:
			return "wkt";
		case SFSP:
			return "SFSP";
		case OBJ:
			return "obj";
		case X3DOMPOP:
		case BIN:
		case GSTWEB:
			return "bin";
		case KMZ:
			return "kmz";
		case DAE:
			switch(geomtype)
			{
			case Geometry::Multipoint3:
			case Geometry::Multiline3:
				return "kml";
			case Geometry::Tin3:
			case Geometry::Multipolygon3:
			case Geometry::Geomcollection3:
			default:
				return "collada";
			}
		case VTK:
			return "vtk";
		case ISATIS:
			// TODO: ISATIS file extension
			// since server currently writes ".hd" we use that.
			return "hd";
		case I3S_SLPK:
			return "slpk";
		case USDZ:
			return "usd";
		case IFC:
			return "ifc";
		case SGY:
			return "sgy";
		case SEGY:
			return "segy";
		case STL:
			return "stl";
		case GPKGPOINTCLOUD:
		case GPKGPROFILE:
		case GPKG:
			return "gpkg";
		case SHPCOLLECTION:
		case SHP:
		case SHPPROFILE:
		case SHPPOINTCLOUD:
			return "shp";
		case RESQML:
			// we only support the EPC container format for now.
			return "epc";
		case NETCDF:
			return "nc";
		case SUPRAC_STR:
			return "str";
		case SURPAC_DTM:
			return "dtm";
		case GEOH5:
			return "geoh5";
		case SVG:
			return "svg";
		default:
		case unkown:
			throw exceptions::GSTRuntimeException(__METHOD_NAME__,
												  "Unknown file type.");
		}
	}

	static bool SupportMetaDataParsing(FileType &fileformat)
	{
		switch(fileformat)
		{
		case IFileSerialisable::GocadFile:
		case IFileSerialisable::MockParse:
			return true;
		default:
			return false;
		}
	}

	static std::string FileType2JsonSendingType(
		IFileSerialisable::FileType ftype)
	{
		switch(ftype)
		{
		case GocadFile:
			return "GCD";
		case DXF:
			return "DXF";
		case OFF:
			return "OFF";
		case OBJ:
			return "OBJ";
		case X3D:
			return "X3D";
		case PLY2:
			return "PLY2";
		case SFS:
			return "SFS";
		case SFSP:
			return "SFSP";
		case BIN:
			return "BIN";
		case SURPAC_DTM:
			return "SURPAC_DTM";
		case SUPRAC_STR:
			return "SURPAC_STR";
		case unkown:
			return "UNKNOWN";
		case VTK:
			return "VTK";
		case ISATIS:
			return "ISATIS";
		case X3DOMPOP:
			return "X3DOMPOP";
		case I3S_SLPK:
			return "I3S_SLPK";
		case USDZ:
			return "USDZ";
		case IFC:
			return "IFC";
		case SEGY:
			return "SGY";
		case SGY:
			return "SGY";
		case STL:
			return "STL";
		case GPKG:
			return "GPKG";
		case SHP:
			return "SHP";
		case SHPCOLLECTION:
			return "SHPCOLLECTION";
		case GSTWEB:
			return "GSTWEB";
		case SHPPROFILE:
			return "SHPPROFILE";
		case GLTF:
			return "GLTF";
		case KML:
			return "KML";
		case CSV:
			return "CSV";
		case GML:
			return "GML";
		case SURPAC:
			return "SURPAC";
		case SHPPOINTCLOUD:
			return "SHPPOINTCLOUD";
		case RESQML:
			return "RESQML";
		case TILES3D:
			return "TILES3D";
		case GEOTIFF:
			return "GEOTIFF";
		case NETCDF:
			return "NETCDF";
		case FDSN:
			return "FDSN";
		case SAXQUAKE:
			return "SAXQUAKE";
		case GPKGPOINTCLOUD:
			return "GPKGPOINTCLOUD";
		case GPKGPROFILE:
			return "GPKGPROFILE";
		case SVG:
			return "SVG";
		case ArchiveFile:
		default:
			throw exceptions::GSTRuntimeException(
				__METHOD_NAME__,
				"Can't write json file type for this geometry.");
		}
	}

	static IFileSerialisable::FileType FileTypeFromJsonSendingType(
		const std::string &ftype)
	{
		if(ftype == "GCD")
			return GocadFile;
		else if(ftype == "DXF")
			return DXF;
		else if(ftype == "OFF")
			return OFF;
		else if(ftype == "OBJ")
			return OBJ;
		else if(ftype == "X3D")
			return X3D;
		else if(ftype == "PLY2")
			return PLY2;
		else if(ftype == "SFS")
			return SFS;
		else if(ftype == "SFSP")
			return SFSP;
		else if(ftype == "BIN")
			return BIN;
		else if(ftype == "SURPAC_DTM")
			return SURPAC_DTM;
		else if(ftype == "SURPAC_STR")
			return SUPRAC_STR;
		else if(ftype == "UNKNOWN")
			return unkown;
		else if(ftype == "VTK")
			return VTK;
		else if(ftype == "ISATIS")
			return ISATIS;
		else if(ftype == "X3DOMPOP")
			return X3DOMPOP;
		else if(ftype == "I3S_SLPK")
			return I3S_SLPK;
		else if(ftype == "USDZ")
			return USDZ;
		else if(ftype == "IFC")
			return IFC;
		else if(ftype == "SEGY")
			return SGY;
		else if(ftype == "SGY")
			return SGY;
		else if(ftype == "STL")
			return STL;
		else if(ftype == "GPKG")
			return GPKG;
		else if(ftype == "SHP")
			return SHP;
		else if(ftype == "SHPCOLLECTION")
			return SHPCOLLECTION;
		else if(ftype == "GSTWEB")
			return GSTWEB;
		else if(ftype == "SHPPROFILE")
			return SHPPROFILE;
		else if(ftype == "GLTF")
			return GLTF;
		else if(ftype == "KML")
			return KML;
		else if(ftype == "CSV")
			return CSV;
		else if(ftype == "GML")
			return GML;
		else if(ftype == "SURPAC")
			return SURPAC;
		else if(ftype == "SHPPOINTCLOUD")
			return SHPPOINTCLOUD;
		else if(ftype == "RESQML")
			return RESQML;
		else if(ftype == "TILES3D")
			return TILES3D;
		else if(ftype == "GEOTIFF")
			return GEOTIFF;
		else if(ftype == "NETCDF")
			return NETCDF;
		else if(ftype == "FDSN")
			return FDSN;
		else if(ftype == "SAXQUAKE")
			return SAXQUAKE;
		else if(ftype == "GPKGPOINTCLOUD")
			return GPKGPOINTCLOUD;
		else if(ftype == "GPKGPROFILE")
			return GPKGPROFILE;
		else if(ftype == "SVG")
			return SVG;
		else
			throw exceptions::GSTRuntimeException(__METHOD_NAME__,
												  "Unsupported file type.");
	}
};

GST_API_EXPORT inline RequestFormats FileTypeToRequestFormat(
	const IFileSerialisable::FileType fileType)
{
	switch(fileType)
	{
	case IFileSerialisable::SFS:
		return Geometry::SFS;
	case IFileSerialisable::SFSP:
		return Geometry::SFSP;
	case IFileSerialisable::GML:
		return Geometry::GML;
	case IFileSerialisable::X3D:
		return Geometry::X3D;
	case IFileSerialisable::OBJ:
		return Geometry::OBJ;
	case IFileSerialisable::PLY2:
		return Geometry::PL2;
	case IFileSerialisable::GocadFile:
		return Geometry::GCD;
	case IFileSerialisable::BIN:
		return Geometry::BIN;
	case IFileSerialisable::SURPAC:
		return Geometry::SURPAC;
	case IFileSerialisable::DAE:
		return Geometry::DAE;
	case IFileSerialisable::KMZ:
		return Geometry::KMZ;
	case IFileSerialisable::VTK:
		return Geometry::VTK;
	case IFileSerialisable::ISATIS:
		return Geometry::ISATIS;
	case IFileSerialisable::CSV:
		return Geometry::CSV;
	case IFileSerialisable::X3DOMPOP:
		return Geometry::X3DOMPOP;
	case IFileSerialisable::I3S_SLPK:
		return Geometry::I3S_SLPK;
	case IFileSerialisable::USDZ:
		return Geometry::USDZ;
	case IFileSerialisable::IFC:
		return Geometry::IFC;
	case IFileSerialisable::GPKG:
		return Geometry::GPKG;
	case IFileSerialisable::SHP:
		return Geometry::SHP;
	case IFileSerialisable::SHPCOLLECTION:
		return Geometry::SHPCOLLECTION;
	case IFileSerialisable::GSTWEB:
		return Geometry::GSTWEB;
	case IFileSerialisable::SEGY:
		return Geometry::SEGY;
	case IFileSerialisable::SHPPROFILE:
		return Geometry::SHPPROFILE;
	case IFileSerialisable::GLTF:
		return Geometry::GLTF;
	case IFileSerialisable::KML:
		return Geometry::KML;
	case IFileSerialisable::SHPPOINTCLOUD:
		return Geometry::SHPPOINTCLOUD;
	case IFileSerialisable::RESQML:
		return Geometry::RESQML;
	case IFileSerialisable::TILES3D:
		return Geometry::TILES3D;
	case IFileSerialisable::GEOTIFF:
		return Geometry::GEOTIFF;
	case IFileSerialisable::NETCDF:
		return Geometry::NETCDF;
	case IFileSerialisable::FDSN:
		return Geometry::FDSN;
	case IFileSerialisable::SAXQUAKE:
		return Geometry::SAXQUAKE;
	case IFileSerialisable::GPKGPOINTCLOUD:
		return Geometry::GPKGPOINTCLOUD;
	case IFileSerialisable::STL:
		return Geometry::STL;
	case IFileSerialisable::DXF:
		return Geometry::DXF;
	case IFileSerialisable::GEOH5:
		return Geometry::GEOH5;
	case IFileSerialisable::SVG:
		return Geometry::SVG;
	case IFileSerialisable::GPKGPROFILE:
		return Geometry::GPKGPROFILE;
	default:
		throw GST::exceptions::GSTRuntimeException(
			__METHOD_NAME__, "Requested output format not registered.");
	}
}

GST_API_EXPORT inline IFileSerialisable::FileType FileTypeFromRequestFormat(
	const RequestFormats fileType)
{
	switch(fileType)
	{
	case Geometry::SFS:
		return IFileSerialisable::SFS;
	case Geometry::SFSP:
		return IFileSerialisable::SFSP;
	case Geometry::GML:
		return IFileSerialisable::GML;
	case Geometry::X3D:
		return IFileSerialisable::X3D;
	case Geometry::OBJ:
		return IFileSerialisable::OBJ;
	case Geometry::PL2:
		return IFileSerialisable::PLY2;
	case Geometry::GCD:
		return IFileSerialisable::GocadFile;
	case Geometry::BIN:
		return IFileSerialisable::BIN;
	case Geometry::SURPAC:
		return IFileSerialisable::SURPAC;
	case Geometry::DAE:
		return IFileSerialisable::DAE;
	case Geometry::KMZ:
		return IFileSerialisable::KMZ;
	case Geometry::VTK:
		return IFileSerialisable::VTK;
	case Geometry::ISATIS:
		return IFileSerialisable::ISATIS;
	case Geometry::CSV:
		return IFileSerialisable::CSV;
	case Geometry::X3DOMPOP:
		return IFileSerialisable::X3DOMPOP;
	case Geometry::I3S_SLPK:
		return IFileSerialisable::I3S_SLPK;
	case Geometry::USDZ:
		return IFileSerialisable::USDZ;
	case Geometry::IFC:
		return IFileSerialisable::IFC;
	case Geometry::GPKG:
		return IFileSerialisable::GPKG;
	case Geometry::SHP:
		return IFileSerialisable::SHP;
	case Geometry::SHPCOLLECTION:
		return IFileSerialisable::SHPCOLLECTION;
	case Geometry::GSTWEB:
		return IFileSerialisable::GSTWEB;
	case Geometry::SEGY:
		return IFileSerialisable::SEGY;
	case Geometry::SHPPROFILE:
		return IFileSerialisable::SHPPROFILE;
	case Geometry::GLTF:
		return IFileSerialisable::GLTF;
	case Geometry::KML:
		return IFileSerialisable::KML;
	case Geometry::SHPPOINTCLOUD:
		return IFileSerialisable::SHPPOINTCLOUD;
	case Geometry::RESQML:
		return IFileSerialisable::RESQML;
	case Geometry::TILES3D:
		return IFileSerialisable::TILES3D;
	case Geometry::GEOTIFF:
		return IFileSerialisable::GEOTIFF;
	case Geometry::NETCDF:
		return IFileSerialisable::NETCDF;
	case Geometry::FDSN:
		return IFileSerialisable::FDSN;
	case Geometry::SAXQUAKE:
		return IFileSerialisable::SAXQUAKE;
	case Geometry::GPKGPOINTCLOUD:
		return IFileSerialisable::GPKGPOINTCLOUD;
	case Geometry::STL:
		return IFileSerialisable::STL;
	case Geometry::GEOH5:
		return IFileSerialisable::GEOH5;
	case Geometry::SVG:
		return IFileSerialisable::SVG;
	case Geometry::GPKGPROFILE:
		return IFileSerialisable::GPKGPROFILE;
	default:
		throw GST::exceptions::GSTRuntimeException(
			__METHOD_NAME__, "Requested output format not registered.");
	}
}

} // namespace Geometry
} // namespace GST

#endif //_IFILESERIALISABLE_H
