/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 *  Communicate with secure elements that are attached to the NFC
 *  controller.
 */
#pragma once
#include "SyncEvent.h"
#include "DataQueue.h"
#include "NfcJniUtil.h"
#include "RouteDataSet.h"
extern "C"
{
    #include "nfa_ee_api.h"
    #include "nfa_hci_api.h"
    #include "nfa_hci_defs.h"
    #include "nfa_ce_api.h"
}


class SecureElement
{
public:
    tNFA_HANDLE  mActiveEeHandle;


    /*******************************************************************************
    **
    ** Function:        getInstance
    **
    ** Description:     Get the SecureElement singleton object.
    **
    ** Returns:         SecureElement object.
    **
    *******************************************************************************/
    static SecureElement& getInstance ();


    /*******************************************************************************
    **
    ** Function:        initialize
    **
    ** Description:     Initialize all member variables.
    **                  native: Native data.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool initialize (nfc_jni_native_data* native);


    /*******************************************************************************
    **
    ** Function:        finalize
    **
    ** Description:     Release all resources.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void finalize ();


    /*******************************************************************************
    **
    ** Function:        getSecureElementIdList
    **
    ** Description:     Get a list of ID's of all secure elements.
    **                  e: Java Virtual Machine.
    **
    ** Returns:         List of ID's.
    **
    *******************************************************************************/
    jintArray getSecureElementIdList (JNIEnv* e);


    /*******************************************************************************
    **
    ** Function:        activate
    **
    ** Description:     Turn on the secure element.
    **                  seID: ID of secure element.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool activate (jint seID);


    /*******************************************************************************
    **
    ** Function:        deactivate
    **
    ** Description:     Turn off the secure element.
    **                  seID: ID of secure element.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool deactivate (jint seID);


    /*******************************************************************************
    **
    ** Function:        connectEE
    **
    ** Description:     Connect to the execution environment.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool connectEE ();


    /*******************************************************************************
    **
    ** Function:        disconnectEE
    **
    ** Description:     Disconnect from the execution environment.
    **                  seID: ID of secure element.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool disconnectEE (jint seID);


    /*******************************************************************************
    **
    ** Function:        transceive
    **
    ** Description:     Send data to the secure element; read it's response.
    **                  xmitBuffer: Data to transmit.
    **                  xmitBufferSize: Length of data.
    **                  recvBuffer: Buffer to receive response.
    **                  recvBufferMaxSize: Maximum size of buffer.
    **                  recvBufferActualSize: Actual length of response.
    **                  timeoutMillisec: timeout in millisecond
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
                     INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec);

    void notifyModeSet (tNFA_HANDLE eeHandle, bool success);

    /*******************************************************************************
    **
    ** Function:        notifyListenModeState
    **
    ** Description:     Notify the NFC service about whether the SE was activated
    **                  in listen mode.
    **                  isActive: Whether the secure element is activated.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void notifyListenModeState (bool isActivated);

    /*******************************************************************************
    **
    ** Function:        notifyRfFieldEvent
    **
    ** Description:     Notify the NFC service about RF field events from the stack.
    **                  isActive: Whether any secure element is activated.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void notifyRfFieldEvent (bool isActive);


    /*******************************************************************************
    **
    ** Function:        resetRfFieldStatus ();
    **
    ** Description:     Resets the field status.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void resetRfFieldStatus ();

    /*******************************************************************************
    **
    ** Function:        storeUiccInfo
    **
    ** Description:     Store a copy of the execution environment information from the stack.
    **                  info: execution environment information.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void storeUiccInfo (tNFA_EE_DISCOVER_REQ& info);


    /*******************************************************************************
    **
    ** Function:        getUiccId
    **
    ** Description:     Get the ID of the secure element.
    **                  eeHandle: Handle to the secure element.
    **                  uid: Array to receive the ID.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid);


    /*******************************************************************************
    **
    ** Function:        getTechnologyList
    **
    ** Description:     Get all the technologies supported by a secure element.
    **                  eeHandle: Handle of secure element.
    **                  techList: List to receive the technologies.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList);


    /*******************************************************************************
    **
    ** Function:        notifyTransactionListenersOfAid
    **
    ** Description:     Notify the NFC service about a transaction event from secure element.
    **                  aid: Buffer contains application ID.
    **                  aidLen: Length of application ID.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void notifyTransactionListenersOfAid (const UINT8* aid, UINT8 aidLen);


    /*******************************************************************************
    **
    ** Function:        notifyTransactionListenersOfTlv
    **
    ** Description:     Notify the NFC service about a transaction event from secure element.
    **                  The type-length-value contains AID and parameter.
    **                  tlv: type-length-value encoded in Basic Encoding Rule.
    **                  tlvLen: Length tlv.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void notifyTransactionListenersOfTlv (const UINT8* tlv, UINT8 tlvLen);


    /*******************************************************************************
    **
    ** Function:        connectionEventHandler
    **
    ** Description:     Receive card-emulation related events from stack.
    **                  event: Event code.
    **                  eventData: Event data.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData);


    /*******************************************************************************
    **
    ** Function:        applyRoutes
    **
    ** Description:     Read route data from XML and apply them again
    **                  to every secure element.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void applyRoutes ();


    /*******************************************************************************
    **
    ** Function:        setActiveSeOverride
    **
    ** Description:     Specify which secure element to turn on.
    **                  activeSeOverride: ID of secure element
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void setActiveSeOverride (UINT8 activeSeOverride);


    /*******************************************************************************
    **
    ** Function:        isBusy
    **
    ** Description:     Whether NFC controller is routing listen-mode events or a pipe is connected.
    **
    ** Returns:         True if either case is true.
    **
    *******************************************************************************/
    bool isBusy ();


