#ifndef GST_CU_COLOR_MAP_HPP__
#define GST_CU_COLOR_MAP_HPP__

#include "buildspec.h"

#include <Client/ClientUtils/Network/constrained_color_value_desc.hpp>
#include <Geometry/IGeometry.h>

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

#include <string>
#include <vector>

namespace GST
{
namespace ClientUtils
{
enum class ColorMapType
{
	Continuous,
	Discrete
};

struct GST_API_EXPORT ColorMapToSegment
{
	float toValue;
	Geometry::IGeometry::Color toColor;
	std::string label;

	ColorMapToSegment(float toValue,
					  Geometry::IGeometry::Color toColor,
					  const std::string &label = std::string())
		: toValue(toValue)
		, toColor(toColor)
		, label(label)
	{
	}
};
typedef std::vector<ColorMapToSegment> ColorMapSegmentList;

struct GST_API_EXPORT ColorMapDiscreteValue
{
	std::string value;
	Geometry::IGeometry::Color color;
	std::string label;
	int order;

	ColorMapDiscreteValue(const std::string &value,
						  Geometry::IGeometry::Color color,
						  const std::string &label,
						  int order)
		: value(value)
		, color(color)
		, label(label)
		, order(order)
	{
	}
};
typedef std::vector<ColorMapDiscreteValue> ColorMapDiscreteValueList;

class ColorMapDesc;

struct GST_API_EXPORT ColorMap
{
	typedef long Id;

	Id id;
	std::string name;
	Geometry::IGeometry::Color nodataColor;
	std::string regex;
	long accessLevelId;
	bool nodataTransparentForGrids;
	// unix time stamp (seconds since epoch)
	int64_t updated_at;

	ColorMap(const std::string &name)
		: id(-1 /*NEW_COLORMAP_ID*/)
		, name(name)
		, nodataColor(0.f, 0.f, 0.f)
		, regex()
		, accessLevelId(0)
		, nodataTransparentForGrids(false)
		, updated_at(-1)
	{
	}

	ColorMap(const std::string &name,
			 const Geometry::IGeometry::Color &nodataColor,
			 const std::string &regex,
			 long accessLevelId,
			 bool nodataTransparentForGrids = false,
			 int64_t updated_at = -1)
		: id(-1 /*NEW_COLORMAP_ID*/)
		, name(name)
		, nodataColor(nodataColor)
		, regex(regex)
		, accessLevelId(accessLevelId)
		, nodataTransparentForGrids(nodataTransparentForGrids)
		, updated_at(updated_at)
	{
	}

	virtual ~ColorMap()
	{
	}

	virtual ColorMapType getType() const = 0;
	bool isConstrained() const;
	const ConstrainedColorValueDesc &constrainedDesc() const;
	void setConstrainedDesc(ConstrainedColorValueDesc desc);

	ColorMapDesc getDesc() const;

private:
	boost::optional<ConstrainedColorValueDesc> m_ConstrainedInfo;
};
typedef boost::shared_ptr<ColorMap> ColorMapPtr;
typedef std::vector<ColorMapPtr> ColorMapList;
typedef boost::shared_ptr<ColorMapList> ColorMapListPtr;

const ColorMap::Id NEW_COLORMAP_ID = -1;

struct GST_API_EXPORT ContinuousColorMap : ColorMap
{
	ColorMapSegmentList segments;

	ContinuousColorMap(const std::string &name) : ColorMap(name), segments()
	{
	}

	ContinuousColorMap(const std::string &name,
					   const ColorMapSegmentList &segments,
					   const Geometry::IGeometry::Color &nodataColor,
					   const std::string &regex,
					   long accessLevelId,
					   bool nodataTransparentForGrids = false)
		: ColorMap(name,
				   nodataColor,
				   regex,
				   accessLevelId,
				   nodataTransparentForGrids)
		, segments(segments)
	{
	}

	ColorMapType getType() const override;
};
typedef boost::shared_ptr<ContinuousColorMap> ContinuousColorMapPtr;

struct GST_API_EXPORT DiscreteColorMap : ColorMap
{
	ColorMapDiscreteValueList values;

	DiscreteColorMap(const std::string &name) : ColorMap(name), values()
	{
	}

	DiscreteColorMap(const std::string &name,
					 const ColorMapDiscreteValueList &values,
					 const Geometry::IGeometry::Color &nodataColor,
					 const std::string &regex,
					 long accessLevelId,
					 bool nodataTransparentForGrids = false)
		: ColorMap(name,
				   nodataColor,
				   regex,
				   accessLevelId,
				   nodataTransparentForGrids)
		, values(values)
	{
	}

	ColorMapType getType() const override;
};
typedef boost::shared_ptr<DiscreteColorMap> DiscreteColorMapPtr;
} // namespace ClientUtils
} // namespace GST

#endif // GST_CU_COLOR_MAP_HPP__
