/*
* Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0""
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  drop-down list control
*
*/


#include <peninputgeneralitutnew.rsg>
#include <peninputitutconfig_chinese.rsg>
#include <peninputdropdownlist.h>
#include <coemain.h>
#include <AknFepGlobalEnums.h>
#include <PtiEngine.h>

#include "peninputitutchnuistatepredict.h"
#include "peninputgenericitutuimgrbase.h"
#include "peninputgenericitutdatamgr.h"
#include "peninputgenericitutlayoutcontext.h"
#include "peninputgenericitutconverter.h"
#include "peninputgenericitutwindowmanager.h"

const TInt KInvalidIndex = -1;

CChnItutUiStatePredict* CChnItutUiStatePredict::NewL(CGenericItutUiMgrBase* aOwner)
    {
    CChnItutUiStatePredict* self = new (ELeave) CChnItutUiStatePredict(aOwner);
    CleanupStack::PushL(self);
    self->ConstructL(); 
    CleanupStack::Pop(self);
    return self;
    }

CChnItutUiStatePredict::~CChnItutUiStatePredict()
    {
    }

CChnItutUiStatePredict::CChnItutUiStatePredict(CGenericItutUiMgrBase* aOwner)
                                                          :CGenericItutUiStateBase(aOwner),
                                                           iLastOverlapIdx(KInvalidIndex)
    {
    }

void CChnItutUiStatePredict::OnEntryL()
    {
    HBufC* puncText = NULL;
    switch (iOwner->DataMgr()->InputMode())
        {
        case EPinyin:
            {
            iOwner->DataMgr()->NotifyChangeControlLayout(
                MItutPropertySubscriber::EItutPropertyKeypadResourceId,
                R_FINGER_INPUT_KEYPAD_PINYIN_STANDBY_PREDICT);
            puncText = CCoeEnv::Static()->AllocReadResourceL(R_ITUT_PUNC_PINYIN_ZHUYIN);             
            }
            break;
        case EStroke:
            {
            TInt resID;
            if (iOwner->DataMgr()->InputLanguage() == ELangPrcChinese)
                {
                resID = R_FINGER_INPUT_KEYPAD_STROKE_STANDBY_PREDICT_PRC;
                }
            else
                {
                resID = R_FINGER_INPUT_KEYPAD_STROKE_STANDBY_PREDICT_TRA;
                }
            iOwner->DataMgr()->NotifyChangeControlLayout(
                MItutPropertySubscriber::EItutPropertyKeypadResourceId,
                resID);
            puncText = CCoeEnv::Static()->AllocReadResourceL(R_ITUT_PUNC_STROKE);	
            }
            break;        
        case EZhuyin:
            {
            iOwner->DataMgr()->NotifyChangeControlLayout(
                MItutPropertySubscriber::EItutPropertyKeypadResourceId,
                R_FINGER_INPUT_KEYPAD_ZHUYIN_STANDBY_PREDICT);
            puncText = CCoeEnv::Static()->AllocReadResourceL(R_ITUT_PUNC_PINYIN_ZHUYIN);
            }
            break;        
        default:
            {
            // wrong input mode	
            return;
            }
        }

    // show punc drop list, and set candidates to it
    CleanupStack::PushL( puncText );
    CFepCtrlDropdownList* punclist = 
        static_cast<CFepCtrlDropdownList*>(iOwner->LayoutContext()->Control(ECtrlIdPuncCandsList));
    punclist->Hide(EFalse);

    iOwner->DataMgr()->ClearChnCandidates(EItutPuncCandidates);
    RPointerArray<HBufC>& punccandslist = 
        TItutDataConverter::AnyToRptrArray(iOwner->DataMgr()->RequestData(EChnPuncCandidates));
    TItutDataConverter::ConvertNonPhraseCandidateL(*puncText, punccandslist);

    punclist->SetCandidatesL(punccandslist, CFepCtrlDropdownList::EListNoExpandableWithBubble);
    CleanupStack::PopAndDestroy( puncText );

    // show candidate drop list
    CFepCtrlDropdownList* candlist = 
        static_cast<CFepCtrlDropdownList*>(iOwner->LayoutContext()->Control(ECtrlIdStdCandsList));
    candlist->Hide(EFalse);

    // may need to change resource id of candidte list to predictive, change keypad resource id if need
    iOwner->DataMgr()->NotifyChangeControlLayout(
        MItutPropertySubscriber::EItutPropertyCandidateListResourceId,
        R_AKN_FEP_NORMAL_CAND_DROP_DOWN_LIST);
        
    }

