/*
* Copyright (c) 2009 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:  Implementation of MDispatcher interface that used
*        to dispatch incoming messages to servers
*        and outcoming to host client.
*        MDispatcher should be used by services to send outcoming
*        messages and by communication modules to dispatch messages.
*        This is the main class in HtiFramework.
*
*/


#ifndef DISPATCHER_H__
#define DISPATCHER_H__

#include <e32base.h>
#include <e32cons.h>
#include "HtiDispatcherInterface.h"
#include "HtiMessage.h"
#include "HtiLogging.h"

const static TUid KHtiSystemServiceUid = { 0x1020DEB6 };

const static TInt KServiceArrayGranularity = 4;

const static TInt KHandbrakeTimerIntervalMS = 100 * 1000; //in microseconds
const static TInt KMaxFailedDispatchCalls = 4;

//forward declarations
class CHtiCommAdapter;
//class CHtiMessage;
class CHtiMessageQueue;
class CHTIServicePluginInterface;
class CHTICommPluginInterface;
class CHtiSecurityManager;


// HTI Framework error codes
enum THtiError
    {
    EHtiErrBigMessage = 1,
    EHtiErrNoMemory,
    EHtiErrServiceNotFound,
    EHtiErrServiceError,
    EHtiErrNotAuthorized,
    EHtiErrUnwrap
    };

// Types for restore factory settings
enum TRfsType
    {
    ERfsUnknown = -1,
    ERfsNormal  = 0,
    ERfsDeep    = 1
    };

/**
* Helper class that constructs messages
* used by the HTI system service
*
**/
class THtiSystemProtocolHelper
    {
public:
    static TDesC8* ErrorMessageL( TInt aHtiErrorCode,
                                  const TUid aTargetServiceUid );
    static TDesC8* ErrorMessageL( TInt aHtiErrorCode,
                                  const TUid aTargetServiceUid,
                                  TInt aErrorCode,
                                  const TDesC8& aErrorDescription );
    static TDesC8* AuthMessageL( const TDesC8& aToken );
    };

