/*
 * Copyright (C) 2005 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.
 */

//
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H

#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>

#include <linux/input.h>

struct pollfd;

namespace android {

class KeyLayoutMap;

/*
 * Grand Central Station for events.  With a single call to waitEvent()
 * you can wait for:
 *  - input events from the keypad of a real device
 *  - input events and meta-events (e.g. "quit") from the simulator
 *  - synthetic events from the runtime (e.g. "URL fetch completed")
 *  - real or forged "vsync" events
 *
 * Do not instantiate this class.  Instead, call startUp().
 */
class EventHub : public RefBase
{
public:
    EventHub();
    
    status_t errorCheck() const;
    
    // bit fields for classes of devices.
    enum {
        CLASS_KEYBOARD      = 0x00000001,
        CLASS_ALPHAKEY      = 0x00000002,
        CLASS_TOUCHSCREEN   = 0x00000004,
        CLASS_TRACKBALL     = 0x00000008,
        CLASS_TOUCHSCREEN_MT= 0x00000010,
        CLASS_DPAD          = 0x00000020,
        CLASS_MOUSE         = 0x00000040
    };
    uint32_t getDeviceClasses(int32_t deviceId) const;
    
    String8 getDeviceName(int32_t deviceId) const;
    
    int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
            int* outMaxValue, int* outFlat, int* outFuzz) const;
        
    int getSwitchState(int sw) const;
    int getSwitchState(int32_t deviceId, int sw) const;
    
    int getScancodeState(int key) const;
    int getScancodeState(int32_t deviceId, int key) const;
    
    int getKeycodeState(int key) const;
    int getKeycodeState(int32_t deviceId, int key) const;
    
    status_t scancodeToKeycode(int32_t deviceId, int scancode,
            int32_t* outKeycode, uint32_t* outFlags) const;

    // exclude a particular device from opening
    // this can be used to ignore input devices for sensors
    void addExcludedDevice(const char* deviceName);

    // special type codes when devices are added/removed.
    enum {
        DEVICE_ADDED = 0x10000000,
        DEVICE_REMOVED = 0x20000000
    };
    
    // examine key input devices for specific framework keycode support
    bool hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags);

    virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
            int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
            int32_t* outValue, nsecs_t* outWhen);

protected:
    virtual ~EventHub();
    
private:
    bool openPlatformInput(void);
    int32_t convertDeviceKey_TI_P2(int code);

    int open_device(const char *device);
    int close_device(const char *device);
    int scan_dir(const char *dirname);
    int read_notify(int nfd);

    status_t mError;

    struct device_t {
        const int32_t   id;
        const String8   path;
        String8         name;
        uint32_t        classes;
        uint8_t*        keyBitmask;
        KeyLayoutMap*   layoutMap;
        String8         keylayoutFilename;
        device_t*       next;
        
        device_t(int32_t _id, const char* _path, const char* name);
        ~device_t();
    };

    device_t* getDevice(int32_t deviceId) const;
    bool hasKeycode(device_t* device, int keycode) const;
    
    // Protect all internal state.
    mutable Mutex   mLock;
    
    bool            mHaveFirstKeyboard;
    int32_t         mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
    
    struct device_ent {
        device_t* device;
        uint32_t seq;
    };
    device_ent      *mDevicesById;
    int             mNumDevicesById;
    
    device_t        *mOpeningDevices;
    device_t        *mClosingDevices;
    
    device_t        **mDevices;
    struct pollfd   *mFDs;
    int             mFDCount;

    bool            mOpened;
    List<String8>   mExcludedDevices;

    // device ids that report particular switches.
#ifdef EV_SW
    int32_t         mSwitches[SW_MAX+1];
#endif
};

}; // namespace android

#endif // _RUNTIME_EVENT_HUB_H
