#ifndef GEOMETRY_EX_H
#define GEOMETRY_EX_H

#include "Vector.h"

#ifndef USE_MS_GEOMETRY

namespace PsimagLite
{

template <typename RealType, typename InputType>
class GeometryEx
{

public:

	typedef typename Vector<RealType>::Type VectorRealType;

	GeometryEx()
	    : meshLength_(0)
	    , enabled_(false)
	    , meshStep_(0)
	{
	}

	GeometryEx(InputType& io, SizeType meshPoints)
	    : meshLength_(static_cast<SizeType>(sqrt(meshPoints)))
	    , enabled_(false)
	    , meshStep_((meshLength_ > 0)
		      ? static_cast<RealType>(2 * M_PI / meshLength_)
		      : 0)
	{
		String str;
		try {
			io.readline(str, "GeometryKind=", false);
		} catch (std::exception&) {
			io.readline(str, "gt0:GeometryKind=", false);
		}

		if (str == "star")
			enabled_ = true;
	}

	template <class Archive>
	void write(Archive& ar, const unsigned int)
	{
		ar& meshLength_;
		ar& enabled_;
		ar& meshStep_;
	}

	template <typename SomeMemResolvType>
	SizeType memResolv(SomeMemResolvType& mres, SizeType x, String msg) const
	{
		String str = msg;
		str += "GeometryEx";
		const char* start = (const char*)&meshLength_;
		const char* end = (const char*)&enabled_;
		SizeType total = mres.memResolv(&meshLength_, end - start, str + " meshLength");

		start = end;
		end = (const char*)&meshStep_;
		total += mres.memResolv(&enabled_, end - start, str + " enabled");

		assert(x > total);
		total += mres.memResolv(&meshStep_, x - total, str + " meshStep");

		return total;
	}

	SizeType dimension(SizeType = 0) const
	{
		assert(enabled_);
		return 2;
	}

	void index2Rvector(SizeType, VectorRealType& rvector) const
	{
		assert(enabled_);
		rvector.resize(2);
		rvector[0] = 0;
		rvector[1] = 0;
	}

	void index2Kvector(SizeType, VectorRealType& kvector) const
	{
		assert(enabled_);
		kvector.resize(2);
		kvector[0] = 0;
		kvector[1] = 0;
	}

	//! Number of symmetry operations for this K Geometry.
	SizeType nGroupK() const
	{
		assert(enabled_);
		return 1;
	}

	SizeType ickequ(SizeType j, SizeType) const
	{
		assert(enabled_);
		return j;
	}

	void getMeshVector(VectorRealType& kvector, SizeType k) const
	{
		assert(enabled_);
		int k1 = k;
		int m = meshLength_;
		div_t q = PsimagLite::div(k1, m);
		kvector[0] = -M_PI + q.quot * meshStep_;
		kvector[1] = -M_PI + q.rem * meshStep_;
	}

	SizeType sizeOfMesh() const
	{
		assert(enabled_);
		return meshLength_ * meshLength_;
	}

private:

	SizeType meshLength_;
	bool enabled_;
	RealType meshStep_;
};

} // namespace PsimagLite

#else

#include "msGeometry.h"

namespace PsimagLite
{

template <typename RealType, typename InputType>
class GeometryEx
{

public:

	typedef typename Vector<RealType>::Type VectorRealType;

	GeometryEx(InputType& io, SizeType meshPoints)
	{
		SizeType ly = 2;
		SizeType lx = 2;
		std::cerr
		    << "WARNING: GeometryEx(): lattice of 2x2 hard wired\n";
		msGeometryInit2D(lx, 0, 0, ly, meshPoints);
	}

	~GeometryEx() { msGeometryEnd(); }

	SizeType dimension(SizeType i = 0) const { return msGeometryDim(); }

	void index2Rvector(SizeType r, VectorRealType& rvector) const
	{
		return msGeometryIndex2Rvector(r, rvector);
	}

	void index2Kvector(SizeType k, VectorRealType& kvector) const
	{
		return msGeometryIndex2Kvector(k, kvector);
	}

	//! Number of symmetry operations for this K Geometry.
	SizeType nGroupK() const { return msGeometryNgroupK(); }

	SizeType ickequ(SizeType j, SizeType op) const
	{
		return msGeometryIckequ(j, op);
	}

	void getMeshVector(VectorRealType& kvector, SizeType k) const
	{
		return msGeometryGetMeshVector(kvector, k);
	}

	SizeType sizeOfMesh() const { return msGeometrySizeOfMesh(); }
};

} // namespace PsimagLite
#endif

#endif // GEOMETRY_EX_H
