#ifndef GST_IntersectionOutputConfig_hpp__
#define GST_IntersectionOutputConfig_hpp__

#include <boost/optional.hpp>
#include <boost/variant.hpp>

#include <string>

#include "exceptions/GSTRuntimeException.h"

#include "buildspec.h"

namespace GST
{
namespace exceptions
{
/**
 * Thrown when an error in the intersection config json exists.
 * This could be due to wrong syntax or missing arguments
 */
class IntersectionConfigJsonError : public GSTRuntimeException
{
public:
	IntersectionConfigJsonError(const std::string &throwLocation,
								const std::string &msg)
		: GSTRuntimeException(throwLocation, msg)
	{
	}
};
} // namespace exceptions
namespace IntersectionOutputConfig
{

namespace Unit
{
enum Type
{
	mm = 0,
	cm,
	px
	// rest of valid SVG units would be:
	// em, ex, pt, pc, in
};
GST_API_EXPORT std::string toString(Type t);
GST_API_EXPORT boost::optional<Type> fromString(const std::string &s);
} // namespace Unit

namespace HeightReferenceType
{
enum Type
{
	masl = 0,
	depthWithVal,
	depthCalc
};
}

namespace YScaleMode
{
enum Type
{
	none = 0,
	left,
	right,
	both
};
GST_API_EXPORT std::string toString(Type t);
GST_API_EXPORT boost::optional<Type> fromString(const std::string &s);
} // namespace YScaleMode

namespace GrowMode
{
enum Type
{
	none = 0,
	upperLeft,
	upperRight,
	lowerLeft,
	lowerRight
};
GST_API_EXPORT std::string toString(Type t);
GST_API_EXPORT boost::optional<Type> fromString(const std::string &s);
} // namespace GrowMode

namespace ImageAlighnment
{
enum Type
{
	up = 0,
	down,
	left,
	right,
	center,
	upperLeft,
	upperRight,
	lowerLeft,
	lowerRight
};
GST_API_EXPORT std::string toString(Type t);
GST_API_EXPORT boost::optional<Type> fromString(const std::string &s);
} // namespace ImageAlighnment

struct GST_API_EXPORT HeightReference
{
	HeightReferenceType::Type type;
	boost::optional<double> referenceValue;
};

struct GST_API_EXPORT BoreholeConfig
{
	boost::optional<double> width;
	boost::optional<double> height;
	boost::optional<double> docWidth;
	boost::optional<double> docHeight;
	boost::optional<double> fontSize;
	boost::optional<std::string> fontFamily;
	boost::optional<HeightReference> heightReference;
	boost::optional<std::string> yScaleRefMarker;
	boost::optional<YScaleMode::Type> yscaleMode;
	boost::optional<double> yscaleStepLength;
	boost::optional<double> yscaleFontSize;
	boost::optional<std::string> yscaleFontFamily;
	boost::optional<double> yscaleWidth;
	boost::optional<double> pillarMarginLeft;
	boost::optional<double> pillarMarginRight;
	boost::optional<double> pillarWidth;
	boost::optional<double> pillarLineOverlap;
	boost::optional<double> labelAreaWidth;
	boost::optional<int> labelAreaWordWrapThreshold;
	boost::optional<double> labelAreaFontSize;
	boost::optional<std::string> labelAreaFontFamily;
	boost::optional<bool> labelAreaEnabled;
	boost::optional<GrowMode::Type> grow;
	boost::optional<bool> standaloneSvg;
	boost::optional<bool> drawHeaderInfo;
};

struct GST_API_EXPORT CrossSectionConfig
{
	boost::optional<double> width;
	boost::optional<double> height;
	boost::optional<double> docWidth;
	boost::optional<double> docHeight;
	boost::optional<double> fontSize;
	boost::optional<std::string> fontFamily;
	boost::optional<std::string> yScaleRefMarker;
	boost::optional<YScaleMode::Type> yscaleMode;
	boost::optional<double> yscaleStepLength;
	boost::optional<double> scaleFontSize;
	boost::optional<double> yscaleWidth;
	boost::optional<std::string> scaleFontFamily;
	boost::optional<double> xscaleStepLength;
	boost::optional<GrowMode::Type> grow;
	boost::optional<bool> standaloneSvg;
	boost::optional<std::string> bendMarkerText;
	boost::optional<bool> drawHeaderInfo;
	boost::optional<bool> drawBoreholeLabelSideways;
	boost::optional<bool> shouldDrawBoreholeLabels;
};

struct GST_API_EXPORT MapSectionConfig
{
	boost::optional<double> width;
	boost::optional<double> height;
	boost::optional<double> docWidth;
	boost::optional<double> docHeight;
	boost::optional<double> fontSize;
	boost::optional<std::string> fontFamily;
	boost::optional<std::string> heightRefMarker;
	boost::optional<double> scaleFontSize;
	boost::optional<std::string> scaleFontFamily;
	boost::optional<double> yscaleWidth;
	boost::optional<GrowMode::Type> grow;
	boost::optional<bool> standaloneSvg;
	boost::optional<bool> drawOutline;
	boost::optional<bool> drawHeaderInfo;
};

struct GST_API_EXPORT LegendConfig
{
	boost::optional<double> width;
	boost::optional<double> height;
	boost::optional<double> docWidth;
	boost::optional<double> docHeight;
	boost::optional<double> fontSize;
	boost::optional<std::string> fontFamily;
	boost::optional<double> borderWidth;
	boost::optional<double> borderHeight;
	boost::optional<double> labelWidth;
	boost::optional<double> labelHeight;
	boost::optional<double> entryVerticalSpacing;
	boost::optional<double> labelToTextSpacing;
	boost::optional<bool> standaloneSvg;
	boost::optional<int> wordWrapThreshold;
	boost::optional<std::string> sectionObject;
	boost::optional<std::string> sectionStrat;
	boost::optional<std::string> sectionPetro;
	boost::optional<std::string> sectionGeologicalMap;
	boost::optional<int> momaSectionsLevel;
};

struct GST_API_EXPORT ScalebarConfig
{
	boost::optional<double> width;
	boost::optional<double> height;
	boost::optional<double> docWidth;
	boost::optional<double> docHeight;
	boost::optional<double> fontSize;
	boost::optional<std::string> fontFamily;
	boost::optional<int> segmentCount;
};

struct GST_API_EXPORT Config
{
	boost::optional<Unit::Type> unit;
	boost::optional<int> dpi;
	boost::optional<ImageAlighnment::Type> sectionImageAlignment;
	boost::optional<GrowMode::Type> grow;
	boost::optional<BoreholeConfig> boreHoleConfig;
	boost::optional<CrossSectionConfig> crossSectionConfig;
	boost::optional<MapSectionConfig> mapSectionConfig;
	boost::optional<LegendConfig> legendConfig;
	boost::optional<ScalebarConfig> scalebarConfig;
};

namespace ConfigParts
{
enum
{
	none = 0,
	boreHoleConfig = 1,
	crossSectionConfig = 2,
	mapSectionConfig = 4,
	legendConfig = 8,
	all = legendConfig | mapSectionConfig | crossSectionConfig | boreHoleConfig
};
}

GST_API_EXPORT void fromJson(Config &config,
							 const std::string json,
							 int selection = ConfigParts::all);
GST_API_EXPORT void toJson(const Config &config,
						   std::string &json,
						   int selection = ConfigParts::all);

// merges otherConfig with config
//
// Note: this will never unset already set values in config.
// If this behavior is desired, just use copy assignment
// (i.e. config = otherConig;)
GST_API_EXPORT void merge(Config &config,
						  const Config &otherConfig,
						  int selection = ConfigParts::all);
} // namespace IntersectionOutputConfig
} // namespace GST

#endif // GST_IntersectionOutputConfig_hpp__
