// COEAUI.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <coeaui.h>
#include <coecntrl.h>
#include <coepanic.h>
#include "coetls.h"
#include <coemain.h>

struct SStackedControl
	{
	CCoeControl* iControl;
	TInt iPriority;
	TInt iFlags;
	};

class CCoeControlStack : public CArrayFixFlat<SStackedControl>
	{
public:
	inline CCoeControlStack() : CArrayFixFlat<SStackedControl>(2) { } // granularity of two
	TKeyResponse OfferKeyL(const TKeyEvent& aKeyEvent,TEventCode aType);
public:
	TInt iKeyIndex;
	};

TKeyResponse CCoeControlStack::OfferKeyL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	iKeyIndex=0;
	while (iKeyIndex<Count())
		{ // both iKeyIndex and Count() can be changed inside OfferKeyL() call below
		SStackedControl& stacked=(*this)[iKeyIndex++];
		if (stacked.iFlags&ECoeStackFlagRefusesAllKeys)
			continue;
		if (stacked.iControl->OfferKeyEventL(aKeyEvent,aType)==EKeyWasConsumed)
			return(EKeyWasConsumed);
		}
	return(EKeyWasNotConsumed);
	}

EXPORT_C CCoeAppUi::CCoeAppUi()
	{
	iCoeEnv=TheCoe();
	}

EXPORT_C CCoeAppUi::~CCoeAppUi()
	{
	if (iStack)
		{
		TInt pos=0;
		const TInt count=iStack->Count();
		CCoeControlStack* stack=iStack;
		iStack=NULL;
		while (pos<count)
			{
			SStackedControl& stacked=(*stack)[pos++];
			if (stacked.iFlags&ECoeStackFlagOwnershipTransfered)
				delete(stacked.iControl);
			}
		delete(stack);
		}
	}

EXPORT_C void CCoeAppUi::ConstructL(CCoeAppUi* aPrevious)
	{
	iStack=new(ELeave) CCoeControlStack;
	if (!aPrevious)
		return;
	CCoeControlStack* previousStack=aPrevious->iStack;
	TInt pos=0;
	const TInt count=previousStack->Count();
	while (pos<count)
		{
		SStackedControl stacked=(*previousStack)[pos++];
		if (!(stacked.iFlags&ECoeStackFlagSharable))
			continue;
		stacked.iFlags&=(~ECoeStackFlagOwnershipTransfered);
		iStack->AppendL(stacked);
		}
	}

EXPORT_C void CCoeAppUi::HandleWsEventL(const TWsEvent& aEvent,CCoeControl* aDestination)
	{
	TInt type=aEvent.Type();
	switch (type)
		{
	case EEventKey:
	case EEventKeyUp:
	case EEventKeyDown:
		if (iStack->OfferKeyL(*aEvent.Key(),(TEventCode)type)==EKeyWasNotConsumed)
			HandleKeyEventL(*aEvent.Key(),(TEventCode)type);
		break;
	case EEventPointer:
		aDestination->ProcessPointerEventL(*aEvent.Pointer());
		break;
	case EEventPointerBufferReady:
		aDestination->ProcessPointerBufferReadyL();
		break;
	case EEventFocusLost:
	case EEventFocusGained:
		{
		TBool foreground=(type==EEventFocusGained);
		if (foreground)
			{
			iCoeEnv->NotifyForegroundObserversOfGainingForeground();
			}
		else
			{
			iCoeEnv->NotifyForegroundObserversOfLosingForeground();
			}
		CCoeControl* topFocusable=TopFocusableControl();
		HandleForegroundEventL(foreground);
		if (!topFocusable)
			SetAndDrawFocus(foreground);
		else
			{
			TBool isFocused=topFocusable->IsFocused();
			if ((foreground && !isFocused) || (!foreground && isFocused))
				topFocusable->SetFocus(foreground,EDrawNow);
			}
		break;
		}
	case EEventSwitchOn:
		HandleSwitchOnEventL(aDestination);
		break;
	case EEventUser:
		HandleSystemEventL(aEvent);
		break;
	case EEventMessageReady:
		HandleMessageReadyL();
		break;
	default:
		if (type>EEventUser)
			HandleApplicationSpecificEventL(type,aEvent);
		break;
		}
	}

EXPORT_C void CCoeAppUi::HandleKeyEventL(const TKeyEvent& /*aKeyEvent*/,TEventCode /*aType*/)
	{
	}

EXPORT_C void CCoeAppUi::HandleForegroundEventL(TBool /*aForeground*/)
	{
	}

EXPORT_C void CCoeAppUi::HandleSwitchOnEventL(CCoeControl* /*aDestination*/)
	{
	}

EXPORT_C void CCoeAppUi::HandleSystemEventL(const TWsEvent& /*aEvent*/)
	{
	}

EXPORT_C void CCoeAppUi::HandleMessageReadyL()
	{
	}

EXPORT_C void CCoeAppUi::HandleApplicationSpecificEventL(TInt /*aType*/,const TWsEvent& /*aEvent*/)
	{
	}

EXPORT_C void CCoeAppUi::SetAndDrawFocus(TBool /*aFocus*/)
	{
	}

