#ifndef __C4DBASEOBJECT_H
#define __C4DBASEOBJECT_H

#include "c4d_baselist.h"
#include "c4d_basecontainer.h"
#include "operatingsystem.h"

class BaseTag;
class BaseDocument;
class BaseTrack;
class BaseContainer;
class LineObject;
class BaseThread;
class BaseSelect;
class Neighbor;

#define MODE_ON    0
#define MODE_OFF   1
#define MODE_UNDEF 2

struct Polygon
{
	Polygon(void) {}
	Polygon(LONG t_a, LONG t_b, LONG t_c) { a=t_a; b=t_b; c=d=t_c; }
	Polygon(LONG t_a, LONG t_b, LONG t_c, LONG t_d) { a=t_a; b=t_b; c=t_c; d=t_d; }

	LONG a,b,c,d;
};

struct Tangent
{
	Vector vl,vr;
};

struct Segment
{
	LONG	cnt;
	Bool	closed;
};

struct ObjectColorProperties
{
	LONG		usecolor;
	Vector	color;
	Bool		xray;
};

class HierarchyHelp
{
	private:
		HierarchyHelp(void);
	public:
		Real GetLOD(void) { return C4DOS.Bd->HhGetLOD(this); }
		LONG GetVFlags(void) { return C4DOS.Bd->HhGetVFlags(this); }
		Matrix			 GetMg(void) { return C4DOS.Bd->HhGetMg(this); }
		BaseThread   *GetThread(void) { return C4DOS.Bd->HhGetThread(this); }
		BaseDocument *GetDocument(void) { return C4DOS.Bd->HhGetDocument(this); }
		void AddVFlags(LONG mask) { C4DOS.Bd->HhAddVFlags(this,mask); }
};

class BaseObject : public BaseList2D
{
	private:
		BaseObject(void);
	public:
		BaseObject *GetNext    (void) { return (BaseObject*)AtCall(GetNext)(); }
		BaseObject *GetPred    (void) { return (BaseObject*)AtCall(GetPred)(); }
		BaseObject *GetUp      (void) { return (BaseObject*)AtCall(GetUp)(); }
		BaseObject *GetDown    (void) { return (BaseObject*)AtCall(GetDown)(); }
		BaseObject *GetDownLast(void) { return (BaseObject*)AtCall(GetDownLast)(); }

		Real	 GetVisibility(Real parent);

		Vector GetPos(void) { return C4DOS.Bo->GetPos(this); }
		void	 SetPos(const Vector &v) { C4DOS.Bo->SetPos(this,v); }
		
		Vector GetScale(void) { return C4DOS.Bo->GetScale(this); }
		void   SetScale(const Vector &v) { C4DOS.Bo->SetScale(this,v); }
		
		Vector GetRot(void) { return C4DOS.Bo->GetRot(this); }
		void	 SetRot(const Vector &v) { C4DOS.Bo->SetRot(this,v); }

		Matrix GetMl(void) { return C4DOS.Bo->GetMl(this); }
		void   SetMl(const Matrix &m, Bool force=TRUE) { C4DOS.Bo->SetMl(this,m,force); }
 		
		Matrix GetMg(void) { return C4DOS.Bo->GetMg(this); }
		void   SetMg(const Matrix &m, Bool force=TRUE) { C4DOS.Bo->SetMg(this,m,force); }

		Matrix GetMln(void);
		Matrix GetMgn(void);
		Matrix GetUpMg(void) { return C4DOS.Bo->GetUpMg(this); }

		Vector GetMp (void) { return C4DOS.Bo->GetMp(this); }
		Vector GetRad(void) { return C4DOS.Bo->GetRad(this); }

		LONG	 GetEditorMode(void); 
		void   SetEditorMode(LONG mode);
		
		LONG	 GetRenderMode(void); 
		void   SetRenderMode(LONG mode);
		
		Bool	 GetDeformMode(void);	
		void   SetDeformMode(Bool mode);

		LONG   GetUniqueIP(void);
		void	 SetUniqueIP(LONG ip);

		BaseTag     *GetFirstTag(void);
		BaseTag			*GetTag(LONG type, LONG nr=0) { return C4DOS.Bo->GetTag(this,type,nr); }
		void				*GetTagData(LONG type, LONG nr=0) { return C4DOS.Bo->GetTagData(this,type,nr); }
		LONG				GetTagDataCount(LONG type) { return C4DOS.Bo->GetTagDataCount(this,type); }
		BaseTag			*MakeTag (LONG type, BaseTag *pred=NULL);
		VariableTag *MakeVariableTag(LONG type, LONG count, BaseTag *pred=NULL);
		void				InsertTag(BaseTag *tp, BaseTag *pred=NULL);
		void        KillTag (LONG type, LONG nr=0);

