/***************************************************************************
 *   Copyright (C) 2004 by Juergen Thies                                   *
 *   layout@juergenthies.de                                                *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef ELEMENT_H
#define ELEMENT_H
#include "general/layoutimagepainter.h"
#include "general/drawpixmap.h"
#include <qdatastream.h>
#include "pointarray.h"
#include <QTextStream>
#include "general/layers.h"
#include <qbitarray.h>
#include <math.h>
#include <qstring.h>
#include "general/setup.h"
#include "strans.h"
#include "widgets/selectwidget.h"
#include <QList>
#include "propertylist.h"
#include "layertranslator.h"
#ifdef USE_3d
#include "3d/dxf3d.h"
#endif

/**
@author Juergen Thies
*/
//#define layer_nr layerNum
class cell;
class polygon;
class box;
class cellref;
class cellrefArray;
class elementList;
class drawingField;
class txt;
class path;
class cif;
class gds;
class oasis;
class svg;
class csv;
class strans;
class gerber;
class drc;
class odb;
class eps;
class dxf;
class source;
//! element of the drawing
/*!
A single element of the drawing. 
*/
class element {
public:
//! layer of element
/*!
The layer number of a element.
It has no function for cellRefs and CellRefsArrays.
*/
    qint16 layerNum;
    qint16 getDefautLayer(){ if (layers::num[layerNum].visible) return layerNum; return -1;};
//! datatype of element
/*!
The datatype is a additional property of each element.
*/
    qint16 datatype;
//! select
/*!
If set to true the whole element is selected. To select a single point use pSelect.
*/
    bool select;
    QList<propertyItem> property;
    virtual void addProperty(const QList<propertyItem>);
    virtual void addProperty(const propertyItem);
    virtual void saveGDSProperty(gds *g);
    virtual void saveOASISProperty( oasis *o);
    element();
    virtual ~element();
    virtual void paint(layoutImagePainter * ) {}
    virtual void paintSelect(layoutImagePainter * ) {}
    virtual void paintSelected(layoutImagePainter * ) {}
    virtual void paintNode(int , layoutImagePainter *){}
    virtual void paintDevice(QString , layoutImagePainter *){}
    virtual void paintDeviceNode(QString ,int, layoutImagePainter *){}
    virtual void paintHighlighted(QPainter *,strans  ) {}
    virtual void paintHighlighted(QPainter *,strans ,QPoint ) {}
    virtual void paintHighlightedBackground(QPainter *po,strans trans_ );
    virtual void paintSize(QPainter *,strans  , double ) {}
    virtual void paintDistance(QPainter *,strans  , double ,element *) {}
    virtual void paintInfo(QPoint *,QPoint *,uint *)const{}
    virtual void fSelect(QRect ) {}
    virtual void fSelectLayer(QRect r,qint16 layer) { if(layerNum==layer)fSelect(r);}
    virtual void fAllSelect(QRect ) {}
    virtual void pSelect(QRect ) {}
    virtual void cSelect(QRect ) {}
    virtual void fDeselect(QRect ) {}
    virtual void fDeselectLayer(QRect r,qint16 layer) { if(layerNum==layer)fDeselect(r);}
    virtual void fAllDeselect(QRect ) {}
    virtual void pDeselect(QRect ) {}
    virtual void cDeselect(QRect ) {}
//! select all
/*!
Selects this element completely. To select single points use pselect.
*/
    virtual void selectAll() { select=true; }
//! invert select
/*!
The selection of this element is inverted.
*/
    virtual void invertSelect() {select= !select;}
//! select visible
/*!
Selects this element if it is visible.
*/
    virtual void selectVisible() { if (layers::num[layerNum].visible) { select=true; } }
//! deselect
/*!
Deselect this element and all points of this element.
*/
    virtual void deselectAll() { select=false; }
    virtual void selectLayer(int){}
    virtual void deselectLayer(int){}
    virtual void minimum(QPoint *) {}
    virtual void maximum(QPoint *) {}
    virtual void minimumSelect(QPoint *) {}
    virtual void maximumSelect(QPoint *) {}
   /* virtual int minSize() {return 0;}
    virtual int minSizeSelect() {if (select) return minSize(); else return 0;}*/
    virtual bool drcMinSize(int ,drc *,bool sharpAngles=true) {return true;sharpAngles=true;}
    virtual bool drcMinDistance(int ,drc *,element *) {return true;}
    virtual bool drcEnclosure(int ,drc *,element *) {return true;}
    virtual bool drcOnGrid(int ,int ){return true;}
    virtual bool drcAngle90(drc *){return true;}
    virtual bool drcAngle45(drc *){return true;}
    virtual bool drcAngle(double,drc *){return true;}
    virtual bool drcNotch(int ,drc *){return true;}
    virtual bool hasHoles(){return false;}
//! delete if selected
/*!
Delete selected points of this element.
*/
    virtual void deleteSelect() {}
    virtual void moveSelect(QPoint) {}
    virtual void move(QPoint ) {}
    virtual void moveOrigin(QPoint ) {}
    virtual void moveToLayer(int layer) { layerNum=layer;}
    virtual void moveToLayerSelect(int layer) { if (select) layerNum=layer;}
    virtual void mapLayer(layerTranslator *t){layerNum=t->map(layerNum);}
    virtual void saveGDS(gds *) {}
    virtual void saveDXF(dxf *) {}
#ifdef USE_3d
    virtual void saveDXF3d(dxf3d*){}
#endif
    virtual void saveOASIS( oasis *);
    virtual void saveCIF( cif *){}
    virtual void saveGerber( gerber *){}
    virtual void saveSelect(QDataStream *){}
    virtual void saveSVG(svg *){}
    virtual void saveCSV( csv *){}
    virtual void saveODB( odb *){}
    virtual void saveSOURCE( source *){}
    virtual void saveEPS(eps *){}
    virtual void save(QDataStream *){}
    virtual int saveEPSCount(){ return 0;}
    virtual void mapSelect(strans ) {}
    virtual void map(strans ) {}
    virtual void resize(double ) {}
    virtual void resize(double s,int, bool *){resize(s);}
    virtual void clean() {}
    virtual void sizeadjustSelect(int ) {}
    virtual void sizeadjustSelect(int ,int) {}
    virtual void modifyCornersSelect(double ,double){}
    virtual bool correct() { return true; }
    virtual void roundSelect(int) {}
    virtual elementList* cutSelect(QPoint , QPoint ) { return NULL;}
    virtual double areaSelect() { return 0; }
    virtual double areaSelected() { return 0; }
    virtual double circumferenceSelect() { return 0; }
    virtual double circumferenceSelected() { return 0; }
    virtual double nearestDistance(QPoint) { return 1E99; }
    virtual double nearestDistance(const QPoint, QPoint *)const { return 1E99; }
	virtual double nearestDistancePoint(const QPoint p1, QPoint *p2)const { return nearestDistance(p1,p2); }
    virtual double nearestLine(QPoint,QPoint *,int) { return 1E99; }
    virtual double nearestMiddle(QPoint,QPoint *,int ) { return 1E99; }
    virtual double nearestCenter(QPoint,QPoint *,int) { return 1E99; }
    virtual bool pointInsideElement(QPoint){return false;}
    virtual bool showProperties(elementList *, drawingField *, bool ){return false;}
    virtual void countSelect(elementCount *){}
    virtual bool useLayer(int){return false;}
    virtual void useLayer(QBitArray *){};
    virtual elementList* convertToMesh(int , int ) { return NULL;}
    virtual double length(){return 0;}
    virtual void snapSelectGet(QHash<int,QPoint> *){}
    virtual void snapSelectSnap(QHash<int,QPoint> *,int ){}
//! set datatype
/*!
The datatype is set to t.
*/
    virtual void setDatatype(int t){ datatype=t;}
//! get datatype
/*!
The datatype is returned.
*/
    virtual int getDatatype(){ return datatype;}
//! select datatype
/*!
If the datatype is t, the element is selected.
*/
    virtual void selectDatatype( int t) {if (datatype==t) selectAll(); }
//! set datatype if selected
/*!
The datatype is set to t, if the element is selected.
*/
    virtual void setDatatypeSelect(int t) {if (select) datatype=t;}
//! get Point
/*!
@return If it is a box: Returns an array of two points: first the top left corner, second the lower right corner.
@return If it is a polygon or path: Returns a array of all point of the element.
@return If it is a cellref: Returns an array of one point: the base point of the reference.
@return If it is a cellrefarray: Returns an array of tree points: first the base point of the reference, second base point plus space in x and third base point plus space in y.
@return If it is a text: Returns an array of one point: the base point of the text.
*/
    virtual pointArray getPoints(){pointArray p; p.resize(0); return p;}
    virtual void setPoints(pointArray){}
// Element specific
//box
//! test box
/*!
@return true if element is a box otherwise false
*/
    virtual bool isBox() const { return false; }
    virtual box* getBox() { return NULL; }
    virtual box* convertToBox() { return NULL; }
    virtual polygon* convertToCircle() { return NULL; }
//polygon
//! test polygon
/*!
@return true if element is a polygon otherwise false
*/
    virtual bool isPolygon()const { return false; }
    virtual polygon* getPolygon() { return NULL;}
    virtual polygon* convertToPolygon()const { return NULL;}
    virtual bool mergeSelect(polygon *) { return false; }
    virtual void edgeRemoveSelect(int) {}
    virtual void cropSharpAnglesSelect(int ){}
    virtual bool add(pointArray *){return false;}
//! test circle
/*!
@return true if element is a regular polygon with more than 8 points. The point is set to the center point and the integer is set to the radius.
*/
    virtual bool isCircle(QPoint *, int *){return false;}
//! test circle
/*!
@return true if element is a regular polygon with more than 8 points
*/
    virtual bool isCircle(){return false;}
//cellref/cellrefarray
//! test cellRef
/*!
@return true if element is a cellRef otherwise false
*/
    virtual bool isCellref() const{ return false; }
//! test cellrefArray
/*!
@return true if element is a cellRefArray otherwise false
*/
    virtual bool isCellrefArray()const { return false;}
    virtual cellref* getCellref() { return NULL; }
    virtual cellrefArray* getCellrefArray() { return NULL;}
//! set mirror x
/*!
sets the mirror attribute for cellrefs, cellrefarrays and text element. Has no effect for other elements.
*/
    virtual void setMirrorx() {}
//! clear mirror x
/*!
clears the mirror attribute for cellrefs, cellrefarrays and text element. Has no effect for other elements.
*/
    virtual void clearMirrorx() {}
//! set mirror x
/*!
toggles the mirror attribute for cellrefs, cellrefarrays and text element. Has no effect for other elements.
*/
    virtual void toggleMirrorx() {}
    virtual void rotate(double) {}
    virtual void scale(double) {}
    virtual void setCellRef(cell *) {}
    virtual void setPos(QPoint ) {}
    virtual void setTrans(strans){}
//! depend on
/*!
@return in cellrefs and cellrefarrays a pointer to the refered cell is returned.
*/
    virtual cell* depend();
    virtual bool identical(element *){ return false;}
    virtual bool identicalStructure(element *){ return false;}
    virtual elementList* flatSelect() { return NULL;}
    virtual elementList* flatLayer(int) { return NULL;}
    // and txt;
//! set name
/*!
set the text for text element. Has no effect for other elements.
*/
    virtual void setName(QString) {}
//! get name
/*!
get the text for text element. Has no effect for other elements.
*/
    virtual QString getName() { return NULL;}
//Text
//! test text
/*!
@return true if element is a text otherwise false
*/
    virtual bool isText()const { return false; }
    virtual txt* getText(){return NULL;}
//! set presentation
/*!
set the prsentation for text element. Has no effect for other elements.
*/
    virtual void setPresentation(int){}
    virtual elementList * convertText(){return NULL;}
//! replace text
/*!
If the text is identical with the first argument, it is replaced with the second arugment.
@return true, if the text is replaced.
*/
    virtual bool replaceText(QString,QString) {return false;}
//Path
//! test path
/*!
@return true if element is a path otherwise false
*/
    virtual bool isPath()const { return false;}
    virtual path* getPath() { return NULL; }
    virtual void expandCaps(int , int){}
//Path
//! set width
/*!
Set the width for path and text-elements. 
@param width The height of a text-element/ width of a path is set to this value. Positive value result in a width in drawing-units. Negative value for size in pixel.
*/
    virtual void setWidth(int width);
//! get width
/*!
Get the width for path and text-elements. 
@return The height of a text-element/ width of a path. Positive value for a width in drawing-units. Negative value for size in pixel.
*/
    virtual int getWidth(){return 0;};
//! set cap
/*!
Set the caps for path elements. 
@param cap	0 for no caps, 1 for round caps, 2 for square caps.
*/
    virtual void setCap(int cap);
    virtual polygon* closeToPolygon(){return NULL;}
    virtual polygon* convertToPolygonIfClosed(){return NULL;}
    virtual bool mergeSelect(path *) { return false; }
//independent

