#ifndef GST_ShapefileParser_hpp__
#define GST_ShapefileParser_hpp__

#include "buildspec.h"
#include "exceptions/GSTRuntimeException.h"

#include <string>

namespace GST
{
namespace exceptions
{
class ShapefileParserException : public exceptions::GSTRuntimeException
{
public:
	ShapefileParserException(const std::string &throwLocation,
							 const std::string &message)
		: exceptions::GSTRuntimeException(throwLocation, message)
	{
	}
	virtual ~ShapefileParserException() throw()
	{
	}
};
class ShapefileParserDbfException : public exceptions::ShapefileParserException
{
public:
	ShapefileParserDbfException(const std::string &throwLocation,
								const std::string &message)
		: exceptions::ShapefileParserException(throwLocation, message)
	{
	}
	virtual ~ShapefileParserDbfException() throw()
	{
	}
};
} // namespace exceptions
namespace Parsers
{
// call graph in pseudo code:
//
// start()
// numLayers()
// for each layer:
//	if nullLayer:
//   newNullLayer()
//  else:
//	  newLayer()
//    for each part in layer:
//      newPart()
//      for each point in part:
//        newPoint()
//      finishPart()
//    finishLayer()
// done()
class GST_API_EXPORT ShapeFileParserCallback
{
public:
	virtual ~ShapeFileParserCallback()
	{
	}
	virtual void start() = 0;
	virtual void numLayers(int numLayers) = 0;
	// doesn't follow with finishLayer
	virtual void newNullLayer() = 0;
	virtual void newLayer(int layerId, int numParts) = 0;
	virtual void finishLayer() = 0;
	virtual void newPart(int numPoints) = 0;
	virtual void finishPart() = 0;
	virtual void newPoint(double x, double y, double z) = 0;
	virtual void done() = 0;
};

struct ShapeFileInfo
{
	enum Type
	{
		Arc = 0,
		ArcZ,
		Polygon,
		PolygonZ,
		Other
	};
	Type type;
	int numLayers;
};
class GST_API_EXPORT ShapeFileParser
{
public:
	ShapeFileParser(const std::string &filePath);
	ShapeFileInfo getFileInfo() const;
	std::vector<std::string> listStringPropertyNames() const;
	// precondition:
	//              - fieldName is a valid field name in the dbf file
	//              - fieldName references a text field
	//              (see listStringPropertyNames for both)
	//              - shapeIndex is a valid index in the shp/dbf file
	// throws:
	//              - ShapefileParserDbfException on violation
	std::string getValue(const std::string &fieldName, int shapeIndex) const;
	// returns values of the text column fieldName
	// precondition:
	//              - fieldName is a valid field name in the dbf file
	//              - fieldName references a text field
	//              (see listStringPropertyNames for both)
	//              - shapeIndices are valid indices in the shp/dbf file
	// postcondition:
	//              - result.size() == shapeIndices.size()
	// throws:
	//              - ShapefileParserDbfException on violation
	std::vector<std::string> getValues(
		const std::string &fieldName,
		const std::vector<int> &shapeIndices) const;
	bool hasSrsDefinition() const;
	std::string getSrsDefinition() const;
	// note:
	//              currently only handles Arc(Z) or Polygon(Z)
	//              (i.e. 2d and 3d multilinestrings/polygons)
	// throws:
	//              - ShapefileParserException if other type
	void parse(ShapeFileParserCallback &callBack) const;

private:
	std::string m_basePath;
	std::string m_srsDefinition;
	bool m_haveSrsDefintion;
};
} // namespace Parsers
} // namespace GST

#endif // GST_ShapefileParser_hpp__
