#include "customgui_splinecontrol.h"
#include "c4d_string.h"
#include "c4d_gui.h"


static CustomGuiSplineLib *lib_SplineControl = NULL;


static CustomGuiSplineLib *CheckLib(LONG offset)
{
  return (CustomGuiSplineLib*)CheckLib(CUSTOMGUI_SPLINE,offset,(C4DLibrary**)&lib_SplineControl);
}

#define SplineCall(b)       CustomGuiSplineLib *lib = CheckLib(LIBOFFSET(CustomGuiSplineLib, b)); \
                              if (!lib || !lib->b) return; \
                              (((iSpline*)this)->*(lib->b))

#define SplineCallR(a,b)     CustomGuiSplineLib *lib = CheckLib(LIBOFFSET(CustomGuiSplineLib, b)); \
                              if (!lib || !lib->b) return a; \
                              return (((iSpline*)this)->*(lib->b))

#define SplineGuiCall(b)     CustomGuiSplineLib *lib = CheckLib(LIBOFFSET(CustomGuiSplineLib, b)); \
                              if (!lib || !lib->b) return; \
                              (((iSplineCustomGui*)this)->*(lib->b))

#define SplineGuiCallR(a,b) CustomGuiSplineLib *lib = CheckLib(LIBOFFSET(CustomGuiSplineLib, b)); \
                              if (!lib || !lib->b) return a; \
                              return (((iSplineCustomGui*)this)->*(lib->b))


LONG SplineData::GetKnotCount() { SplineCallR(-1, GetKnotCount)(); }
CustomSplineKnot* SplineData::GetKnots() { SplineCallR(NULL, GetKnots)(); }
Vector SplineData::GetPoint(Real r) { SplineCallR(Vector(0, 0, 0), GetPoint)(r); }
Vector SplineData::GetPointFromX(Real r, LONG lMaxIter, Real rMaxEps) { SplineCallR(Vector(0, 0, 0), GetPointFromX)(r, lMaxIter, rMaxEps); }

void SplineData::DeleteAllPoints() { SplineCall(DeleteAllPoints)(); }
Bool SplineData::MakePointBuffer(LONG lPoints) { SplineCallR(FALSE, MakePointBuffer)(lPoints); }
Bool SplineData::MakeLinearSpline(LONG lPoints) { SplineCallR(FALSE, MakeLinearSpline)(lPoints); }
Bool SplineData::MakeSquareSpline(LONG lPoints) { SplineCallR(FALSE, MakeSquareSpline)(lPoints); }
Bool SplineData::MakeCubicSpline(LONG lPoints) { SplineCallR(FALSE, MakeCubicSpline)(lPoints); }
Bool SplineData::MakeRootSpline(LONG lPoints) { SplineCallR(FALSE, MakeRootSpline)(lPoints); }
Bool SplineData::MakeInversSpline(LONG lPoints) { SplineCallR(FALSE, MakeInversSpline)(lPoints); }
Bool SplineData::MakeSinSpline(LONG lPoints) { SplineCallR(FALSE, MakeSinSpline)(lPoints); }
Bool SplineData::MakeAbsCosSpline(LONG lPoints) { SplineCallR(FALSE, MakeAbsCosSpline)(lPoints); }
void SplineData::Flip() { SplineCall(Flip)(); }
void SplineData::Mirror() { SplineCall(Mirror)(); }
void SplineData::Maximum() { SplineCall(Maximum)(); }
void SplineData::Minimum() { SplineCall(Minimum)(); }
void SplineData::SetRound(Real r) { SplineCall(SetRound)(r); }
Real SplineData::GetRound() { SplineCallR(0, GetRound)(); }
void SplineData::SortKnots(LONG &lActiveKnot) { SplineCall(SortKnots)(lActiveKnot); }
LONG SplineData::InsertKnot(Real x, Real y, LONG lFlags) { SplineCallR(-1, InsertKnot)(x, y, lFlags); }
Bool SplineData::DeleteKnot(LONG a) { SplineCallR(FALSE, DeleteKnot)(a); }
LONG SplineData::GetSelectCount() { SplineCallR(0, GetSelectCount)(); }


SplineControlFunctionTable SplineControlInternalFunctionTable;
SplineControlMessagesF SplineControlFunctions;

void SplineCustomGui::SetMessageFunctions(SplineControlMessages* pFuncs)
{
  CustomGuiSplineLib *lib = CheckLib(LIBOFFSET(CustomGuiSplineLib, SetMessageFunctions));
  if (!lib || !lib->SetMessageFunctions) return;

  SplineControlFunctionTable* f = &SplineControlInternalFunctionTable;
  ClearMem(f, sizeof(SplineControlFunctionTable), 0);
  
  f->KnotMoved = &SplineControlMessagesF::KnotMoved;
  f->KnotInserted = &SplineControlMessagesF::KnotInserted;

  (((iSplineCustomGui*)this)->*(lib->SetMessageFunctions))(f, sizeof(SplineControlFunctionTable), &SplineControlFunctions, pFuncs);
}


SplineData* SplineCustomGui::GetSplineData(void) { SplineGuiCallR(NULL, GetSplineData)(); }
Bool SplineCustomGui::SetSpline(SplineData* pData) { SplineGuiCallR(FALSE, SetSpline)(pData); }
void SplineCustomGui::SetGridLineCountH(LONG l) { SplineGuiCall(SetGridLineCountH)(l); }
void SplineCustomGui::SetGridLineCountV(LONG l) { SplineGuiCall(SetGridLineCountV)(l); }
LONG SplineCustomGui::GetGridLineCountH() { SplineGuiCallR(0, GetGridLineCountH)(); }
LONG SplineCustomGui::GetGridLineCountV() { SplineGuiCallR(0, GetGridLineCountV)(); }
void SplineCustomGui::SetLabelText(String* strXMin, String* strXMax, String* strYMin, String* strYMax, String* strX, String* strY)
  { SplineGuiCall(SetLabelText)(strXMin, strXMax, strYMin, strYMax, strX, strY); }

Bool SplineData::GetRange(Real* xmin, Real* xmax, Real* xsteps, Real* ymin, Real* ymax, Real* ysteps)
  { SplineCallR(FALSE, GetRange)(xmin, xmax, xsteps, ymin, ymax, ysteps); }

void SplineData::SetRange(Real xmin, Real xmax, Real xsteps, Real ymin, Real ymax, Real ysteps)
  { SplineCall(SetRange)(xmin, xmax, xsteps, ymin, ymax, ysteps); }

Bool CustomSplineKnot::operator == (CustomSplineKnot& k)
{
  return vPos == k.vPos && lFlags == k.lFlags && bSelect == k.bSelect;
}

Bool CustomSplineKnot::operator != (CustomSplineKnot& k)
{
  return !(*this == k);
}

// version 0 functions
void SplineControlMessagesF::KnotMoved(SplineControlMessages* pFuncs, Real x, Real y)
{
  pFuncs->KnotMoved(x, y);
}

void SplineControlMessagesF::KnotInserted(SplineControlMessages* pFuncs, LONG lKnot, Real x, Real y)
{
  pFuncs->KnotInserted(lKnot, x, y);
}
