/*  LilyPad - Pad plugin for PS2 Emulator
 *  Copyright (C) 2002-2017  PCSX2 Dev Team/ChickenLiver
 *
 *  PCSX2 is free software: you can redistribute it and/or modify it under the
 *  terms of the GNU Lesser General Public License as published by the Free
 *  Software Found- ation, either version 3 of the License, or (at your option)
 *  any later version.
 *
 *  PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with PCSX2.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef INPUT_MANAGER_H
#define INPUT_MANAGER_H

// Both of these are hard coded in a lot of places, so don't modify them.
// Base sensitivity means that a sensitivity of that corresponds to a factor of 1.
// Fully down means that value corresponds to a button being fully down (255).
// a value of 128 or more corresponds to that button being pressed, for binary
// values.
#define BASE_SENSITIVITY (1 << 16)
#define BASE_ANALOG_SENSITIVITY (87183)
#define FULLY_DOWN (1 << 16)

#define DEFAULT_DEADZONE (BASE_SENSITIVITY * 201 / 1000)

/* Idea is for this file and the associated cpp file to be Windows independent.
 * Still more effort than it's worth to port to Linux, however.
 */

enum PadType {
    DisabledPad,
    Dualshock2Pad,
    GuitarPad,
    PopnPad,
    MousePad,
    neGconPad,
    numPadTypes // total number of PadTypes. Add new PadType above this line.
};

// Mostly match DirectInput8 values.  Note that these are for physical controls.
// One physical axis maps to 3 virtual ones, and one physical POV control maps to
// 4 virtual ones.
enum ControlType {
    NO_CONTROL = 0,
    // Axes are ints.  Relative axes are for mice, mice wheels, etc,
    // and are always reported relative to their last value.
    // Absolute axes range from -65536 to 65536 and are absolute positions,
    // like for joysticks and pressure sensitive buttons.
    RELAXIS = 1,
    ABSAXIS = 2,

    // Buttons range from 0 to 65536.
    PSHBTN = 4,
    TGLBTN = 8,

    // POV controls are ints, values range from -1 to 36000.
    // -1 means not pressed, otherwise it's an angle.
    // For easy DirectInput compatibility, anything outside.
    // that range is treated as -1 (Though 36000-37000 is treated
    // like 0 to 1000, just in case).
    POV = 16,

    // Pressure sensitive buttons.  Only a different type because
    // they have configurable dead zones, unlike  push or toggle buttons.
    PRESSURE_BTN = 32,
};

// Masks to determine button type.  Don't need one for POV.
#define BUTTON (PSHBTN | TGLBTN | PRESSURE_BTN)
#define BINARY_BUTTON (PSHBTN | TGLBTN)
#define AXIS 3

struct Binding
{
    int controlIndex;
    int command;
    int sensitivity;
    int deadZone;
    int skipDeadZone;
    unsigned char rapidFire;
};

#define UID_AXIS (1U << 31)
#define UID_POV (1 << 30)

#define UID_AXIS_POS (1U << 24)
#define UID_AXIS_NEG (2U << 24)
#define UID_POV_N (3 << 24)
#define UID_POV_E (4 << 24)
#define UID_POV_S (5 << 24)
#define UID_POV_W (6 << 24)

// One of these exists for each bindable object.
// Bindable objects consist of buttons, axis, pov controls,
// and individual axis/pov directions.  Not that pov controls
// cannot actually be bound, but when trying to bind as an axis,
// all directions are assigned individually.
struct VirtualControl
{
    // Unique id for control, given device.  Based on source control's id,
    // source control type, axis/pov flags if it's a pov/axis (Rather than
    // a button or a pov/axis control's individual button), and an index,
    // if the control is split.
    unsigned int uid;
    // virtual key code.  0 if none.
    int physicalControlIndex;
};