    static pointArray convert(const pointArray array, const strans trans);
    //virtual QRect convert(QRect rect, drawpixmap *e);
    static pointArray convert(const QRect rect, const strans trans);
    static QPoint convert(const QPoint point,const strans trans);
    static pointArray convert(const pointArray array, const drawpixmap *e){return convert(array,e->getDrawTrans());}
    static pointArray convert(const QRect rect, const drawpixmap *e){return convert(rect,e->getDrawTrans());}
    static QPoint convert(const QPoint point,const drawpixmap *e){return convert(point,e->getDrawTrans());}
    static bool pointInRect(QPoint p,QRect rect);
	static bool cutting(QPoint p1,QPoint p2,QPoint p3,QPoint p4);
    static bool cutPoint(QPoint p1,QPoint p2,QPoint p3,QPoint p4,QPoint *pc);
    static bool cutPoint2(QPoint p1,QPoint p2,QPoint p3,QPoint p4,QPoint *pc);
    static bool cutPoint3(QPoint p1,QPoint p2,QPoint p3,QPoint p4,QPoint *pc);
    static bool cutPoint4(QPoint p1,QPoint p2,QPoint p3,QPoint p4,QPoint *pc);
    static bool parallel(QPoint p1,QPoint p2,QPoint p3,QPoint p4);
    static bool nearlyParallel(QPoint p1,QPoint p2,QPoint p3,QPoint p4);
    static bool identical(QPoint p1,QPoint p2,QPoint p3,QPoint p4);
    static bool onLine(QPoint p1,QPoint p2, QPoint p3);
    static bool onLine2(QPoint p1,QPoint p2, QPoint p3);
    static bool nearLine(QPoint p1,QPoint p2, QPoint p3);
//! angle
/*!
This function return the angle of line p1-p2 and p2-p3.
*/
    static double angle(QPoint p1, QPoint p2, QPoint p3);
//! angle
/*!
This function return the angle of line p1-p2 to the xaxis.
*/
    static double angle(QPoint p1, QPoint p2);
//! distance
/*!
This function return the shortest distance of p3 to the line p1-p2 in databaseunits.
*/
    static double distance(QPoint p1, QPoint p2, QPoint p3);
//! distance
/*!
This function return the distance between p1 and p2 in databaseunits.
*/
    static double distance(QPoint p1, QPoint p2);
    static double length(QPoint p);
    static pointArray spirale(QPoint center,QPoint p1,QPoint p2,double angelstep);
    static pointArray ellipse(QPoint center,int rx,int ry,double angelstep);
    static bool pointInPolygon(pointArray array,QPoint point);
    static bool pointOnPolygon(pointArray array,QPoint point);
    static int runden(double d);
    static QPoint runden(QPointF p){return QPoint(runden(p.x()),runden(p.y()));};
//! round
/*!
This function rounds the double d.
*/
    static int round(double d){return runden(d);}
    static QPoint round(QPoint p, int);
    virtual void nextPoint() {}
    static pointArray bezier2(QPoint pstart, QPoint pend, QPoint pbezier,int maxDepth=-2);
    static pointArray bezier3(QPoint pstart, QPoint pend, QPoint pbezierstart, QPoint pbezierend, int maxDepth=-2);
    private:
    static void bezier2(double px0, double py0,double px1, double py1,double px2, double py2,int depth, pointArray *a, int maxDepth);
    static void bezier3(double px0, double py0,double px1, double py1,double px2, double py2,double px3, double py3,int depth, pointArray *a,int maxDepth);
public:
    static pointArray fitToCircle(pointArray p, bool useLastPoint=true);
private:
    static double dotProduct( QVector<double> x, QVector<double> y) ; // für fit to circle
public:

	element * copy();

	virtual void setNode(int node);
	virtual void clearNode();
	virtual int getNode();
	virtual QList<int> getNodes(int node);
	virtual void connectNodes(int node1 ,int node2);
	void setDeviceName(QString name);
	QString getDeviceName();
	virtual void findEdge(QPoint , QPoint,int ,char ,int *){};
	virtual void lineDistanceLayer(QPoint ,QPoint , int *,int *,int , QPoint , QPoint ){};
	virtual bool pointOnLayer(QPoint ,int ){return false;}
}
;

#endif