void CChnItutUiStatePredict::OnExit()
    {
    // hide dropdownlist & reset its status
    CFepCtrlDropdownList* punclist = 
        static_cast<CFepCtrlDropdownList*>(iOwner->LayoutContext()->Control(ECtrlIdPuncCandsList));
    punclist->ResetAndClear(CFepCtrlDropdownList::EListNoExpandable);
    iOwner->DataMgr()->ClearChnCandidates(EItutPuncCandidates);
    punclist->Hide(ETrue);

    CFepCtrlDropdownList* candlist = 
        static_cast<CFepCtrlDropdownList*>(iOwner->LayoutContext()->Control(ECtrlIdStdCandsList));
    candlist->ResetAndClear(CFepCtrlDropdownList::EListExpandable);
    iOwner->DataMgr()->ClearChnCandidates(EItutCandidates);
    candlist->Hide(ETrue);
    
    //show indicator 
    iOwner->LayoutContext()->Control(ECtrlIdIndicator)->Hide(EFalse);
    
    // Hide ICF, Backspace, Arrow contrls when exit to avoid flick
    //iOwner->LayoutContext()->Control(ECtrlIdICF)->Hide( ETrue );
    //iOwner->LayoutContext()->Control(ECtrlIdBackspace)->Hide(ETrue);
    //iOwner->LayoutContext()->ShowArrowBtn(0);
    
    }

TBool CChnItutUiStatePredict::HandleKeyL(TInt aCmd, TInt aKey)
    {
    TInt immode = iOwner->DataMgr()->InputMode();

    if (IsKeyValid(aKey))
        {
        iOwner->SetNumLongPressValid(ETrue);
        iOwner->SetCurrentStateL(CGenericItutUiMgrBase::EStateComposition);
        iOwner->CurrentState()->HandleKeyL(aCmd, aKey);
        return ETrue;
        }
    return EFalse;
    }

CGenericItutUiMgrBase::TUiState CChnItutUiStatePredict::StateType()
    {
    return CGenericItutUiMgrBase::EStatePredict;
    }
    
TBool CChnItutUiStatePredict::IsKeyValid(TInt aKey)
    {
    TInt immode = iOwner->DataMgr()->InputMode();
    
    return (immode == EPinyin && aKey >= EPtiKey2 && aKey <= EPtiKey9) ||
           (immode == EStroke && aKey >= EPtiKey1 && aKey <= EPtiKey6) ||
           (immode == EZhuyin && aKey >= EPtiKey0 && aKey <= EPtiKey9);
    }
    
