#ifndef _FILE_WRAPPING_GEOMETRY_H_
#define _FILE_WRAPPING_GEOMETRY_H_

#include <Client/ClientUtils/Network/NetworkInterfaceStructs.h>
#include <Geometry/ClientGeometry.h>
#include <Geometry/ClientSimplexProperty.h>
#include <Geometry/IFileSerialisable.h>
#include <Parsers/GrammarRawStructs.h>
#include <Utils/IPartCountProgress.h>
#include <buildspec.h>
#include <exceptions/GSTRuntimeException.h>

namespace GST
{
// exceptions:
namespace exceptions
{
class FileOpenProblem : public GSTRuntimeException
{
public:
	std::string filename;

	FileOpenProblem(const std::string &throwLocation,
					const std::string &filename)
		: GSTRuntimeException(throwLocation, "")
		, filename(filename)
	{
	}
	virtual ~FileOpenProblem() throw()
	{
	}
};
class NoPersmission : public FileOpenProblem
{
public:
	NoPersmission(const std::string &throwLocation, const std::string &filename)
		: FileOpenProblem(throwLocation, filename)
	{
		this->_msg = "No permission to open file " + filename + ".";
	}
};

class FileNotExists : public FileOpenProblem
{
public:
	FileNotExists(const std::string &throwLocation, const std::string &filename)
		: FileOpenProblem(throwLocation, filename)
	{
		this->_msg = "File " + filename + " does not exists.";
	}
};
} // namespace exceptions

// prototypes:
namespace ClientUtils
{
struct CrudeFeature;
}

namespace Geometry
{

// prototypes:
class FileWrappingGeometry;

/**
 * Due to some format an object file can reside over a set of files (e.g. surpac
 * format: DTM/STR+SSI) This is the base class covering one file.
 */
struct GST_API_EXPORT FileBundle
{
	std::string file;

	FileBundle()
	{
	}
	FileBundle(const std::string &filename) : file(filename)
	{
	}

	FileBundle &operator=(const std::string &file)
	{
		this->file = file;
		return *this;
	}
	std::string get() const
	{
		return file;
	}
};

struct GST_API_EXPORT SurpacFileBundle : public FileBundle
{
	std::string styleFile;

	SurpacFileBundle() : FileBundle()
	{
	}

	void setObjectFile(const std::string &filename)
	{
		this->file = filename;
	}
	void setStyleFile(const std::string &filename)
	{
		this->styleFile = filename;
	}
	std::string getObjectFile() const
	{
		return this->file;
	}
	std::string getStyleFile() const
	{
		return this->styleFile;
	}
};

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

class GST_API_EXPORT TextFileReader
{
public:
	TextFileReader();

	ClientGeometryListPtr ReadWrappersFromArchive(
		const FileBundle &filebundle,
		const IGeometry::GeometryType &geomtype,
		Utils::IPartCountProgress *progress);
	ClientGeometryListPtr ReadWrappers(
		const std::vector<FileBundle> &filenames,
		const IFileSerialisable::FileType &filetype,
		const IGeometry::GeometryType &geomtype,
		Utils::IPartCountProgress *progress);
	ClientGeometryListPtr ReadWrappers(
		const FileBundle &filebundle,
		const IFileSerialisable::FileType &filetype,
		const IGeometry::GeometryType &geomtype,
		Utils::IPartCountProgress *progress);
	ClientGeometryListPtr getWrappers() const;
	ClientGeometryListPtr ReleaseWrapper();

	static IFileSerialisable::FileType DetermineFileType(
		const std::string &filename);

private:
	ClientGeometryListPtr container;
}; // class TextFileReader

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

class GST_API_EXPORT FileWrappingSimplexProperty : public ClientSimplexProperty
{
public:
	FileWrappingSimplexProperty(const std::string &propDesc);
	FileWrappingSimplexProperty(const std::string &name,
								PropertyType type,
								int dim,
								PropertyAlignment alignment
								= Geometry::VERTEX_ALIGNED);

	FileWrappingSimplexProperty(const ClientUtils::TableAttributeDesc &p);
	virtual ~FileWrappingSimplexProperty();
	///@name boost container members
	//@{
	ClientSimplexProperty *clone() const override;
	//@}

