/*
* Copyright (c) 2002 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: 
*
*/

#include "aknapp.h"
#include <eikenv.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <uikon/eikenvinterface.h>
#endif

#include <apgtask.h>
#include <apgwgnam.h>
#include <AknServerApp.h>
#include "AknTaskList.h"

#include <aknenv.h>
#include <akntranseffect.h> // for Transition effect enumerations
#include <UikonInternalPSKeys.h>
#include <e32property.h>
#include <AknSgcc.h>
#include <w32std.h>

LOCAL_C TBool IsInHiddenList(const TUid& aUid)
	{
	TBuf16<2 * KMaxHiddenApps> lst;
	if(KErrNone != RProperty::Get(KPSUidUikon, KUikAppHiddenList, lst))
		return EFalse;
	for(TInt i = 0; i < KMaxHiddenApps; i++)
		{
		const TInt bytePos = i << 1;
		const TUint32 uid = (lst[bytePos] << 16) | lst[bytePos + 1];
		if(aUid.iUid == uid)
			return ETrue;
		if(uid == 0) //end of list
			return EFalse;
		}
	return EFalse;
	}

EXPORT_C void CAknApplication::PreDocConstructL()
	{
	CEikonEnv* env = CEikonEnv::Static();
	if (!env->StartedAsServerApp() && !env->EikAppUi())
		{
		// Only run this check for top level (non embedded) apps.
		RWsSession& ws = env->WsSession();
		const TInt myWg = env->RootWin().Identifier();
		TInt wgId = 0;

		// set this apps UID in the window group name to remove the gap between this check and it being set in UpdateTaskNameL()
		TUid uid(AppDllUid());
		CApaWindowGroupName* wgName = CApaWindowGroupName::NewLC(ws, myWg);
		wgName->SetAppUid(uid);
		wgName->SetWindowGroupName(env->RootWin());
	      
        // Use a CAknTaskList to check for root instances of apps
        CAknTaskList* taskList = CAknTaskList::NewLC(ws);
        TBool foundInstance = EFalse;
	    
		// Look for another instance of this app
		while (wgId>=0)
			{
		    TBool rootTask = taskList->IsRootWindowGroup(wgId);
		    TBool rootWg = EFalse;
		    TInt wndPriority = -1;
		    if ( wgId != myWg && wgId > 0  && !rootTask )
		        {
                wndPriority = ws.GetWindowGroupOrdinalPriority( wgId );
                RArray<RWsSession::TWindowGroupChainInfo> wgs;
                // it seems effecient to call WindowGroupList here, this codes will seldom executed.
                ws.WindowGroupList( wndPriority,  &wgs );
                   
                TInt count = wgs.Count();
                for ( TInt ii=0; ii<count; ii++ )
                    {
                    const RWsSession::TWindowGroupChainInfo& info = wgs[ii];
                    // find the window group id and check that it has no parent
                    if ( info.iId == wgId )
                        {
                        rootWg = (info.iParentId <= 0);
                        break;
                        }
                    }
                
                wgs.Close();
		        }
		    
			if (wgId && wgId != myWg  &&  ( rootWg || rootTask ) )
				{	// found another app, switch to it & die
				/*
				TApaTask other(ws);
				other.SetWgId(wgId);
				other.BringToForeground();

				CBaActiveScheduler::Exit();
				*/
				foundInstance = ETrue;
				break;

				}

			CApaWindowGroupName::FindByAppUid(uid,ws,wgId);
			}
			
		if(!foundInstance)
			{
			//
            // Application launched with commands EApaCommandBackground or 
            // EApaCommandRunWithoutViews has non-zero ordinal position for their
            // window group.
            // For such applications transition effects on application start
            // should not be used.
            // 
            TInt ordPosition = env->RootWin().OrdinalPosition();
                    
			if (!ordPosition)
			    {
			    iAvkonEnv->TransitionEvent(AknTransEffect::EApplicationStart, AppDllUid());    
			    }			            
			else
			    {
			    iAvkonEnv->TransitionEvent( AknTransEffect::EAppStartupBackground, AppDllUid() );
			    }
			}
        else
            {
            // If application is launched to background, then do not bring application to
            // foreground. This needs to be deduced using ordinal position of root window
            // as command line parameters are not available to this method. With this
            // approach, there is small chance for error, but it's considered to be so
            // rare that this is acceptable. For example, otherwise applications launched
            // to background during startup might cause foreground application changes.
            const TInt ordPosition = env->RootWin().OrdinalPosition();
            if ( !ordPosition )
                {
                if(wgName->Hidden() || IsInHiddenList(AppDllUid()))
                    {
                    iAvkonEnv->TransitionEvent(AknTransEffect::EApplicationStartSwitch, AppDllUid());
                    }
                CAknSgcClient::MoveApp(wgId, ESgcMoveAppToForeground);
                }
            CBaActiveScheduler::Exit();
            }
        CleanupStack::PopAndDestroy(taskList); //taskList        
        CleanupStack::PopAndDestroy(wgName);
        }

	if(env->StartedAsServerApp())
		{
		// Start embedded
		iAvkonEnv->TransitionEvent(AknTransEffect::EEmbeddedApplicationStart, AppDllUid());
		}
	CEikApplication::PreDocConstructL();
	}

EXPORT_C CDictionaryStore* CAknApplication::OpenIniFileLC(RFs& /*aFs*/) const
	{
	// By default, ini files are not supported by SERIES60 applications.
	// If you want to use an ini file, either override this function to base call
	// CEikApplication::OpenIniFileLC, or call it directly.
	User::Leave(KErrNotSupported);
	return NULL;
	}

EXPORT_C void CAknApplication::NewAppServerL(CApaAppServer*& aAppServer)
	{
	aAppServer = new(ELeave) CAknAppServer;
	}