    /*******************************************************************************
    **
    ** Function         getActualNumEe
    **
    ** Description      Returns number of secure elements we know about.
    **
    ** Returns          Number of secure elements we know about.
    **
    *******************************************************************************/
    UINT8 getActualNumEe();


    /*******************************************************************************
    **
    ** Function         getSeVerInfo
    **
    ** Description      Gets version information and id for a secure element.  The
    **                  seIndex parmeter is the zero based index of the secure
    **                  element to get verion info for.  The version infommation
    **                  is returned as a string int the verInfo parameter.
    **
    ** Returns          ture on success, false on failure
    **
    *******************************************************************************/
    bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid);


    /*******************************************************************************
    **
    ** Function:        isActivatedInListenMode
    **
    ** Description:     Can be used to determine if the SE is activated in listen mode
    **
    ** Returns:         True if the SE is activated in listen mode
    **
    *******************************************************************************/
    bool isActivatedInListenMode();

    /*******************************************************************************
    **
    ** Function:        isRfFieldOn
    **
    ** Description:     Can be used to determine if the SE is in an RF field
    **
    ** Returns:         True if the SE is activated in an RF field
    **
    *******************************************************************************/
    bool isRfFieldOn();

private:
    static const unsigned int MAX_RESPONSE_SIZE = 1024;
    enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute};
    static const int MAX_NUM_EE = 5;    //max number of EE's
    static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe
    static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe
    static const UINT8 EVT_SEND_DATA = 0x10;    //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3
    static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0
    static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1
    static SecureElement sSecElem;
    static const char* APP_NAME;

    UINT8           mDestinationGate;       //destination gate of the UICC
    tNFA_HANDLE     mNfaHciHandle;          //NFA handle to NFA's HCI component
    nfc_jni_native_data* mNativeData;
    bool    mIsInit;                // whether EE is initialized
    UINT8   mActualNumEe;           // actual number of EE's reported by the stack
    UINT8   mNumEePresent;          // actual number of usable EE's
    bool    mbNewEE;
    UINT8   mNewPipeId;
    UINT8   mNewSourceGate;
    UINT16  mActiveSeOverride;      // active "enable" seid, 0 means activate all SEs
    tNFA_STATUS mCommandStatus;     //completion status of the last command
    bool    mIsPiping;              //is a pipe connected to the controller?
    RouteSelection mCurrentRouteSelection;
    int     mActualResponseSize;         //number of bytes in the response received from secure element
    bool    mUseOberthurWarmReset;  //whether to use warm-reset command
    bool    mActivatedInListenMode; // whether we're activated in listen mode
    UINT8   mOberthurWarmResetCommand; //warm-reset command byte
    tNFA_EE_INFO mEeInfo [MAX_NUM_EE];  //actual size stored in mActualNumEe
    tNFA_EE_DISCOVER_REQ mUiccInfo;
    tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg;
    SyncEvent       mEeRegisterEvent;
    SyncEvent       mHciRegisterEvent;
    SyncEvent       mEeSetModeEvent;
    SyncEvent       mPipeListEvent;
    SyncEvent       mCreatePipeEvent;
    SyncEvent       mPipeOpenedEvent;
    SyncEvent       mAllocateGateEvent;
    SyncEvent       mDeallocateGateEvent;
    SyncEvent       mRoutingEvent;
    SyncEvent       mUiccInfoEvent;
    SyncEvent       mUiccListenEvent;
    SyncEvent       mAidAddRemoveEvent;
    SyncEvent       mTransceiveEvent;
    SyncEvent       mVerInfoEvent;
    SyncEvent       mRegistryEvent;
    UINT8           mVerInfo [3];
    UINT8           mResponseData [MAX_RESPONSE_SIZE];
    RouteDataSet    mRouteDataSet; //routing data
    std::vector<std::string> mUsedAids; //AID's that are used in current routes
    UINT8           mAidForEmptySelect[NCI_MAX_AID_LEN+1];
    Mutex           mMutex; // protects fields below
    bool            mRfFieldIsOn; // last known RF field state
    struct timespec mLastRfFieldToggle; // last time RF field went off
    /*******************************************************************************
    **
    ** Function:        SecureElement
    **
    ** Description:     Initialize member variables.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    SecureElement ();


    /*******************************************************************************
    **
    ** Function:        ~SecureElement
    **
    ** Description:     Release all resources.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    ~SecureElement ();


    /*******************************************************************************
    **
    ** Function:        nfaEeCallback
    **
    ** Description:     Receive execution environment-related events from stack.
    **                  event: Event code.
    **                  eventData: Event data.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData);


    /*******************************************************************************
    **
    ** Function:        nfaHciCallback
    **
    ** Description:     Receive Host Controller Interface-related events from stack.
    **                  event: Event code.
    **                  eventData: Event data.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    static void nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData);


    /*******************************************************************************
    **
    ** Function:        findEeByHandle
    **
    ** Description:     Find information about an execution environment.
    **                  eeHandle: Handle to execution environment.
    **
    ** Returns:         Information about an execution environment.
    **
    *******************************************************************************/
    tNFA_EE_INFO *findEeByHandle (tNFA_HANDLE eeHandle);


    /*******************************************************************************
    **
    ** Function:        findUiccByHandle
    **
    ** Description:     Find information about an execution environment.
    **                  eeHandle: Handle of the execution environment.
    **
    ** Returns:         Information about the execution environment.
    **
    *******************************************************************************/
    tNFA_EE_DISCOVER_INFO *findUiccByHandle (tNFA_HANDLE eeHandle);


    /*******************************************************************************
    **
    ** Function:        getDefaultEeHandle
    **
    ** Description:     Get the handle to the execution environment.
    **
    ** Returns:         Handle to the execution environment.
    **
    *******************************************************************************/
    tNFA_HANDLE getDefaultEeHandle ();


    /*******************************************************************************
    **
    ** Function:        adjustRoutes
    **
    ** Description:     Adjust routes in the controller's listen-mode routing table.
    **                  selection: which set of routes to configure the controller.
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void adjustRoutes (RouteSelection selection);


    /*******************************************************************************
    **
    ** Function:        adjustProtocolRoutes
    **
    ** Description:     Adjust default routing based on protocol in NFC listen mode.
    **                  isRouteToEe: Whether routing to EE (true) or host (false).
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);


    /*******************************************************************************
    **
    ** Function:        adjustTechnologyRoutes
    **
    ** Description:     Adjust default routing based on technology in NFC listen mode.
    **                  isRouteToEe: Whether routing to EE (true) or host (false).
    **
    ** Returns:         None
    **
    *******************************************************************************/
    void adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);


    /*******************************************************************************
    **
    ** Function:        getEeInfo
    **
    ** Description:     Get latest information about execution environments from stack.
    **
    ** Returns:         True if at least 1 EE is available.
    **
    *******************************************************************************/
    bool getEeInfo ();

    /*******************************************************************************
    **
    ** Function:        eeStatusToString
    **
    ** Description:     Convert status code to status text.
    **                  status: Status code
    **
    ** Returns:         None
    **
    *******************************************************************************/
    static const char* eeStatusToString (UINT8 status);


    /*******************************************************************************
    **
    ** Function:        encodeAid
    **
    ** Description:     Encode AID in type-length-value using Basic Encoding Rule.
    **                  tlv: Buffer to store TLV.
    **                  tlvMaxLen: TLV buffer's maximum length.
    **                  tlvActualLen: TLV buffer's actual length.
    **                  aid: Buffer of Application ID.
    **                  aidLen: Aid buffer's actual length.
    **
    ** Returns:         True if ok.
    **
    *******************************************************************************/
    bool encodeAid (UINT8* tlv, UINT16 tlvMaxLen, UINT16& tlvActualLen, const UINT8* aid, UINT8 aidLen);
};