{
    This file is part of Chentrah,
    Copyright (C) 2004-2012 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program 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 this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************}

var
  GamepadError: WideString;
  GamepadPresent: boolean = false;

const
  GAMEPAD_PRESENCE_CHECK_PERIOD = 2500; //miliseconds. Rounded up to 100
  GAMEPAD_POLLING_FREQUENCE = 100; //Hz
  GAMEPAD_RUMBLE_DURATION_LIMIT = 5.0; //maximum seconds it would run if the requested amplitude (MotherState.GamepadRumble[0]) doesn't change
  GAMEPAD_EVENT_QUEUE_LIMIT = 1000;

  XUSER_MAX_COUNT = 4;
  XINPUT_DEVTYPE_GAMEPAD          = $01;
  XINPUT_DEVSUBTYPE_GAMEPAD       = $01;
  XINPUT_FLAG_GAMEPAD             = $00000001;

  XinputButtons: array[KEY_GAMEPAD_DPAD_UP..KEY_GAMEPAD_Y] of word = (
    $0001, $0002, $0004, $0008, $0010, $0020, $0040, $0080, $0100, $0200, $1000, $2000, $4000, $8000
  );

  XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  = 7849;
  XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE = 8689;
  XINPUT_GAMEPAD_TRIGGER_THRESHOLD    = 30;

type

{$ifdef windows}

(*type
{ $packrecords c}  //This moved to a separate unit because this directive fucks up the combined main header dump
  T_XINPUT_GAMEPAD = record
    wButtons:         Word;
    bLeftTrigger:     Byte;
    bRightTrigger:    Byte;
    sThumbLX:         Smallint;
    sThumbLY:         Smallint;
    sThumbRX:         Smallint;
    sThumbRY:         Smallint;
  end;
  T_XINPUT_STATE = record
    dwPacketNumber:   DWORD;
    Gamepad:          T_XINPUT_GAMEPAD;
  end;
  T_XINPUT_VIBRATION = record
    case integer of
    0: (
      wLeftMotorSpeed:  Word;
      wRightMotorSpeed: Word;
    );
    1: (
      Amp: array[0..1] of Word;
    );
  end;
  T_XINPUT_CAPABILITIES = record
    _Type:            Byte;
    SubType:          Byte;
    Flags:            Word;
    Gamepad:          T_XINPUT_GAMEPAD;
    Vibration:        T_XINPUT_VIBRATION;
  end;
*)

  TGamepadManager = class;

  TjoyState = record
    ix, iy, ixmax,ixmin,iymax,iymin: integer;
    x, y: float;
    rdtstamp: qword;
  end;

  TGamepadmanagerThread = class(TThread)
    parent:  TGamepadManager;
    KeyState: array[KEY_GAMEPAD_LEFT_TRIGGER..KEY_GAMEPAD_Y] of boolean;
    JoyState: array[TJoystickType] of TJoyState;
    RumbleAmp,
    RumbleTime: array[0..1] of float;
    Enabled, HasFocus: boolean;
    PreviousRateCullTsc: qword;
    State: T_XINPUT_STATE;
    constructor Create(_parent: TGamepadManager);
    procedure ProcessKey(k: TKey; pressed: boolean);
    procedure ProcessJoystick(t: TJoystickType; rawix, rawiy, range: integer);
    procedure Execute; override;
    function Poll: boolean;
    procedure ProcessRumble(seconds_passed: float);
  end;

{$endif}
  TGamepadManager = class
{$ifdef windows}
    DllName: AnsiString;
    Dll: THandle;
    Thread: TGamepadmanagerThread;
    LeftTriggerThreshold,
    RightTriggerThreshold,
    LeftThumbDeadZone,
    RightThumbDeadZone: float;
    ThreadCrashed: WideString;
    CriticalSection: TRTLCriticalSection;
    MaxEvent: integer;
    Events: array[1..GAMEPAD_EVENT_QUEUE_LIMIT] of TInputEvent;
    function Init(just_starting: boolean = false): boolean;
    procedure AddEvent(_evtype: integer; _key: TKey); overload;
    procedure AddEvent(joy_type: TJoystickType; _x, _y, _dx, _dy: float); overload;
{$endif}
    constructor Create;
    destructor Destroy;
    procedure Pulse;
  end;

  var
   GamepadManager: TGamepadManager;
{$ifdef windows}
   XInputGetState: function ( dwUserIndex: DWORD; var T_XINPUT_STATE): DWORD; stdcall = nil;
   XInputSetState: function ( dwUserIndex: DWORD; var Vibration: T_XINPUT_VIBRATION): DWORD; stdcall = nil;
   XInputGetCapabilities: function ( dwUserIndex: DWORD; dwFlags: DWORD; var Capabilities: T_XINPUT_CAPABILITIES): DWORD; stdcall = nil;
   XInputEnable: procedure (enable: BOOL); stdcall = nil;
{$endif}