	///@name GUI and Utils called methods
	//@{
	std::string getName() const override;
	void setName(const std::string &name) override;
	PropertyType getType() const override;
	int getDimension() const override;
	PropertyAlignment getAlignment() const override;

private:
	std::string name;
	PropertyType type;
	int dim;
	PropertyAlignment alignment;
};

//-------------------------- class of headerfile
//--------------------------------

class GST_API_EXPORT FileWrappingGeometry : public ClientGeometry
{
	friend class TextFileReader;

protected:
	FileWrappingGeometry();

public:
	/// construct empty (File->Request)
	FileWrappingGeometry(IGeometry::GeometryType type,
						 IFileSerialisable::FileType filetype);

	/// construct from string (Request->File)
	FileWrappingGeometry(IGeometry::GeometryType type,
						 ClientUtils::CrudeFeature *requestFeature);

	virtual ~FileWrappingGeometry();

	///@name ClientGeometry members (lib independent)
	//@{
	unsigned int addSimplexProperty(
		const std::string &name,
		ClientSimplexProperty::PropertyType PropertyType,
		unsigned int dims,
		ClientSimplexProperty::PropertyAlignment alignment
		= Geometry::VERTEX_ALIGNED) override;
	unsigned int addSimplexProperty(const ClientSimplexProperty &p) override;
	unsigned int addSimplexProperty(
		const ClientUtils::TableAttributeDesc &p) override;
	SmplxPropertyListPtr getProperties() const override;

	void setPropDesc(const std::string &propertyDesc);
	void setProperties(const SmplxPropertyListPtr &newlist) override;

	void SaveGeometry(const std::string &filename,
					  const FileType &filetype) override;
	void SaveProperty(const std::string &filename,
					  const FileType &filetype) override;

	boost::optional<boost::uint64_t> GetGeometryFileStart() const override;
	boost::optional<boost::uint64_t> GetGeometryFileEnd() const override;

	//@}

	///@name IFileSerialisable members
	//@{
	void saveToFile(const std::string &filename,
					const FileType &filetype) override;
	virtual void saveToFile(const std::string &filestem,
							const IFileSerialisable::FileType &format,
							const std::string &geometryStr,
							const std::string &propDescStr,
							const std::string &propertyStr);
	void loadFromFile(const std::string &filename,
					  const FileType &filetype) override;
	virtual void loadPropertyFromFile(const std::string &filename);
	//@}

	//@name StreamposRead
	//@{
	virtual void loadFromStreampos(std::istream &objectStream,
								   const std::streampos &firstPos,
								   const std::streampos &lastPos);
	virtual void loadFromString(const std::string &content);
	//@}

	///@name IGeometry members:
	//@{
	std::string GetName() const override;

	bool serializeGeometry(std::ostream &os) const override;
	bool serializeSimplexPropertyValues(std::ostream &os) const override;
	bool serializeSimplexPropertyDescription(std::ostream &os) const override;
	//@}

	///@name own interface:
	//@{
	std::string getGeometryString() const;
	void setGeometryString(const std::string &geo);
	void setGridDesc(const Parsers::GridDescription &gd);
	Parsers::GridDescription getGridDesc() const;
	void setGeometryFilePos(boost::uint64_t start, boost::uint64_t end);
	//@}

	std::string geometryString;
	std::string propertyString;
	std::string propertyDesc;
	ClientUtils::SEGYInfoPtr segyInfo;
	// potentially set by a header parser, 0 if not set
	uint32_t srsEpsgCode;
	// potentially set by a header parser, empty if not set
	std::string srsProj4Def;
	// potentially set by a header parser, empty if not set
	std::string texturePath;

protected:
	SmplxPropertyListPtr simplexProperties;
	IFileSerialisable::FileType filetype;

	ClientUtils::CrudeFeature *requestFeature;
	boost::optional<boost::uint64_t> geometryFileStart;
	boost::optional<boost::uint64_t> geometryFileEnd;

	Parsers::GridDescription gridDesc;
};

} // namespace Geometry
} // namespace GST

#endif //_FILE_WRAPPING_GEOMETRY_H_
