/*
 *    Copyright 2012, 2013 Jan Dalheimer
 *
 *    This file is part of OpenOrienteering.
 *
 *    OpenOrienteering is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    OpenOrienteering is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
 */


#ifndef OPENORIENTEERING_DXFPARSER_H
#define OPENORIENTEERING_DXFPARSER_H

#include <QtGlobal>
#include <QChar>
#include <QColor>
#include <QFont>
#include <QLatin1Char>
#include <QList>
#include <QRectF>
#include <QString>

class QIODevice;
class QPointF;

namespace OpenOrienteering {

struct DXFCoordinate
{
	constexpr DXFCoordinate() noexcept;
	
	qreal x;
	qreal y;
	qreal z;
};

enum type_e
{
	CIRCLE, LINE, SPLINE, POINT, TEXT, ARC, UNKNOWN
};

/** Path generated by DXFParser. */
class DXFPath
{
public:
	DXFPath(type_e type);
	
	QList<DXFCoordinate> coords;
	QString layer;
	QColor  color;
	qreal   thickness;
	qreal   radius;
	type_e  type;
	qreal   rotation;
	QFont   font;
	QString text;
	qreal   start_angle;
	qreal   end_angle;
	bool    closed;
};


/**
 * Parses DXF input data into lists of path_t.
 * 
 * TODO: Should be reviewed.
 */
class DXFParser
{
public:
	DXFParser();
	void setData(QIODevice *data) { device = data; in_vertex = false; }
	QString parse();
	QList<DXFPath> getData() { return paths; }
	QRectF getSize() { return size; }

private:
	QIODevice* device;
	QList<DXFPath> paths;

	QList<DXFCoordinate> vertices;
	DXFPath vertex_main;
	bool in_vertex;

	QRectF size;

	int current_section;

	bool readNextCodeValue(QIODevice* device, int& code, QString& value);

	void parseCommon(int code, const QString& value, DXFPath& path);

	void parseLine(QIODevice *d, QList<DXFPath> *p);
	void parsePolyline(QIODevice *d, QList<DXFPath> *p);
	void parseLwPolyline(QIODevice* d, QList<DXFPath> *p);
	void parseSpline(QIODevice* d, QList<DXFPath> *p);
	void parseCircle(QIODevice *d, QList<DXFPath> *p);
	void parsePoint(QIODevice *d, QList<DXFPath> *p);
	void parseVertex(QIODevice *d, QList<DXFPath> *p);
	void parseSeqend(QIODevice *d, QList<DXFPath> *p);
	void parseText(QIODevice *d, QList<DXFPath> *p);
	void parseArc(QIODevice *d, QList<DXFPath> *p);
	void parseExtminmax(QIODevice *d, QPointF &p);
	void parseUnknown(QIODevice *d);
	
	bool atEntityEnd(QIODevice *d);

	enum{
		HEADER, ENTITIES, SECTION, NOTHING, POLYLINE
	};
};


// ### Public inline code ###

inline
constexpr DXFCoordinate::DXFCoordinate() noexcept
 : x(0.0),
   y(0.0),
   z(0.0)
{
	; // nothing
}

inline
DXFPath::DXFPath(type_e type)
 : layer(QLatin1Char('1')),
   color(127,127,127),
   thickness(0),
   radius(0),
   type(type),
   rotation(0.0),
   start_angle(0.0),
   end_angle(0.0),
   closed(false)
{
	; // nothing
}

inline
DXFParser::DXFParser()
 : device(0),
   vertex_main(UNKNOWN)
{
	; // nothing
}


}  // namespace OpenOrienteering

#endif
