#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,
  SPLINECONTROL_GRID_V,
  SPLINECONTROL_VALUE_EDIT_H,
  SPLINECONTROL_VALUE_EDIT_V,
  SPLINECONTROL_VALUE_LABELS_H,
  SPLINECONTROL_VALUE_LABELS_V,
  SPLINECONTROL_X_MIN,
  SPLINECONTROL_X_MAX,
  SPLINECONTROL_X_STEPS,
  SPLINECONTROL_Y_MIN,
  SPLINECONTROL_Y_MAX,
  SPLINECONTROL_Y_STEPS,
  SPLINECONTROL_PRESET_BTN,
  SPLINECONTROL_ROUND_SLIDER,
  SPLINECONTROL_GRIDLINES_H,
  SPLINECONTROL_GRIDLINES_V,
  SPLINECONTROL_MINSIZE_H,
  SPLINECONTROL_MINSIZE_V,
  SPLINECONTROL_X_MIN_TEXT,
  SPLINECONTROL_X_MAX_TEXT,
  SPLINECONTROL_Y_MIN_TEXT,
  SPLINECONTROL_Y_MAX_TEXT,
  SPLINECONTROL_X_TEXT,
  SPLINECONTROL_Y_TEXT,
  SPLINECONTROL_NEW_NO_HORIZ,
  SPLINECONTROL_NEW_NO_VERT,

  _SPLINECONTROL_DUMMY_
};

#define SPLINE_KNOT_FLAG_NO_HORIZ_MOVE    2
#define SPLINE_KNOT_FLAG_NO_VERT_MOVE     4

struct CustomSplineKnot
{
  Vector vPos;
  LONG lFlags;
  Bool bSelect; // internal select state - DO NOT USE

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

};

class SplineData : public iCustomDataType<SplineData>
{
private:
  SplineData() { }
public:
  LONG GetKnotCount();
  CustomSplineKnot* GetKnots();

  Vector GetPoint(Real r);
  Vector GetPointFromX(Real r, LONG lMaxIter = 10, Real rMaxEps = 0.01); // 0 <= x <= 1 and 0 <= y <= 1

  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);

  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();

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);
};

// 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
