#include "c4d_snapplugin.h"

SnapCoreLib				*snaplib_cache;

static SnapCoreLib *CheckSnapLib(LONG offset)
{
	return (SnapCoreLib*)CheckLib(ID_SNAPCORE_LIB, offset, (C4DLibrary**)&snaplib_cache);
}

Bool SnapCore::Init( BaseDocument *doc, BaseDraw *bd, AtomArray *exclude /*= NULL*/ )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Init));
	if (!slib || !slib->Init) return FALSE;

	return (((iSnapCore*)this)->*(slib->Init))(doc, bd, exclude);
}

Bool SnapCore::Update( void )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Update));
	if (!slib || !slib->Update) return FALSE;

	return (((iSnapCore*)this)->*(slib->Update))();
}

Bool SnapCore::Snap( const Vector &p, SnapResult &result, SNAPFLAGS flags )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Snap));
	if (!slib || !slib->Snap) return FALSE;

	return (((iSnapCore*)this)->*(slib->Snap))(p, result, flags);
}

Bool SnapCore::Intersect( const Vector &p, const Vector &n, Bool plane, SnapResult &result, SNAPFLAGS flags)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Intersect));
	if (!slib || !slib->Intersect) return FALSE;

	return (((iSnapCore*)this)->*(slib->Intersect))(p, n, plane, result, flags);
}

BaseObject* SnapCore::AddInferred(BaseDocument *doc, const Matrix &mat, INFERREDGUIDETYPE type)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, AddInferred));
	if (!slib || !slib->AddInferred) return FALSE;

	return (BaseObject*)(((iSnapCore*)this)->*(slib->AddInferred))(doc, mat, type);
}

Bool SnapCore::FlushInferred( void )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, FlushInferred));
	if (!slib || !slib->FlushInferred) return FALSE;
	
	return (((iSnapCore*)this)->*(slib->FlushInferred))();
	
}

void SnapCore::SetToolObject(BaseObject* op)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, SetToolObject));
	if (!slib || !slib->SetToolObject) return;
	
	(((iSnapCore*)this)->*(slib->SetToolObject))(op);
}

SnapCore* SnapCore::Alloc( void )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Alloc));
	if (!slib || !slib->Alloc) return NULL;

	return (SnapCore*)slib->Alloc();
} 

void SnapCore::Free( SnapCore *&p )
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, Free));
	if (!slib || !slib->Free) return;

	iSnapCore *tmp = (iSnapCore*)p;
	slib->Free(tmp);
	p = NULL;
}

//////////////////////////////////////////////////////////////////////////
//!Helper functions
Bool IsSnapEnabled(BaseDocument *doc, LONG mode)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, IsSnapEnabled));
	if (!slib || !slib->IsSnapEnabled) return FALSE;

	return slib->IsSnapEnabled(mode, doc);
}

void EnableSnap(Bool state, BaseDocument *doc, LONG mode)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, EnableSnap));
	if (!slib || !slib->EnableSnap) return;

	slib->EnableSnap(mode, state, doc);
}

BaseContainer SnapSettings(BaseDocument *doc, LONG snapmode/* = NOTOK*/)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetSnapSettings));
	if (!slib || !slib->GetSnapSettings) return BaseContainer();

	return slib->GetSnapSettings(doc, snapmode);
}

void SnapSettings(BaseDocument *doc, const BaseContainer &bc, LONG snapmode /*= NOTOK*/)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, SetSnapSettings));
	if (!slib || !slib->SetSnapSettings) return;

	slib->SetSnapSettings(doc, bc, snapmode);
}

Bool IsQuantizeEnabled(BaseDocument *doc)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, IsQuantizeEnabled));
	if (!slib || !slib->IsQuantizeEnabled) return FALSE;

	return slib->IsQuantizeEnabled(doc);
}

Real QuantizeStep(BaseDocument *doc, BaseDraw *bd, LONG quantize_mode)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetQuantizeStep));
	if (!slib || !slib->GetQuantizeStep) return FALSE;

	return slib->GetQuantizeStep(doc, bd, quantize_mode);
}