		BaseObject	*GetCache(HierarchyHelp *hh=NULL) { return C4DOS.Bo->GetCache(this,hh); }
		BaseObject	*GetDeformCache(void) { return C4DOS.Bo->GetDeformCache(this); }
		LineObject	*GetIsoparm(void) { return C4DOS.Bo->GetIsoparm(this); }
		void				SetIsoparm(LineObject *l);
		BaseObject  *GetCacheParent(void);

		Bool				CopyTagsTo(BaseObject *dest, LONG visible, LONG variable, LONG hierarchical, AliasTrans *trans); 

		Bool				SetPhong(Bool on, Bool anglelimit, Real angle);

		Bool				IsDirty(LONG flags)  { return C4DOS.Bo->IsDirty(this,flags); }
		ULONG				GetDirty(LONG flags) { return C4DOS.Bo->GetDirty(this,flags); }
		void				SetDirty(LONG flags) { C4DOS.Bo->SetDirty(this,flags); }
		Bool				CheckCache(HierarchyHelp *hh) { return C4DOS.Bo->CheckCache(this,hh); }
		void				Touch(void);

		void				SetColorProperties(ObjectColorProperties *prop);
		void				GetColorProperties(ObjectColorProperties *prop);

		SplineObject *GetRealSpline(void);

		static BaseObject *Alloc(LONG type);
		static void Free(BaseObject *&bl);
};

class CameraObject: public BaseObject
{
	private:
		CameraObject(void);
	public:
		LONG				GetProjection(void);
		Real				GetFocus(void);
		Real				GetZoom(void);
		Vector			GetOffset(void);
		Real				GetAperture(void);
		Bool				SetProjection(LONG projection);
		Bool				SetFocus(Real v);
		Bool				SetAperture(Real v);
		Bool				SetZoom(Real zoom);
		Bool				SetOffset(const Vector &offset);

		static CameraObject *Alloc();
		static void Free(CameraObject *&bl);
};

class PointObject: public BaseObject
{
	private:
		PointObject(void);
	public:
		BaseSelect	*GetPointS(void);
		BaseSelect	*GetPointH(void);
		
		Vector			*GetPoint(void) { return (Vector*)GetTagData(Tpoint); }
		LONG				GetPointCount(void) { return GetTagDataCount(Tpoint); }

		Real				*CalcVertexMap(BaseObject *modifier);

		Bool				ResizeObject(LONG pcnt);
};

struct Line
{
	Real t,pos;
};

class LineObject : public PointObject
{
	private:
		LineObject(void);
	public:
		Segment			*GetSegment(void) { return (Segment*)GetTagData(Tsegment); }
		LONG				GetSegmentCount(void) { return GetTagDataCount(Tsegment); }
		
		Line				*GetLine(void) { return (Line*)GetTagData(Tline); }

		Bool				ResizeObject(LONG pcnt, LONG scnt);
		PolygonObject *Triangulate(Real regular, BaseThread *bt);

		static LineObject *Alloc(LONG pcnt, LONG scnt);
		static void Free(LineObject *&bl);
};

enum EdgeSelectionType
{
	EDGES_SELECTION = 0,
	EDGES_HIDDEN    = 1,
	EDGES_PHONG     = 2
};

class PolygonObject: public PointObject
{
	private:
		PolygonObject(void);
	public:
		BaseSelect	*GetPolygonS(void);
		BaseSelect	*GetPolygonH(void);

		BaseSelect	*GetEdgeS(void);
		BaseSelect	*GetEdgeH(void);
		
		BaseSelect	*GetPhongBreak(void);

		Polygon			*GetPolygon(void) { return (Polygon*)GetTagData(Tpolygon); }
		LONG				GetPolygonCount(void) { return GetTagDataCount(Tpolygon); }
		
		Bool				ResizeObject(LONG pcnt, LONG vcnt);

    BaseSelect* GetSelectedEdges(Neighbor *e, EdgeSelectionType ltype);
    Bool SetSelectedEdges(Neighbor *e, BaseSelect* pSel, EdgeSelectionType ltype);

		static PolygonObject *Alloc(LONG pcnt, LONG vcnt);
		static void Free(PolygonObject *&bl);
};

class SplineObject : public PointObject
{
	private:
		SplineObject(void);
	public:
		LONG		GetInterpolationType(void); 
		Bool		IsClosed(void);
		Vector  GetSplinePoint  (Real t, LONG segment=0, Vector *padr=NULL); 
		Vector  GetSplineTangent(Real t, LONG segment=0, Vector *padr=NULL); 
		
		Bool		InitLength(LONG segment=0, Vector *padr=NULL);
		void		FreeLength(void);
		Real		UniformToNatural(Real t); 
		Real		GetLength(void);
		Real		GetSegmentLength(LONG a, LONG b);
		Bool		SetDefaultCoeff(void);

