#include "c4d_library.h"
#include "lib_noise.h"
#include "c4d_basecontainer.h"

NoiseLib* lib_noise = NULL;

static NoiseLib *CheckLibNoise(LONG offset)
{
	return (NoiseLib*)CheckLib(NOISE_LIB, offset, (C4DLibrary**)&lib_noise);
}

#define NoiseLibCall(b, ...) 		NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, b)); \
															if (!lib || !lib->b) return; \
															(lib->b((iNoise*)this,##__VA_ARGS__))
															//(((iNoise*)this)->*lib->b)

#define NoiseLibCallR(r,b, ...)  NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, b)); \
															if (!lib || !lib->b) return r; \
															return (lib->b((iNoise*)this,##__VA_ARGS__))
															//return (((iNoise*)this)->*lib->b)

C4DNoise* C4DNoise::Alloc(LONG seed)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_Alloc)); if (!lib) return NULL;
	return (C4DNoise*)lib->NoiseLib_Alloc(seed);	
}

C4DNoise* C4DNoise::Alloc2(LONG seed)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_Alloc2)); if (!lib) return NULL;
	return (C4DNoise*)lib->NoiseLib_Alloc2(seed);	
}

void C4DNoise::Free(C4DNoise *&p)
{
	if (!p) return;
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_Free)); if (!lib) return;
  iNoise* i = (iNoise*)p;
	lib->NoiseLib_Free(i);
	p = NULL;
}

BaseContainer C4DNoise::CreateMenuContainer(Bool bIncludeNone)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_CreateMenuContainer)); 
  if (!lib) return BaseContainer();
	return lib->NoiseLib_CreateMenuContainer(bIncludeNone);
}

Bool C4DNoise::HasOctaves(NoiseType t)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_HasOctaves)); 
	if (!lib) return FALSE;
	return lib->NoiseLib_HasOctaves(t);
}

Bool C4DNoise::HasAbsolute(NoiseType t)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_HasAbsolute)); 
	if (!lib) return FALSE;
	return lib->NoiseLib_HasAbsolute(t);
}

Bool C4DNoise::HasCycles(NoiseType t)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_HasCycles)); 
	if (!lib) return FALSE;
	return lib->NoiseLib_HasCycles(t);
}

void C4DNoise::EvaluateSampleOffset(NoiseType type, Real rOctaves, Real rDelta, Real &rSampleOffset)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_EvaluateSampleOffset)); 
  if (!lib) { rSampleOffset = RCO .01; return; }
	lib->NoiseLib_EvaluateSampleOffset(type, rOctaves, rDelta, rSampleOffset);
}

void C4DNoise::GetNoisePreview(NoiseType t, IconData &dat, String *str)
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_GetNoisePreview)); 
	if (!lib) { dat.bmp = NULL; return; }
	lib->NoiseLib_GetNoisePreview(t, dat, str);
}


Real C4DNoise::Noise(NoiseType t, Bool two_d, const Vector &p, Real time, Real octaves, Bool absolute, Real sampleRad, Real detailAtt, LONG t_repeat)
{
  NoiseLibCallR(0, NoiseLib_Noise, t, two_d, p, time, octaves, absolute, sampleRad, detailAtt, t_repeat);
}

Bool C4DNoise::InitFbm(LONG lMaxOctaves, Real rLacunarity, Real h)
{
  NoiseLibCallR(FALSE, NoiseLib_InitFbm, lMaxOctaves, rLacunarity, h);
}

const Real* C4DNoise::GetFBMTable()
{
	NoiseLibCallR(NULL, NoiseLib_GetFBMTable );
}

const Real* C4DNoise::GetValueTable()
{
	NoiseLibCallR(NULL, NoiseLib_GetValueTable );
}

const Real* C4DNoise::GetImpulseTable()
{
	NoiseLibCallR(NULL, NoiseLib_GetImpulseTable );
}

const UCHAR* C4DNoise::GetPermutationTable()
{
	NoiseLib *lib = CheckLibNoise(LIBOFFSET(NoiseLib, NoiseLib_GetPermutationTable)); 
	if (!lib) return NULL;
	return lib->NoiseLib_GetPermutationTable();
}

const NoiseGradient* C4DNoise::GetNoiseGradient()
{
	NoiseLibCallR(NULL, NoiseLib_GetNoiseGradient );
}

const LONG* C4DNoise::GetPermutationTableA()
{
	NoiseLibCallR(NULL, NoiseLib_GetPermutationTableA );
}

Real C4DNoise::SNoise(Vector p)
{
	NoiseLibCallR(0.0, SNoise, p);
}

Real C4DNoise::SNoise(Vector p, Real t, LONG lRepeat)
{
	NoiseLibCallR(0.0, SNoiseR, p, t, lRepeat);
}

Real C4DNoise::Turbulence(Vector p, Real t, Real rOctaves, Bool bAbsolute, LONG lRepeat)
{
	NoiseLibCallR(0.0, Turbulence, p, t, rOctaves, bAbsolute, lRepeat);
}

Real C4DNoise::Fbm(Vector p, Real t, Real rOctaves, LONG lRepeat)
{
	NoiseLibCallR(0.0, Fbm, p, t, rOctaves, lRepeat);
}

Real C4DNoise::RidgedMultifractal(Vector p, Real t, Real rOctaves, Real rOffset, Real rGain, LONG lRepeat)
{
	NoiseLibCallR(0.0, RidgedMultifractal, p, t, rOctaves, rOffset, rGain, lRepeat);
}
