//---------------------------------------------------------------------------
/*
	TVP2 ( T Visual Presenter 2 )  A script authoring tool
	Copyright (C) 2000 W.Dee <dee@kikyou.info> and contributors

	See details of license at "license.txt"
*/
//---------------------------------------------------------------------------
// "MenuItem" class interface
//---------------------------------------------------------------------------
#include "tjsCommHead.h"

#include "MsgIntf.h"
#include "MenuItemIntf.h"
#include "WindowIntf.h"
#include "EventIntf.h"
#include "tjsArray.h"


//---------------------------------------------------------------------------
// Input Events
//---------------------------------------------------------------------------
// For input event tag
tTVPUniqueTagForInputEvent tTVPOnMenuItemClickInputEvent      ::Tag;
//---------------------------------------------------------------------------





//---------------------------------------------------------------------------
// tTJSNI_BaseMenuItem
//---------------------------------------------------------------------------
tTJSNI_BaseMenuItem::tTJSNI_BaseMenuItem()
{
	Owner = NULL;
	Window = NULL;
	Parent = NULL;
	ChildrenArrayValid = false;
	ChildrenArray = NULL;
	ArrayClearMethod = NULL;

	ActionOwner.Object = ActionOwner.ObjThis = NULL;
}
//---------------------------------------------------------------------------
tjs_error TJS_INTF_METHOD
		tTJSNI_BaseMenuItem::Construct(tjs_int numparams, tTJSVariant **param,
			iTJSDispatch2 *tjs_obj)
{
	if(numparams < 1) return TJS_E_BADPARAMCOUNT;

	tjs_error hr = inherited::Construct(numparams, param, tjs_obj);
	if(TJS_FAILED(hr)) return hr;

	ActionOwner = param[0]->AsObjectClosure();
	Owner = tjs_obj;

	if(numparams >= 2)
	{
		if(param[1]->Type() == tvtObject)
		{
			// is this Window instance ?
			tTJSVariantClosure clo = param[1]->AsObjectClosureNoAddRef();
			if(clo.Object == NULL) TVPThrowExceptionMessage(TVPSpecifyWindow);
			tTJSNI_Window *win = NULL;
			if(TJS_FAILED(clo.Object->NativeInstanceSupport(TJS_NIS_GETINSTANCE,
				tTJSNC_Window::ClassID, (iTJSNativeInstance**)&win)))
				TVPThrowExceptionMessage(TVPSpecifyWindow);
			Window = win;
		}
	}

	return TJS_S_OK;
}
//---------------------------------------------------------------------------
void TJS_INTF_METHOD tTJSNI_BaseMenuItem::Invalidate()
{
	TVPCancelSourceEvents(Owner);
	TVPCancelInputEvents(this);

	{ // locked
		tObjectListSafeLockHolder<tTJSNI_BaseMenuItem> holder(Children);
		tjs_int count = Children.GetSafeLockedObjectCount();
		for(tjs_int i = 0; i < count; i++)
		{
			tTJSNI_BaseMenuItem *item = Children.GetSafeLockedObjectAt(i);
			if(!item) continue;

			if(item->Owner)
			{
				item->Owner->Invalidate(0, NULL, NULL, item->Owner);
				item->Owner->Release();
			}
		}
	} // locked

//	Owner = NULL;
	Window = NULL;
	Parent = NULL;

	if(ChildrenArray) ChildrenArray->Release(), ChildrenArray = NULL;
	if(ArrayClearMethod) ArrayClearMethod->Release(), ArrayClearMethod = NULL;

	ActionOwner.Release();
	ActionOwner.ObjThis = ActionOwner.Object = NULL;

	inherited::Invalidate();
}
//---------------------------------------------------------------------------
tTJSNI_MenuItem * tTJSNI_BaseMenuItem::CastFromVariant(const tTJSVariant & from)
{
	if(from.Type() == tvtObject)
	{
		// is this Window instance ?
		tTJSVariantClosure clo = from.AsObjectClosureNoAddRef();
		if(clo.Object == NULL) TVPThrowExceptionMessage(TVPSpecifyMenuItem);
		tTJSNI_MenuItem *menuitem = NULL;
		if(TJS_FAILED(clo.Object->NativeInstanceSupport(TJS_NIS_GETINSTANCE,
			tTJSNC_MenuItem::ClassID, (iTJSNativeInstance**)&menuitem)))
			TVPThrowExceptionMessage(TVPSpecifyMenuItem);
		return menuitem;
	}
	TVPThrowExceptionMessage(TVPSpecifyMenuItem);
	return NULL;
}
//---------------------------------------------------------------------------
void tTJSNI_BaseMenuItem::AddChild(tTJSNI_BaseMenuItem *item)
{
	if(Children.Add(item))
	{
		ChildrenArrayValid = false;
		if(item->Owner) item->Owner->AddRef();
		item->Parent = this;
	}
}
//---------------------------------------------------------------------------
void tTJSNI_BaseMenuItem::RemoveChild(tTJSNI_BaseMenuItem *item)
{
	if(Children.Remove(item))
	{
		ChildrenArrayValid = false;
		if(item->Owner) item->Owner->Release();
		item->Parent = NULL;
	}
}
//---------------------------------------------------------------------------
iTJSDispatch2 * tTJSNI_BaseMenuItem::GetChildrenArrayNoAddRef()
{
	if(!ChildrenArray)
	{
		// create an Array object
		iTJSDispatch2 * classobj;
		ChildrenArray = TJSCreateArrayObject(&classobj);
		try
		{
			tTJSVariant val;
			tjs_error er;
			er = classobj->PropGet(0, TJS_W("clear"), NULL, &val, classobj);
				// retrieve clear method
			if(TJS_FAILED(er)) TVPThrowInternalError;
			ArrayClearMethod = val.AsObject();
		}
		catch(...)
		{
			ChildrenArray->Release();
			ChildrenArray = NULL;
			classobj->Release();
			throw;
		}
		classobj->Release();
	}

	if(!ChildrenArrayValid)
	{
		// re-create children list
		ArrayClearMethod->FuncCall(0, NULL, NULL, NULL, 0, NULL, ChildrenArray);
			// clear array

		{ // locked
			tObjectListSafeLockHolder<tTJSNI_BaseMenuItem> holder(Children);
			tjs_int count = Children.GetSafeLockedObjectCount();
			tjs_int itemcount = 0;
			for(tjs_int i = 0; i < count; i++)
			{
				tTJSNI_BaseMenuItem *item = Children.GetSafeLockedObjectAt(i);
				if(!item) continue;

				iTJSDispatch2 * dsp = item->Owner;
				tTJSVariant val(dsp, dsp);
				ChildrenArray->PropSetByNum(TJS_MEMBERENSURE, itemcount, &val,
					ChildrenArray);
				itemcount++;
			}
		} // locked

		ChildrenArrayValid = true;
	}

	return ChildrenArray;
}
//---------------------------------------------------------------------------
void tTJSNI_BaseMenuItem::OnClick(void)
{
	// fire onClick event
	if(!CanDeliverEvents()) return;

	// also check window
	tTJSNI_BaseMenuItem *item = this;
	while(!item->Window)
	{
		if(!item->Parent) break;
		item = item->Parent;
	}
	if(!item->Window) return;
	if(!item->Window->CanDeliverEvents()) return;

	// fire event
	static ttstr eventname(TJS_W("onClick"));
	TVPPostEvent(Owner, Owner, eventname, 0, TVP_EPT_IMMEDIATE, 0, NULL);
}
//---------------------------------------------------------------------------
tTJSNI_BaseMenuItem * tTJSNI_BaseMenuItem::GetRootMenuItem() const
{
	tTJSNI_BaseMenuItem * current = const_cast<tTJSNI_BaseMenuItem*>(this);
	tTJSNI_BaseMenuItem * parent = current->GetParent();
	while (parent)
	{
		current = parent;
		parent = current->GetParent();
	}
	return current;
}
//---------------------------------------------------------------------------