EXPORT_C void CCoeAppUi::AddToStackL(CCoeControl* aControl,TInt aPriority,TInt aStackingFlags)
	{
	SStackedControl newStacked;
	newStacked.iControl=aControl;
	newStacked.iPriority=aPriority;
	newStacked.iFlags=aStackingFlags;
	TInt pos=0;
	const TInt count=iStack->Count();
	while (pos<count)
		{
		if (aPriority>=(*iStack)[pos].iPriority)
			break;
		pos++;
		}
	iStack->InsertL(pos,newStacked);
	if (pos<iStack->iKeyIndex)
		iStack->iKeyIndex++;
	HandleStackChanged();
	}

EXPORT_C void CCoeAppUi::RemoveFromStack(CCoeControl* aControl)
	{
	if (!iStack)
		return; // whole stack in process of destruction
	TInt pos=FindPos(aControl);
	if (pos>=0)
		{
		iStack->Delete(pos);
		if (pos<iStack->iKeyIndex)
			iStack->iKeyIndex--;
		HandleStackChanged();
		}
	}

EXPORT_C void CCoeAppUi::HandleStackChanged()
	{
	CCoeControl* toFocus=TopFocusableControl();
	CCoeControl* focused=TopFocusedControl();
	if (toFocus!=focused)
		{
		SetFocusToControl(focused,EFalse);
		SetFocusToControl(toFocus,ETrue);
		}
	else if (!toFocus)
		SetAndDrawFocus(ETrue);
	}

EXPORT_C TBool CCoeAppUi::IsDisplayingControlBetweenPriorities(TInt aLowerPriority, TInt aHigherPriority) const
	{
	TBool ret=EFalse;
	const TInt count=iStack->Count();
	for (TInt ii=0; ii<count; ii++)
		{
		SStackedControl sC=(*iStack)[ii];
		if (sC.iPriority>aLowerPriority && sC.iPriority<aHigherPriority)
			{
			if (sC.iControl->IsVisible())
				{
				ret=ETrue;
				break;
				}
			}
		}
	return ret;
	}

EXPORT_C TBool CCoeAppUi::IsDisplayingMenuOrDialog() const
	{
	TBool ret=EFalse;
	const TInt count=iStack->Count();
	for (TInt ii=0; ii<count; ii++)
		{
		SStackedControl sC=(*iStack)[ii];
		if (sC.iPriority>=ECoeStackPriorityMenu && sC.iPriority<=ECoeStackPriorityAlert)
			{
			if (sC.iControl->IsVisible())
				{
				ret=ETrue;
				break;
				}
			}
		}
	return ret;
	}

void CCoeAppUi::SetFocusToControl(CCoeControl* aControl,TBool aFocus)
	{
	if (aControl)
		aControl->SetFocus(aFocus,EDrawNow);
	else
		SetAndDrawFocus(aFocus);
	}

CCoeControl* CCoeAppUi::TopFocusedControl() const
	{
	TInt pos=0;
	const TInt count=iStack->Count();
	while (pos<count)
		{
		CCoeControl* const control=(*iStack)[pos++].iControl;
		if (control->IsFocused())
			return(control);
		}
	return(NULL);
	}

CCoeControl* CCoeAppUi::TopFocusableControl() const
	{
	TInt pos=0;
	const TInt count=iStack->Count();
	while (pos<count)
		{
		SStackedControl& stacked=(*iStack)[pos++];
		if (!(stacked.iFlags&ECoeStackFlagRefusesFocus))
			return(stacked.iControl);
		}
	return(NULL);
	}

TInt CCoeAppUi::FindPos(CCoeControl* aControl) const
	{
	TInt pos=0;
	const TInt count=iStack->Count();
	FOREVER
		{
		if (pos==count)
			return(KErrNotFound);
		if ((*iStack)[pos].iControl==aControl)
			break;
		pos++;
		}
	return(pos);
	}

EXPORT_C void CCoeAppUi::UpdateStackedControlFlags(CCoeControl* aControl,TInt aFlags,TInt aMask)
	{
	TInt pos=FindPos(aControl);
	if (pos<0)
		Panic(ECoePanicNoSuchControlInStack);
	SStackedControl& stacked=(*iStack)[pos];
	stacked.iFlags&=(~aMask);
	stacked.iFlags|=(aFlags&aMask);
	if ((stacked.iFlags&(ECoeStackFlagRefusesAllKeys|ECoeStackFlagRefusesFocus))==(ECoeStackFlagRefusesAllKeys|ECoeStackFlagRefusesFocus))
		return; // else promote control to start of section of equi-priority controls
	TInt startPos=pos;
	while (startPos--)
		{
		if ((*iStack)[startPos].iPriority!=stacked.iPriority)
			break;
		}
	if (++startPos==pos)
		return;
	SStackedControl copy=stacked;
	iStack->Delete(pos);
	iStack->InsertL(startPos,copy); // bound to succeed
	}

EXPORT_C void CCoeAppUi::Reserved_1()
	{
	}

EXPORT_C void CCoeAppUi::Reserved_2()
	{
	}

EXPORT_C void CCoeAppUiBase::Reserved_1()
	{
	}

EXPORT_C void CCoeAppUiBase::Reserved_2()
	{
	}

EXPORT_C void CCoeAppUiBase::PrepareToExit()
	{
	}