// Need one for each button, axis, and pov control.
// API-specific code creates the PhysicalControls and
// updates their state, standard function then populates
// the VirtualControls and queues the keyboard messages, if
// needed.
struct PhysicalControl
{
    // index of the first virtual control corresponding to this.
    // Buttons have 1 virtual control, axes 3, and povs 5, all
    // in a row.
    int baseVirtualControlIndex;
    ControlType type;
    // id.  Must be unique for control type.
    // short so can be combined with other values to get
    // uid for virtual controls.
    unsigned short id;
    unsigned short vkey;
    wchar_t *name;
};

enum DeviceAPI {
    NO_API = 0,
    DI = 1,
    WM = 2,
    RAW = 3,
    XINPUT = 4,
    DS3 = 5,
    // Not currently used.
    LLHOOK = 6,
    // Not a real API, obviously.  Only used with keyboards,
    // to ignore individual buttons.  Wrapper itself takes care
    // of ignoring bound keys.  Otherwise, works normally.
    IGNORE_KEYBOARD = 7,
    // XXX
    LNX_KEYBOARD = 16,
    LNX_JOY = 17,
};

enum DeviceType {
    NO_DEVICE = 0,
    KEYBOARD = 1,
    MOUSE = 2,
    OTHER = 3
};

enum EffectType {
    EFFECT_CONSTANT,
    EFFECT_PERIODIC,
    EFFECT_RAMP
};

// force range sfrom -BASE_SENSITIVITY to BASE_SENSITIVITY.
// Order matches ForceFeedbackAxis order.  force of 0 means to
// ignore that axis completely.  Force of 1 or -1 means to initialize
// the axis with minimum force (Possibly 0 force), if applicable.
struct AxisEffectInfo
{
    int force;
};

struct ForceFeedbackBinding
{
    AxisEffectInfo *axes;
    int effectIndex;
    unsigned char motor;
};

// Bindings listed by effect, so I don't have to bother with
// indexing effects.
struct ForceFeedbackEffectType
{
    wchar_t *displayName;
    // Because I'm lazy, can only have ASCII characters and no spaces.
    wchar_t *effectID;
    // constant, ramp, or periodic
    EffectType type;
};


struct ForceFeedbackAxis
{
    wchar_t *displayName;
    int id;
};

// Used both for active devices and for sets of settings for devices.
// Way things work:
// LoadSettings() will delete all device info, then load settings to get
// one set of generic devices.  Then I enumerate all devices.  Then I merge
// them, moving settings from the generic devices to the enumerated ones.

struct PadBindings
{
    Binding *bindings;
    int numBindings;
    ForceFeedbackBinding *ffBindings;
    int numFFBindings;
};

class WndProcEater;

struct InitInfo
{
    // 1 when binding key to ignore.
    int bindingIgnore;
    // 1 when binding.
    int binding;

#ifdef _MSC_VER
    HWND hWndTop;

    // For config screen, need to eat button's message handling.
    //HWND hWndButton;

    WndProcEater *hWndProc;
#else
    // Linux equivalent to HWND
    Display *GSdsp;
    Window GSwin;
#endif
};


// Mostly self-contained, but bindings are modified by config.cpp, to make
// updating the ListView simpler.
class Device
{
public:
    DeviceAPI api;
    DeviceType type;
    char active;
    char attached;
    // Based on input modes.
    char enabled;

#ifdef _MSC_VER
    // Not all devices need to subclass the windproc, but most do so might as well
    // put it here... --air
    WndProcEater *hWndProc;
#endif

    union
    {
        // Allows for one loop to compare all 3 in order.
        wchar_t *IDs[3];
        struct
        {
            // Same as DisplayName, when not given.  Absolutely must be unique.
            // Used for loading/saving controls.  If matches, all other strings
            // are ignored, so must be unique.
            wchar_t *instanceID;
            // Not required.  Used when a device's instance id changes, doesn't have to
            // be unique.  For devices that can only have one instance, not needed.
            wchar_t *productID;

            wchar_t *displayName;
        };
    };

    PadBindings pads[2][4][numPadTypes];

