/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef _CUSTOMGUI_SPLINE_H_
#define _CUSTOMGUI_SPLINE_H_

#include "customgui_base.h"
#include "c4d_customdatatype.h"
#include "c4d_basecontainer.h"
#include "c4d_gui.h"


#define CUSTOMGUI_SPLINE        1009059 
#define CUSTOMDATATYPE_SPLINE   1009060 

enum
{
	SPLINECONTROL_GRID_H          = 10000,   // shows the horizontal grid
	SPLINECONTROL_GRID_V,                    // shows the vertical grid
	SPLINECONTROL_VALUE_EDIT_H,              // show X edit box
	SPLINECONTROL_VALUE_EDIT_V,              // show Y edit box
	SPLINECONTROL_VALUE_LABELS_H,            // show labels on the X axis
	SPLINECONTROL_VALUE_LABELS_V,            // show labels on the Y axis
	SPLINECONTROL_X_MIN,                     // min. X
	SPLINECONTROL_X_MAX,                     // max. X
	SPLINECONTROL_X_STEPS,                   // X steps (for the edit box)
	SPLINECONTROL_Y_MIN,                     // min. Y
	SPLINECONTROL_Y_MAX,                     // max. Y
	SPLINECONTROL_Y_STEPS,                   // Y steps (for the edit box)
	SPLINECONTROL_PRESET_BTN,                // has preset button
	SPLINECONTROL_ROUND_SLIDER,              // has tension slider
	SPLINECONTROL_GRIDLINES_H,               // number of horizontal grid lines
	SPLINECONTROL_GRIDLINES_V,               // number of vertical grid lines
	SPLINECONTROL_MINSIZE_H,                 // minimal horizontal size
	SPLINECONTROL_MINSIZE_V,                 // minimal vertical size
	SPLINECONTROL_X_MIN_TEXT,                // xmin label text
	SPLINECONTROL_X_MAX_TEXT,                // xmax label text
	SPLINECONTROL_Y_MIN_TEXT,                // xmin label text
	SPLINECONTROL_Y_MAX_TEXT,                // xmax label text
	SPLINECONTROL_X_TEXT,                    // x label text
	SPLINECONTROL_Y_TEXT,                    // y label text
	SPLINECONTROL_NEW_NO_HORIZ,              // new knots can't be moved horizontally
	SPLINECONTROL_NEW_NO_VERT,               // new knots can't be moved vertically

	SPLINECONTROL_HIDE_GRID_H,               // hide the horizontal grid
	SPLINECONTROL_HIDE_GRID_V,               // hide the vertical grid
	SPLINECONTROL_HIDE_PRESET_BTN,           // hide preset button
	SPLINECONTROL_HIDE_ROUND_SLIDER,         // hide tension slider
	SPLINECONTROL_HIDE_VALUE_EDIT_H,         // hide X edit box
	SPLINECONTROL_HIDE_VALUE_EDIT_V,         // hide Y edit box
	SPLINECONTROL_HIDE_VALUE_LABELS_H,       // hide labels on the X axis
	SPLINECONTROL_HIDE_VALUE_LABELS_V,       // hide labels on the Y axis

	_SPLINECONTROL_DUMMY_
};

#define SPLINE_KNOT_FLAG_NO_HORIZ_MOVE    2
#define SPLINE_KNOT_FLAG_NO_VERT_MOVE     4

#define SPLINE_KNOT_GET_ID(flags)          ((flags >> 16) & 0x0000ffff)
#define SPLINE_KNOT_SET_ID(flags, flag_id) (flags = (flags & 65535) | ((flag_id & 0x0000ffff) << 16))

struct CustomSplineKnot
{
	Vector vPos;
	LONG lFlags; // the upper 16 bits are used for the point index - do not modify these bits
	Bool bSelect; // internal select state - DO NOT USE

	Bool operator == (CustomSplineKnot& k);
	Bool operator != (CustomSplineKnot& k);

};

class SplineData : public iCustomDataType<SplineData>
{
private:
	SplineData();
	~SplineData();
public:
	static SplineData* Alloc();
	static void Free(SplineData *&pData);

	LONG GetKnotCount();
	CustomSplineKnot* GetKnots();

	Vector GetPoint(Real r);
	// Vector GetPointFromX(Real r, LONG lMaxIter = 10, Real rMaxEps = 0.01); removed in 8.6 - use GetPoint instead

	void DeleteAllPoints();
	Bool MakePointBuffer(LONG lPoints = -1);

	Bool MakeLinearSpline(LONG lPoints = -1);
	Bool MakeSquareSpline(LONG lPoints = -1);
	Bool MakeCubicSpline(LONG lPoints = -1);
	Bool MakeRootSpline(LONG lPoints = -1);
	Bool MakeInversSpline(LONG lPoints = -1);
	Bool MakeSinSpline(LONG lPoints = -1);
	Bool MakeAbsCosSpline(LONG lPoints = -1);
	Bool MakeUserSpline(const String &str, LONG lPoints = -1);

	void SelectAll();
	void Flip();
	void Mirror();
	void Maximum();
	void Minimum();

	void SetRound(Real r);
	Real GetRound();
	void SortKnots(LONG &lActiveKnot);
	LONG GetSelectCount();

