/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2011 Sandro Santilli <strk@keybit.net>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation. 
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: io/WKTWriter.java rev. 1.34 (JTS-1.7)
 *
 **********************************************************************/

#ifndef GEOS_IO_WKTWRITER_H
#define GEOS_IO_WKTWRITER_H

#include <geos/export.h>

#include <string>

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
#endif

// Forward declarations
namespace geos {
	namespace geom {
		class Coordinate;
		class CoordinateSequence;
		class Geometry;
		class GeometryCollection;
		class Point;
		class LineString;
		class LinearRing;
		class Polygon;
		class MultiPoint;
		class MultiLineString;
		class MultiPolygon;
		class PrecisionModel;
	} 
	namespace io {
		class Writer;
	} 
} 


namespace geos {
namespace io {

/**
 * \class WKTWriter io.h geos.h
 *
 * \brief Outputs the textual representation of a Geometry.
 * See also WKTReader.
 * 
 * The WKTWriter outputs coordinates rounded to the precision
 * model. No more than the maximum number of necessary decimal places will be
 * output.
 * 
 * The Well-known Text format is defined in the <A
 * HREF="http://www.opengis.org/techno/specs.htm">OpenGIS Simple Features
 * Specification for SQL</A>.
 * 
 * A non-standard "LINEARRING" tag is used for LinearRings. The WKT spec does
 * not define a special tag for LinearRings. The standard tag to use is
 * "LINESTRING".
 *
 * See WKTReader for parsing.
 *
 */
class GEOS_DLL WKTWriter {
public:
	WKTWriter();
	~WKTWriter();

	//string(count, ch) can be used for this
	//static string stringOfChar(char ch, int count);

	/// Returns WKT string for the given Geometry
	std::string write(const geom::Geometry *geometry);

	// Send Geometry's WKT to the given Writer
	void write(const geom::Geometry *geometry, Writer *writer);

	std::string writeFormatted(const geom::Geometry *geometry);

	void writeFormatted(const geom::Geometry *geometry, Writer *writer);

	/**
	 * Generates the WKT for a N-point <code>LineString</code>.
	 *
	 * @param seq the sequence to outpout
	 *
	 * @return the WKT
	 */
	static std::string toLineString(const geom::CoordinateSequence& seq); 

	/**
	 * Generates the WKT for a 2-point <code>LineString</code>.
	 *
	 * @param p0 the first coordinate
	 * @param p1 the second coordinate
	 *
	 * @return the WKT
	 */
	static std::string toLineString(const geom::Coordinate& p0, const geom::Coordinate& p1);

	/**
	 * Generates the WKT for a <code>Point</code>.
	 *
	 * @param p0 the point coordinate
	 *
	 * @return the WKT
	 */
	static std::string toPoint(const geom::Coordinate& p0);
 
	/**
	 * Sets the rounding precision when writing the WKT
	 * a precision of -1 disables it
	 *
	 * @param p0 the new precision to use
	 *
	 */
	void setRoundingPrecision(int p0);

	/**
	 * Enables/disables trimming of unnecessary decimals
	 *
	 * @param p0 the trim boolean
	 *
	 */
	void setTrim(bool p0);

	/**
	 * Enable old style 3D/4D WKT generation.
	 *
	 * By default the WKBWriter produces new style 3D/4D WKT
	 * (ie. "POINT Z (10 20 30)") but if this method is used
	 * to turn on old style WKT production then the WKT will
	 * be formatted in the style "POINT (10 20 30)".
	 *
	 * @param useOld3D true or false
	 */
	void setOld3D(bool useOld3D ) { old3D = useOld3D; }

	/*
	 * \brief
	 * Returns the output dimension used by the
	 * <code>WKBWriter</code>.
	 */
	int getOutputDimension() const { return defaultOutputDimension; }

	/*
	 * Sets the output dimension used by the <code>WKBWriter</code>.  
	 *
	 * @param newOutputDimension Supported values are 2 or 3. 
	 *        Note that 3 indicates up to 3 dimensions will be
	 *        written but 2D WKB is still produced for 2D geometries.
	 */
	void setOutputDimension(int newOutputDimension);
	
protected:

  int decimalPlaces;

	void appendGeometryTaggedText(const geom::Geometry *geometry, int level, Writer *writer);

	void appendPointTaggedText(
			const geom::Coordinate* coordinate,
			int level, Writer *writer);

	void appendLineStringTaggedText(
			const geom::LineString *lineString,
			int level, Writer *writer);

	void appendLinearRingTaggedText(
			const geom::LinearRing *lineString,
			int level, Writer *writer);

	void appendPolygonTaggedText(
			const geom::Polygon *polygon,
			int level, Writer *writer);

	void appendMultiPointTaggedText(
			const geom::MultiPoint *multipoint,
			int level, Writer *writer);

	void appendMultiLineStringTaggedText(
			const geom::MultiLineString *multiLineString,
			int level,Writer *writer);

	void appendMultiPolygonTaggedText(
			const geom::MultiPolygon *multiPolygon,
			int level, Writer *writer);

	void appendGeometryCollectionTaggedText(
			const geom::GeometryCollection *geometryCollection,
			int level,Writer *writer);

	void appendPointText(const geom::Coordinate* coordinate, int level,
			Writer *writer);

	void appendCoordinate(const geom::Coordinate* coordinate,
			Writer *writer);

	std::string writeNumber(double d);

	void appendLineStringText(
			const geom::LineString *lineString,
			int level, bool doIndent, Writer *writer);

	void appendPolygonText(
			const geom::Polygon *polygon,
			int level, bool indentFirst, Writer *writer);

	void appendMultiPointText(
			const geom::MultiPoint *multiPoint,
			int level, Writer *writer);

	void appendMultiLineStringText(
			const geom::MultiLineString *multiLineString,
			int level, bool indentFirst,Writer *writer);

	void appendMultiPolygonText(
			const geom::MultiPolygon *multiPolygon,
			int level, Writer *writer);

	void appendGeometryCollectionText(
			const geom::GeometryCollection *geometryCollection,
			int level,Writer *writer);

private:

	enum {
		INDENT = 2
	};

//	static const int INDENT = 2;

	bool isFormatted;

	int roundingPrecision;

	bool trim;

	int level;

	int defaultOutputDimension;
    int outputDimension;
    bool old3D;

	void writeFormatted(
			const geom::Geometry *geometry,
			bool isFormatted, Writer *writer);

	void indent(int level, Writer *writer);
};

} // namespace geos::io
} // namespace geos

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif // #ifndef GEOS_IO_WKTWRITER_H