    // Virtual controls.  All basically act like pressure sensitivity buttons, with
    // values between 0 and 2^16.  2^16 is fully down, 0 is up.  Larger values
    // are allowed, but *only* for absolute axes (Which don't support the flip checkbox).
    // Each control on a device must have a unique id, used for binding.
    VirtualControl *virtualControls;
    int numVirtualControls;

    int *virtualControlState;
    int *oldVirtualControlState;

    PhysicalControl *physicalControls;
    int numPhysicalControls;
    int *physicalControlState;

    ForceFeedbackEffectType *ffEffectTypes;
    int numFFEffectTypes;
    ForceFeedbackAxis *ffAxes;
    int numFFAxes;
    void AddFFAxis(const wchar_t *displayName, int id);
    void AddFFEffectType(const wchar_t *displayName, const wchar_t *effectID, EffectType type);

    Device(DeviceAPI, DeviceType, const wchar_t *displayName, const wchar_t *instanceID = 0, const wchar_t *deviceID = 0);
    virtual ~Device();

    // Allocates memory for old and new state, sets everything to 0.
    // all old states are in one array, buttons, axes, and then POVs.
    // start of each section is int aligned.  This makes it DirectInput
    // compatible.
    void AllocState();

    // Doesn't actually flip.  Copies current state to old state.
    void FlipState();

    // Frees state variables.
    void FreeState();

    ForceFeedbackEffectType *GetForcefeedbackEffect(wchar_t *id);
    ForceFeedbackAxis *GetForceFeedbackAxis(int id);

    VirtualControl *GetVirtualControl(unsigned int uid);

    PhysicalControl *AddPhysicalControl(ControlType type, unsigned short id, unsigned short vkey, const wchar_t *name = 0);
    VirtualControl *AddVirtualControl(unsigned int uid, int physicalControlIndex);

    virtual wchar_t *GetVirtualControlName(VirtualControl *c);
    virtual wchar_t *GetPhysicalControlName(PhysicalControl *c);

    void CalcVirtualState();

    virtual int Activate(InitInfo *args)
    {
        return 0;
    }

    inline virtual void Deactivate()
    {
        FreeState();
        active = 0;
    }

    // Default update proc.  All that's needed for post-based APIs.
    inline virtual int Update()
    {
        return active;
    }

    // force is from -FULLY_DOWN to FULLY_DOWN.
    // Either function can be overridden.  Second one by default calls the first
    // for every bound effect that's affected.

    // Note:  Only used externally for binding, so if override the other one, can assume
    // all other forces are currently 0.
    inline virtual void SetEffect(ForceFeedbackBinding *binding, unsigned char force) {}
    virtual void SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);

    // Called after reading.  Basically calls FlipState().
    // Some device types (Those that don't incrementally update)
    // could call FlipState elsewhere, but this makes it simpler to ignore
    // while binding.
    virtual void PostRead();
};

class InputDeviceManager
{
public:
    Device **devices;
    int numDevices;

    void ClearDevices();

    // When refreshing devices, back up old devices, then
    // populate this with new devices, then call copy bindings.
    // All old bindings are copied to matching devices.

    // When old devices are missing, I do a slightly more careful search
    // using productIDs and then (in desperation) displayName.
    // Finally create new dummy devices if no matches found.
    void CopyBindings(int numDevices, Device **devices);


    InputDeviceManager();
    ~InputDeviceManager();

    void AddDevice(Device *d);
    Device *GetActiveDevice(InitInfo *info, unsigned int *uid, int *index, int *value);
    void Update(InitInfo *initInfo);

    // Called after reading state, after Update().
    void PostRead();

    void SetEffect(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);

    // Update does this as needed.
    // void GetInput(void *v);
    void ReleaseInput();

    void DisableDevice(int index);
    inline void EnableDevice(int i)
    {
        devices[i]->enabled = 1;
    }

    void EnableDevices(DeviceType type, DeviceAPI api);
    void DisableAllDevices();
};

extern InputDeviceManager *dm;

#endif