class CHtiDispatcher:
    public CBase,
    public MHtiDispatcher
    {
public:
    /**
    * Creates dispatcher. Leaves on failure.
    *
    * @param aCommPlugin plug-in name to use for communication
    * @param aMaxMsgSize maximum size for an incoming message
    * @param aMaxQueueMemorySize maximum size of all messages in the
    *        incoming queue
    * @param aReconnectDelay seconds of delay for reconnecting when connection
    *        lost. Value 0 means that reconnect would not happen.
    * @param aShowConsole whether to open a console window for HTI
    * @param aShowErrorDialogs whether to show a dialog in case of critical
    *        error or just silently exit
    * @return pointer to the created CHtiDispatcher instance
    */
    static CHtiDispatcher* NewL( const TDesC8& aCommPlugin,
                                 TInt aMaxMsgSize,
                                 TInt aMaxQueueMemorySize,
                                 TInt aReconnectDelay,
                                 TBool aShowConsole,
                                 TBool aShowErrorDialogs );

    /**
    * Creates dispatcher and puts the created isntance to the cleanup stack.
    * Leaves on failure.
    *
    * @param aCommPlugin plug-in name to use for communication
    * @param aMaxMsgSize maximum size for an incoming message
    * @param aMaxQueueMemorySize maximum size of all messages in the
    *        incoming queue
    * @param aReconnectDelay seconds of delay for reconnecting when connection
    *        lost. Value 0 means that reconnect would not happen.
    * @param aShowConsole whether to open a console window for HTI
    * @param aShowErrorDialogs whether to show a dialog in case of critical
    *        error or just silently exit
    * @return pointer to the created CHtiDispatcher instance
    */
    static CHtiDispatcher* NewLC( const TDesC8& aCommPlugin,
                                  TInt aMaxMsgSize,
                                  TInt aMaxQueueMemorySize,
                                  TInt aReconnectDelay,
                                  TBool aShowConsole,
                                  TBool aShowErrorDialogs );

    /**
    * Destructor. Frees the allocated resources.
    */
    ~CHtiDispatcher();

    /**
    *
    * Parse message to a corresponding service
    * The function returns immediately.
    * Transfer ownership of aMessage.
    *
    *  @param aMessage contains incoming message
    */
    void DispatchIncomingMessage( CHtiMessage* aMessage );

    /**
    * Construct and dispath HTI error message. For internal use.
    *
    * @param aHtiErrorCode error code
    * @param aTargetService UID of the service plug-in that caused the error
    * @return standard Symbian error code
    */
    TInt DispatchOutgoingErrorMessage( THtiError aHtiErrorCode,
                   const TUid aTargetService = KHtiSystemServiceUid );

public: // Inherited methods from MHtiDispatcher
    TInt DispatchOutgoingMessage( TDesC8* aMessage,
                    const TUid aTargetServiceUid,
                    TBool aWrappedFlag,
                    THtiMessagePriority aPriority );

    TInt DispatchOutgoingMessage( TDesC8* aMessage,
                    const TUid aTargetServiceUid );

    TInt DispatchOutgoingErrorMessage( TInt aErrorCode,
                    const TDesC8& aErrorDescription,
                    const TUid aTargetServiceUid );

    /**
    * Adds memory observer.
    *
    * @param anObserver memory observer
    */
    void AddMemoryObserver( MHtiMemoryObserver* anObserver );

    /**
    * Removes memory observer.
    *
    * @param anObserver memory observer
    */
    void RemoveMemoryObserver( MHtiMemoryObserver* anObserver );

    /**
    * Returns the amount of memory available for message in the incoming queue
    *
    */
    TInt GetFreeMemory();

    void Notify( TInt aError );

    /*
    * Returns a pointer to the HTI console
    */
    CConsoleBase* GetConsole();

    /**
    * Unload all service plugins and clear queues
    */
    void Reset();

    /*
    * Shutdown HTI and reboot the device.
    *
    * Called from service plug-ins or from EHtiReboot HtiSystem command
    */
    void ShutdownAndRebootDeviceL();

    /*
    * Query the ShowErrorDialogs configuration value.
    * @return iShowErrorDialogs value
    */
    TBool GetShowErrorDialogs();

    
    /*
     * Delay a period and reconnect when connection lost.
     * If the period is 0, reconnect would not happen.
     * @return whether reconnect
     */
     TBool CommReconnect();
     
protected:
    /**
    * Constructors
    *
    */
    CHtiDispatcher( TInt aMaxQueueMemorySize, TInt aReconnectDelay, TBool aShowErrorDialogs );

    void ConstructL( const TDesC8& aCommPlugin,
                     TInt aMaxMsgSize,
                     TBool aShowConsole );

    /**
    * Construct and dispath HTI error message. For internal use
    *
    * @param aHtiErrorCode error code
    * @param aLeaveCode leave code that caused error
    * @param aTargetServiceUid UID of the service plug-in that caused the error
    *
    */
    TInt DispatchOutgoingErrorMessage( THtiError aHtiErrorCode,
                                    TInt aLeaveCode,
                                    const TUid aTargetServiceUid );

    /**
    * Ensures that iIdle is started
    * when a new message come
    *
    */
    void Start();

    /**
    * Does message dispatching one at a time
    * This method is called by the static callback function
    * DispatchCallback().
    *
    */
    TInt DoDispatch();

    void DoMemoryNotification();

    /**
    * Callback functions called by CIdle in idel time to
    * process messages in the queues
    *
    * @param aObj the reference to a CHTIDispatcher is passed
    *             to call its non-static DoDispatch() method
    */
    static TInt DispatchCallback( TAny* aObj );

    /**
    * Finds and if needed loads specified service
    * Returns NULL if service in question was not found
    *
    */
    CHTIServicePluginInterface* GetService( const TUid aServiceUid );

    /**
    * Destructs all loaded services from iLoadedServices array.
    * Note this function does not delete iLoadedServices object itself.
    *
    */
    void UnloadAllServices();

    /**
    * Used instead of panic when framework cannot work further
    * Reason code and description used for logging
    *
    * @param aReason code for rebooting
    * @param aReasonDescr description
    */
    void UrgentReboot( TInt aReason, const TDesC8& aReasonDescr );

    /**
    * Handle HTI message addressed to HTI system service.
    * It's processed right in the dispatcher.
    * The method is trapped and no special actions if it leaves.
    * @param aMessage the message data
    */
    void HandleSystemMessageL( const TDesC8& aMessage );

    // functions to handle HTI system commands

    /**
    * Phone reboot
    *
    */
    void Reboot();

    /**
    * Activate restore factory settings. Causes also a reboot.
    * The mode of restore factory settings (normal or deep) is
    * defined by iRfsMode.
    */
    void RestoreFactorySettings();

    /**
    * Checks whether given file is in a ROM drive.
    * @param aFileName full path to the file to check
    */
    TBool IsFileInRom( const TDesC& aFileName );

    TDesC8* ServicePluginsListL();

    /**
    * Checks and readjust priorities of comm adapters and idle object to
    * prevent overflow of message queues.
    *
    */
    void CheckPriorities();

    /**
    * Kills HTI watchdog process if it exists.
    *
    */
    void KillHtiWatchDogL();

#ifdef __ENABLE_LOGGING__
    /**
    * List in log files all found comm and service plugins
    */
    void DebugListPlugins();
#endif

    /**
    * Generate unique ID for HTI instance.
    */
    void CreateInstanceId();

    /**
    * Maps the service plugin protocol UID to implementation UID and vice versa.
    */
    TUid MapServicePluginUid( const TUid aUid );

private:
    /**
    * used to dispatch messages when thread is free
    */
    CIdle* iIdle;

    /**
    * Indicates that iIdle was started
    */
    TBool iIdleActive;

    /**
    * Incoming message queue
    * holds pointers to messages located in heap
    */
    CHtiMessageQueue* iIncomingQueue;

    /**
    * Outgoing message queue
    * holds pointers to messages located in heap
    */
    CHtiMessageQueue* iOutgoingQueue;

    /**
    * loaded service plugins description
    */
    struct TServiceItem
        {
        TUid iServiceUid;
        CHTIServicePluginInterface* iService; /** service instance */
        };

    /**
    * An array that keeps all loaded service plugins
    */
    RArray<TServiceItem>* iLoadedServices;

    /**
    * Memory observers
    */
    RPointerArray<MHtiMemoryObserver>* iMemoryObservers;

    /**
    * Instance of comm. plug-in used by iListener and iSender.
    * It's not used by dispatcher.
    */
    CHTICommPluginInterface* iCommPlugin;

    /**
    * CCommAdapter instance for constant receiving of incoming HTI messages
    */
    CHtiCommAdapter* iListener;

    /**
    * CCommAdapter instance for sending outgoing HTI messages
    */
    CHtiCommAdapter* iSender;

    /**
    * Security manager
    */
    CHtiSecurityManager* iSecurityManager;

    /**
    * maximum size of all messages in the incoming queue
    */
    const TInt iMaxQueueMemorySize;

    /**
    * Flag to indicate reboot after framework stoped
    */
    TBool iToReboot;

    /**
    * Flag indicating the requested factory settings restore mode.
    */
    TRfsType iRfsMode;

    /**
    * Queue size thresold for priorities readjusting
    */
    TInt iQueueSizeLowThresold;
    TInt iQueueSizeHighThresold;

    /**
    * Console for HTI
    */
    CConsoleBase* iConsole;

    /**
    * By default the idle object and comm adapters AO will have the same priority
    * iIdle will be added later to the AS that gives comm. adapter AO priority
    * In case of very fast incoming data there is possibility that idle will not be
    * called at all, because comm API will comlete async request at once. That will
    * lead to incoming queue overflow. The solution is to change AOs priorities.
    * Using AO priorities directly is complicated that active AO's priority cannot be changed.
    * So the order of AOs with equal priorities used to change the way they will be
    * picked up by AS.
    * When new incoming message is added, in comm adapter AO, the incoming queue is checked
    * in case it reaches predefined high-watermark, comm adapter AO is removed from AS and
    * added again, so idle AO will be picked next time.
    * when idle AO checks that incoming queue is less than predefined low-watermark, it will
    * remove itself and add to AS, to give a way to comm adapter's AO.
    * The following flag iIdleOverCommAdapter is used when idle is first in AS.
    *
    */
    TBool iIdleOverCommAdapter;

    /**
    * Unique ID for HTI instance.
    * The ID is generated only when it is queried for the first time (to add
    * randomness). Until then it's zero.
    */
    TUint32 iHtiInstanceId;

    /**
    * Indicates whether to show error dialogs (notifiers) in case of critical
    * errors or just silently exit.
    */
    TBool iShowErrorDialogs;
    
    /**
     * Delay a period and reconnect when connection lost.
     * If the period is 0, reconnect would not happen.
     */
    TInt iReconnectDelay;
    };


#endif