//---------------------------------------------------------------------------
// tTJSNC_MenuItem
//---------------------------------------------------------------------------
tjs_uint32 tTJSNC_MenuItem::ClassID = -1;
tTJSNC_MenuItem::tTJSNC_MenuItem() : inherited(TJS_W("MenuItem"))
{
	// registration of native members

	TJS_BEGIN_NATIVE_MEMBERS(MenuItem) // constructor
	TJS_DECL_EMPTY_FINALIZE_METHOD
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_CONSTRUCTOR_DECL(/*var.name*/_this, /*var.type*/tTJSNI_MenuItem,
	/*TJS class name*/MenuItem)
{
	return TJS_S_OK;
}
TJS_END_NATIVE_CONSTRUCTOR_DECL(/*TJS class name*/MenuItem)
//----------------------------------------------------------------------

//-- methods

//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_METHOD_DECL(/*func. name*/add)
{
	TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
	if(numparams < 1) return TJS_E_BADPARAMCOUNT;
	tTJSNI_MenuItem * item = tTJSNI_BaseMenuItem::CastFromVariant(*param[0]);
	_this->Add(item);
	return TJS_S_OK;
}
TJS_END_NATIVE_METHOD_DECL(/*func. name*/add)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_METHOD_DECL(/*func. name*/insert)
{
	TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
	if(numparams < 2) return TJS_E_BADPARAMCOUNT;
	tTJSNI_MenuItem * item = tTJSNI_BaseMenuItem::CastFromVariant(*param[0]);
	tjs_int index = *param[1];
	_this->Insert(item, index);
	return TJS_S_OK;
}
TJS_END_NATIVE_METHOD_DECL(/*func. name*/insert)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_METHOD_DECL(/*func. name*/remove)
{
	TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
	if(numparams < 1) return TJS_E_BADPARAMCOUNT;
	tTJSNI_MenuItem * item = tTJSNI_BaseMenuItem::CastFromVariant(*param[0]);
	_this->Remove(item);
	return TJS_S_OK;
}
TJS_END_NATIVE_METHOD_DECL(/*func. name*/remove)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_METHOD_DECL(/*func. name*/popup) // not trackPopup
{
	TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
	if(numparams < 3) return TJS_E_BADPARAMCOUNT;
	tjs_uint32 flags = (tTVInteger)*param[0];
	tjs_int x = *param[1];
	tjs_int y = *param[2];
	tjs_int rv = _this->TrackPopup(flags, x, y);
	if (result) *result = rv;
	return TJS_S_OK;
}
TJS_END_NATIVE_METHOD_DECL(/*func. name*/popup) // not trackPopup
//---------------------------------------------------------------------------

//-- events

//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_METHOD_DECL(/*func. name*/onClick)
{
	TJS_GET_NATIVE_INSTANCE(/*var. name*/_this,
		/*var. type*/tTJSNI_MenuItem);

	tTJSVariantClosure obj = _this->GetActionOwnerNoAddRef();
	if(obj.Object)
	{
		TVP_ACTION_INVOKE_BEGIN(0, "onClick", objthis);
		TVP_ACTION_INVOKE_END(obj);
	}

	return TJS_S_OK;
}
TJS_END_NATIVE_METHOD_DECL(/*func. name*/onClick)
//----------------------------------------------------------------------

//--properties

//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(caption)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		ttstr res;
		_this->GetCaption(res);
		*result = res;
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetCaption(*param);
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(caption)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(checked)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		*result = _this->GetChecked();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetChecked(param->operator bool());
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(checked)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(enabled)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		*result = _this->GetEnabled();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetEnabled(param->operator bool());
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(enabled)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(group)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		*result = _this->GetGroup();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetGroup((tjs_int)*param);
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(group)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(radio)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		*result = _this->GetRadio();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetRadio(param->operator bool());
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(radio)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(shortcut)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		ttstr res;
		_this->GetShortcut(res);
		*result = res;
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetShortcut(*param);
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(shortcut)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(visible)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		*result = _this->GetVisible();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetVisible(param->operator bool());
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(visible)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(parent)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		tTJSNI_BaseMenuItem *parent = _this->GetParent();
		if(parent)
		{
			iTJSDispatch2 *dsp = parent->GetOwnerNoAddRef();
			*result = tTJSVariant(dsp, dsp);
		}
		else
		{
			*result = tTJSVariant((iTJSDispatch2 *)NULL);
		}
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_DENY_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(parent)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(children)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		iTJSDispatch2 *dsp = _this->GetChildrenArrayNoAddRef();
		*result = tTJSVariant(dsp, dsp);
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_DENY_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(children)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(root) // not rootMenuItem
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		tTJSNI_BaseMenuItem * root = _this->GetRootMenuItem();
		if (root)
		{
			iTJSDispatch2 *dsp = root->GetOwnerNoAddRef();
			if (result) *result = tTJSVariant(dsp, dsp);
		}
		else
		{
			if (result) *result = tTJSVariant((iTJSDispatch2 *)NULL);
		}
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_DENY_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(root) // not rootMenuItem
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(window)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		tTJSNI_Window * window = _this->GetWindow();
		if (window)
		{
			iTJSDispatch2 *dsp = window->GetOwnerNoAddRef();
			if (result) *result = tTJSVariant(dsp, dsp);
		}
		else
		{
			if (result) *result = tTJSVariant((iTJSDispatch2 *)NULL);
		}
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_DENY_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(window)
//----------------------------------------------------------------------
TJS_BEGIN_NATIVE_PROP_DECL(index)
{
	TJS_BEGIN_NATIVE_PROP_GETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		if (result) *result = (tTVInteger)_this->GetIndex();
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_GETTER

	TJS_BEGIN_NATIVE_PROP_SETTER
	{
		TJS_GET_NATIVE_INSTANCE(/*var. name*/_this, /*var. type*/tTJSNI_MenuItem);
		_this->SetIndex((tjs_int)(*param));
		return TJS_S_OK;
	}
	TJS_END_NATIVE_PROP_SETTER
}
TJS_END_NATIVE_PROP_DECL(index)
//----------------------------------------------------------------------

	TJS_END_NATIVE_MEMBERS
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
iTJSDispatch2 * TVPCreateMenuItemObject(iTJSDispatch2 * window)
{
	struct tHolder
	{
		iTJSDispatch2 * Obj;
		tHolder() { Obj = new tTJSNC_MenuItem(); }
		~tHolder() { Obj->Release(); }
	} static menuitemclass;

	iTJSDispatch2 *out;
	tTJSVariant param(window);
	tTJSVariant *pparam[2] = {&param, &param};
	if(TJS_FAILED(menuitemclass.Obj->CreateNew(0, NULL, NULL, &out, 2, pparam,
		menuitemclass.Obj)))
		TVPThrowExceptionMessage(TVPInternalError,
			TJS_W("TVPCreateMenuItemObject"));

	return out;
}
//---------------------------------------------------------------------------