void QuantizeStep(BaseDocument *doc, BaseDraw *bd, LONG quantize_mode, Real val)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, SetQuantizeStep));
	if (!slib || !slib->SetQuantizeStep) return;

	slib->SetQuantizeStep(doc, bd, quantize_mode, val);
}

Bool GetConstructionPlane(BaseDraw *bd, Matrix *mg, Vector *scale, BaseObject **op)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetConstructionPlane));
	if (!slib || !slib->GetConstructionPlane) return FALSE;

	return slib->GetConstructionPlane(bd, mg, scale, op);
}

BaseObject* GetWorkplaneObject(BaseDocument *doc)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetWorkplaneObject));
	if (!slib || !slib->GetWorkplaneObject) return FALSE;

	return slib->GetWorkplaneObject(doc);
}

Bool WorkplaneLock(BaseDocument *doc)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetWorkplaneLock));
	if (!slib || !slib->GetWorkplaneLock) return FALSE;

	return slib->GetWorkplaneLock(doc);
}

void WorkplaneLock(BaseDraw *bd, Bool locked)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, SetWorkplaneLock));
	if (!slib || !slib->SetWorkplaneLock) return;

	slib->SetWorkplaneLock(bd, locked);
}

Matrix GetWorkplaneMatrix(BaseDocument*doc, BaseDraw *bd)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GetWorkplaneMatrix));
	if (!slib || !slib->GetWorkplaneMatrix) return Matrix();
	
	return slib->GetWorkplaneMatrix(doc, bd);
}

//////////////////////////////////////////////////////////////////////////
///! Internal Snap Registration
Bool GeRegisterSnapModePlugin(LONG id, const String &str, BaseBitmap *icon, const String &help, LONG parent, SNAPPLUGIN &np, LONG flags)
{
	SnapCoreLib *slib = CheckSnapLib(LIBOFFSET(SnapCoreLib, GeRegisterSnapModePlugin));
	if (!slib || !slib->GeRegisterSnapModePlugin) return FALSE;

	return slib->GeRegisterSnapModePlugin(id, str, icon, help, parent, np, flags);
}

//////////////////////////////////////////////////////////////////////////
///! SnapData registration
///! 
static void FillSnapPlugin(SNAPPLUGIN *np, SnapDataAllocator *npalloc, LONG info, BaseBitmap *icon, LONG parent_mode, SNAPPRIORITY priority, const String &help)
{
	np->adr										= NULL;
	np->Allocator							= npalloc;
	np->Destructor						= &SnapData::Destructor;

	np->Init									= &SnapData::Init;
	np->Free									= &SnapData::Free;
	np->InitSnap							= &SnapData::InitSnap;
	np->Snap									= &SnapData::Snap;
	np->Intersect							= &SnapData::Intersect;
	np->FreeSnap							= &SnapData::FreeSnap;
	np->Draw									= &SnapData::Draw;
	np->GetCursorInfo					= &SnapData::GetCursorInfo;
	np->MouseInput						= &SnapData::MouseInput;
	np->KeyboardInput					= &SnapData::KeyboardInput;

	np->command_icon					= icon;
	np->parent_mode						= parent_mode;
	np->priority							= priority;
	np->help									= (String*)&help;
	np->info									= info;
}

Bool RegisterSnapPlugin(LONG id, const String &str, const String &help, LONG snapinfo, SnapDataAllocator *npalloc, BaseBitmap *icon, SNAPPRIORITY priority /*= SNAPPRIORITY_EDGE*/, LONG parent_mode /*= NOTOK*/)
{
	SNAPPLUGIN np;
	ClearMem(&np,sizeof(np));
	FillSnapPlugin(&np,npalloc,snapinfo,icon, parent_mode, priority, help);

	return GeRegisterSnapModePlugin(id, str, icon, help, parent_mode, np, snapinfo);
}