	// only used if the spline is shown in the spline gui
	Bool GetRange(Real* xmin, Real* xmax, Real* xsteps, Real* ymin, Real* ymax, Real* ysteps); // returns FALSE if no values weere set before
	void SetRange(Real xmin, Real xmax, Real xsteps, Real ymin, Real ymax, Real ysteps);

	LONG InsertKnot(Real x, Real y, LONG lFlags = 0);
	Bool DeleteKnot(LONG a);
};

class SplineControlMessages
{
public:
	virtual void KnotMoved(Real x, Real y) { }
	virtual void KnotInserted(LONG lKnot, Real x, Real y) { }
};

class SplineCustomGui : public BaseCustomGui<CUSTOMGUI_SPLINE>
{
	SplineCustomGui();
	~SplineCustomGui();

public:
	void SetMessageFunctions(SplineControlMessages* pFuncs);

	SplineData* GetSplineData(void);
	Bool SetSpline(SplineData* pData);
	void SetGridLineCountH(LONG l);
	void SetGridLineCountV(LONG l);
	LONG GetGridLineCountH();
	LONG GetGridLineCountV();
	void SetLabelText(String* strXMin = NULL, String* strXMax = NULL, String* strYMin = NULL, String* strYMax = NULL, String* strX = NULL, String* strY = NULL);
};



// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

class SplineControlMessagesF
{
public:
	// version 0
	void KnotMoved(SplineControlMessages* pFuncs, Real x, Real y);
	void KnotInserted(SplineControlMessages* pFuncs, LONG l, Real x, Real y);
};

struct SplineControlFunctionTable
{
	// spline control version 0
	void    (SplineControlMessagesF::*KnotMoved)(SplineControlMessages* pFuncs, Real x, Real y);
	void    (SplineControlMessagesF::*KnotInserted)(SplineControlMessages* pFuncs, LONG l, Real x, Real y);

	void* dummy[(15 - 2) * C4DPL_MEMBERMULTIPLIER];
};

#ifndef _INTERNAL_DEF_
	class iSplineCustomGui
	{
	};
	class iSpline 
	{
	};
#else
	class iSplineCustomGui;
	class iSpline;
#endif

struct CustomGuiSplineLib : public BaseCustomGuiLib
{
	LONG              (iSpline::*GetKnotCount)();
	CustomSplineKnot* (iSpline::*GetKnots)();

	Vector            (iSpline::*GetPoint)(Real r);
	Vector            (iSpline::*GetPointFromX)(Real r, LONG lMaxIter, Real rMaxEps);

	void              (iSpline::*DeleteAllPoints)();
	Bool              (iSpline::*MakePointBuffer)(LONG lPoints);
									 
	Bool              (iSpline::*MakeLinearSpline)(LONG lPoints);
	Bool              (iSpline::*MakeSquareSpline)(LONG lPoints);
	Bool              (iSpline::*MakeCubicSpline)(LONG lPoints);
	Bool              (iSpline::*MakeRootSpline)(LONG lPoints);
	Bool              (iSpline::*MakeInversSpline)(LONG lPoints);
	Bool              (iSpline::*MakeSinSpline)(LONG lPoints);
	Bool              (iSpline::*MakeAbsCosSpline)(LONG lPoints);
 
	
	void              (iSpline::*Flip)();
	void              (iSpline::*Mirror)();
	void              (iSpline::*Maximum)();
	void              (iSpline::*Minimum)();
									 
	void              (iSpline::*SetRound)(Real r);
	Real              (iSpline::*GetRound)();
	void              (iSpline::*SortKnots)(LONG &lActiveKnot);
									 
	LONG              (iSpline::*InsertKnot)(Real x, Real y, LONG lFlags);
	Bool              (iSpline::*DeleteKnot)(LONG a);
	LONG              (iSpline::*GetSelectCount)();


	void          (iSplineCustomGui::*SetMessageFunctions)(SplineControlFunctionTable* f, LONG lSize, SplineControlMessagesF *pControl, SplineControlMessages* pFunctions);
	SplineData*   (iSplineCustomGui::*GetSplineData)(void);
	Bool          (iSplineCustomGui::*SetSpline)(SplineData* pData);
	void          (iSplineCustomGui::*SetGridLineCountH)(LONG l);
	void          (iSplineCustomGui::*SetGridLineCountV)(LONG l);
	LONG          (iSplineCustomGui::*GetGridLineCountH)();
	LONG          (iSplineCustomGui::*GetGridLineCountV)();
	void          (iSplineCustomGui::*SetLabelText)(String* strXMin, String* strXMax, String* strYMin, String* strYMax, String* strX, String* strY);

	Bool          (iSpline::*GetRange)(Real* xmin, Real* xmax, Real* xsteps, Real* ymin, Real* ymax, Real* ysteps);
	void          (iSpline::*SetRange)(Real xmin, Real xmax, Real xsteps, Real ymin, Real ymax, Real ysteps);

	SplineData*   (*Spline_Alloc)();
	void          (*Spline_Free)(SplineData *&pData);
	void          (iSpline::*SelectAll)();
	Bool          (iSpline::*MakeUserSpline)(const String &str, LONG lPoints);
};

// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF
// INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF -- INTERNAL STUFF

#endif