		Bool				 ResizeObject(LONG pcnt, LONG scnt);

		Segment			 *GetSegment(void) { return (Segment*)GetTagData(Tsegment); }
		LONG				 GetSegmentCount(void) { return GetTagDataCount(Tsegment); }

		Tangent			 *GetTangent(void) {	return (Tangent*)GetTagData(Thermite2d); }
		
		LineObject   *GetLineObject(BaseDocument *doc, Real lod, BaseThread *thread=NULL); 

		static SplineObject *Alloc(LONG pcnt, LONG type);
		static void Free(SplineObject *&bl);
};

class PluginObject : public BaseObject
{
	private:
		PluginObject(void);
	public:
		BaseObject *GetAndCheckHierarchyClone(HierarchyHelp *hh, BaseObject *op, LONG flags, Bool *dirty, AliasTrans *trans, Bool allchilds);
		BaseObject *GetHierarchyClone(HierarchyHelp *hh, BaseObject *op, LONG flags, Bool *dirty, AliasTrans *trans);

		void NewDependenceList(void);					
		Bool CompareDependenceList(void);			
		void AddDependence(HierarchyHelp *hh, BaseObject *op);		
		void TouchDependenceList(void);

		Bool AddTexture(const Filename &fn, RootTextureString *priv);

		static PluginObject *Alloc(LONG type);
		static void Free(PluginObject *&bl);
};

BaseObject *GeneratePrimitive(BaseDocument *doc, LONG type, const BaseContainer &bc, Real lod, Bool isoparm, BaseThread *bt=NULL);
BaseObject *GenerateSplinePrimitive(BaseDocument *doc, LONG type, const BaseContainer &bc, Real lod, BaseThread *bt=NULL);

#define ToPoint(op)		((PointObject*)(op))
#define ToPoly(op)		((PolygonObject*)(op))
#define ToSpline(op)  ((SplineObject*)(op))

inline Vector CalcFaceNormal(Vector *padr, const Polygon &v)
{
	if (v.c==v.d)
		return !((padr[v.b]-padr[v.a])%(padr[v.c]-padr[v.a]));
	else
		return !((padr[v.b]-padr[v.d])%(padr[v.c]-padr[v.a]));
}

class Safety
{
	private:
		ObjectSafety *os;
	public:
		Safety(void);
		~Safety(void);
		Bool Init(BaseObject *op);
		void Detach(void);
};

LONG CalcLOD(LONG val, Real lod, LONG min, LONG max);
Bool DisjointMesh(PointObject *op);

SplineObject *FitCurve(Vector *padr, LONG pcnt, Real error, BaseThread *bt);
Bool Triangulate(Vector *padr, LONG pcnt, Polygon **vadr, LONG *vcnt);
Bool TriangulateStandard(Vector *padr, LONG pcnt, LONG *list, LONG lcnt, Polygon *&vadr, LONG &vcnt, BaseThread *thread);
Bool TriangulateRegular(Vector *pinp, LONG pinp_cnt, LONG *list, LONG lcnt, Vector *&padr, LONG &pcnt, Polygon *&vadr, LONG &vcnt, Real regular_width, BaseThread *thread);
BaseObject *GenerateText(BaseContainer *cp, BaseThread *bt, Bool separate);

Bool CheckDisplayFilter(BaseObject *op, LONG filter);

struct PolyInfo
{
	LONG face[4];
	LONG edge[4];
	CHAR mark[4];
};

class Neighbor
{
	private:
		EnumerateEdges *ee;
	public:
		Neighbor(void);
		virtual ~Neighbor(void);
		
		virtual Bool Init(LONG pcnt, Polygon *vadr, LONG vcnt, BaseSelect *bs);
		void GetEdgePolys(LONG a, LONG b,LONG *first,LONG *second) { C4DOS.Nb->GetEdgePolys(ee,a,b,first,second); }
		void GetPointPolys(LONG pnt, LONG **dadr, LONG *dcnt)  { C4DOS.Nb->GetPointPolys(ee,pnt,dadr,dcnt); }
		LONG GetEdgeCount(void);
		PolyInfo *GetPolyInfo(LONG poly) { return C4DOS.Nb->GetPolyInfo(ee,poly); }
		LONG GetNeighbor(LONG a, LONG b, LONG poly);
};

BaseObject *GetVirtualLineObject(BaseObject *op, HierarchyHelp *hh, const Matrix &mloc, Bool keep_spline, Bool recurse, Matrix *mres, Bool *dirty);

UVWTag *GenerateUVW(BaseObject *op, const Matrix &opmg, TextureTag *tp, const Matrix &texopmg, BaseView *view);

// special handling: light object
void CutReal(BaseContainer &data, LONG id, Real min, Real max);
void CutVector(BaseContainer &data, LONG id, Real min, Real max);

#endif