TBool CChnItutUiStatePredict::HandleCtrlEventL(TInt aEventType, 
                                               CFepUiBaseCtrl* aCtrl, 
                                               const TDesC& aEventData)
    {
    switch (aEventType)
        {
        case EItutCmdCandidateSelected:
            {
            TPtrC buf = aEventData.Left(aEventData.Length() - 1);

            if (aCtrl->ControlId() == ECtrlIdStdCandsList)
                {
                // if press cell on candidate list, set predictive candidates of it
                iOwner->DataMgr()->PtiEngine()->SetPredictiveChineseChar(buf);
                TPtrC cands = iOwner->DataMgr()->PtiEngine()->CandidatePage();

                iOwner->DataMgr()->ClearChnCandidates(EItutCandidates);

                RPointerArray<HBufC>& candslist = TItutDataConverter::AnyToRptrArray(
                    iOwner->DataMgr()->RequestData(EChnCandidates));
                TItutDataConverter::ConvertChnPhraseCandidateL(cands, candslist);

                // remove duplicate punctuation from predict candidate
                RPointerArray<HBufC>& punccandslist = TItutDataConverter::AnyToRptrArray(
                    iOwner->DataMgr()->RequestData(EChnPuncCandidates));
                iLastOverlapIdx = RemoveDuplicateCand(punccandslist,
                                                      candslist,
                                                      0,
                                                      0);

                CFepCtrlDropdownList* canddroplist = 
                    reinterpret_cast<CFepCtrlDropdownList*>(aCtrl);
                canddroplist->SetCandidatesL(candslist, CFepCtrlDropdownList::EListExpandableWithBubble);

                // input pressed candidate
                iOwner->LayoutContext()->SubmitText(buf);

                return ETrue;
                }
            else if (aCtrl->ControlId() == ECtrlIdPuncCandsList)
                {
                // if press cell on punc drop list, input it directly
                iOwner->LayoutContext()->SubmitText(buf);
                
                return ETrue;
                }
            }
            break;
        case EItutCmdGetNextCandidatePage:
            {
            if (aCtrl->ControlId() == ECtrlIdStdCandsList)
                {
                RPointerArray<HBufC>& candslist = TItutDataConverter::AnyToRptrArray(
                    iOwner->DataMgr()->RequestData(EChnCandidates));

                if (candslist.Count() >= KMaxPredictCandCnt)
                    {
                    return ETrue;
                    }

                // original candidate count before fetch new candidate
                TInt candscnt = candslist.Count();
                if (iOwner->DataMgr()->GetNextPageCandidateL(candslist) == KErrNone)
                    {
                    // remove duplicate punctuation from predict candidate
                    RPointerArray<HBufC>& punccandslist = TItutDataConverter::AnyToRptrArray(
                        iOwner->DataMgr()->RequestData(EChnPuncCandidates));
                    iLastOverlapIdx = RemoveDuplicateCand(punccandslist,
                                                          candslist,
                                                          iLastOverlapIdx + 1,
                                                          candscnt);

                    if (candslist.Count() >= KMaxPredictCandCnt)
                        {
                        candscnt = candslist.Count();
                        for (TInt i = KMaxPredictCandCnt; i < candscnt; i++)
                            {
                            delete candslist[KMaxPredictCandCnt];
                            candslist.Remove(KMaxPredictCandCnt);
                            }
                        }

                    static_cast<CFepCtrlDropdownList*>(aCtrl)->AddCandidatesL(candslist);    
                    }

                return ETrue;    
                }
            }
            break;
        case EItutCmdCandidateExisted:
            {
            if (aCtrl->ControlId() == ECtrlIdStdCandsList)
                {
                RPointerArray<HBufC>& candslist = TItutDataConverter::AnyToRptrArray(
                    iOwner->DataMgr()->RequestData(EChnCandidates));

                if (candslist.Count() >= KMaxPredictCandCnt)
                    {
                    static_cast<CFepCtrlDropdownList*>(aCtrl)->SetFlagCandidateExist(EFalse);
                    }
                else
                    {
                    static_cast<CFepCtrlDropdownList*>(aCtrl)->SetFlagCandidateExist(
                        iOwner->DataMgr()->NextPageCandidateExist());
                    }
                
                return ETrue;
                }
            }
            break;
        case EEventControlFocusGained:
            {
            if (aCtrl->ControlId() == ECtrlIdICF)
                {
                iOwner->SetCurrentStateL(CGenericItutUiMgrBase::EStateStandby);

                // ui layout may also need to handle this event
                return EFalse;
                }
            }
            break;
        case EEventIcfPointerUpEvent:
        	{
            if (aCtrl->ControlId() == ECtrlIdICF)
                {
                iOwner->SetCurrentStateL(CGenericItutUiMgrBase::EStateStandby);

                // ui layout may also need to handle this event
                return ETrue;
                }
        	}
        	break;
        case EEventRawKeyDownEvent:
        	{

        	if ( iOwner->UiManager()->IsAllowHandleRawKeyEvent())
        		{
				TInt immode = iOwner->DataMgr()->InputMode();
				const TKeyEvent *key = reinterpret_cast<const TKeyEvent*>(aEventData.Ptr());
				if ( ( immode == EPinyin && 
					 ( key->iScanCode == EPtiKey0 || key->iScanCode == EPtiKey1 || key->iScanCode == EPtiKeyStar ) ) ||
					 ( immode == EStroke && 
					 ( key->iScanCode == EPtiKeyStar || key->iScanCode == EPtiKey0 || (key->iScanCode >= EPtiKey7 && key->iScanCode <= EPtiKey9 ))) ||
					 ( immode == EZhuyin && key->iScanCode == EPtiKeyStar) ||
					 ( key->iScanCode == EStdKeyBackspace))
					{                
					// For those special keys, simulate down key immedidately.
					// to ensure to simulate down key event before up key event
					iOwner->UiManager()->SimulateImmeRawEvent( key->iScanCode, TRawEvent::EKeyDown );
					iOwner->UiManager()->SetLastRawKeyDown( key->iScanCode, ETrue, aCtrl );               			
					return ETrue;                               
					}   
        		}
        	}
        	break;
        case EEventRawKeyUpEvent:
        	{
        	if ( iOwner->UiManager()->IsAllowHandleRawKeyEvent())
        		{
				TInt immode = iOwner->DataMgr()->InputMode();
				const TKeyEvent *key = reinterpret_cast<const TKeyEvent*>(aEventData.Ptr());
				if ( ( immode == EPinyin && 
					 ( key->iScanCode == EPtiKey0 || key->iScanCode == EPtiKey1 || key->iScanCode == EPtiKeyStar ) ) ||
					 ( immode == EStroke && 
					 ( key->iScanCode == EPtiKeyStar || key->iScanCode == EPtiKey0 || (key->iScanCode >= EPtiKey7 && key->iScanCode <= EPtiKey9 ))) ||
					 ( immode == EZhuyin && key->iScanCode == EPtiKeyStar) ||
					 ( key->iScanCode == EStdKeyBackspace))
					{
					// For those special keys, simulate up key events immediately before changing state.
					// The action can avoid up key event being delayed by running changing state,
					// otherwise, short press will be thought as long press by window server.
					iOwner->UiManager()->SimulateImmeRawEvent( key->iScanCode, TRawEvent::EKeyUp );
					iOwner->UiManager()->SetLastRawKeyDown( key->iScanCode, EFalse, aCtrl );                
					iOwner->SetCurrentStateL( CGenericItutUiMgrBase::EStateStandby );
					return ETrue;                          
					}
        		}
        	}
        	break;
        default:
            break;
        }
    
    return EFalse;    
    }
    
TInt CChnItutUiStatePredict::RemoveDuplicateCand(const RPointerArray<HBufC>& aSrc,
                                                 RPointerArray<HBufC>& aTgt,
                                                 TInt aSrcStartIdx,
                                                 TInt aTgtStartIdx)
    {
    TInt lastOverlapIdx = KInvalidIndex;

    // on the assumption that if candidate overlap,
    // it is overlap only once
    TInt srccandcnt = aSrc.Count();

    for (TInt i = aSrcStartIdx; i < srccandcnt; i++)
        {
        for (TInt j = aTgtStartIdx; j < aTgt.Count(); j++)
            {
            if (aTgt[j]->Compare(*(aSrc[i])) == 0)
                {
                lastOverlapIdx = i;
                delete aTgt[j];
                aTgt.Remove(j);
                j--;
                break;
                }
            }
        }

    return lastOverlapIdx;
    }

// End Of File
