#ifndef CONTENT_BROWSER_GAMEPAD_RAW_INPUT_DATA_FETCHER_WIN_H_
#define CONTENT_BROWSER_GAMEPAD_RAW_INPUT_DATA_FETCHER_WIN_H_
#include "build/build_config.h"
#include <stdlib.h>
#include <Unknwn.h>
#include <WinDef.h>
#include <windows.h>
#include <hidsdi.h>
#include <map>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/scoped_native_library.h"
#include "base/win/message_window.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
namespace content {
struct RawGamepadAxis {
  HIDP_VALUE_CAPS caps;
  float value;
  bool active;
};
struct RawGamepadInfo {
  HANDLE handle;
  scoped_ptr<uint8[]> ppd_buffer;
  PHIDP_PREPARSED_DATA preparsed_data;
  uint32_t report_id;
  uint32_t vendor_id;
  uint32_t product_id;
  wchar_t id[blink::WebGamepad::idLengthCap];
  uint32_t buttons_length;
  bool buttons[blink::WebGamepad::buttonsLengthCap];
  uint32_t axes_length;
  RawGamepadAxis axes[blink::WebGamepad::axesLengthCap];
};
class RawInputDataFetcher
    : public base::SupportsWeakPtr<RawInputDataFetcher>,
      public base::MessageLoop::DestructionObserver {
 public:
  explicit RawInputDataFetcher();
  ~RawInputDataFetcher();
  
  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
  bool Available() { return rawinput_available_; }
  void StartMonitor();
  void StopMonitor();
  std::vector<RawGamepadInfo*> EnumerateDevices();
  RawGamepadInfo* GetGamepadInfo(HANDLE handle);
 private:
  RawGamepadInfo* ParseGamepadInfo(HANDLE hDevice);
  void UpdateGamepad(RAWINPUT* input, RawGamepadInfo* gamepad_info);
  
  LRESULT OnInput(HRAWINPUT input_handle);
  
  bool HandleMessage(UINT message,
                     WPARAM wparam,
                     LPARAM lparam,
                     LRESULT* result);
  RAWINPUTDEVICE* GetRawInputDevices(DWORD flags);
  void ClearControllers();
  
  typedef NTSTATUS (__stdcall *HidPGetCapsFunc)(
      PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
  typedef NTSTATUS (__stdcall *HidPGetButtonCapsFunc)(
      HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps,
      PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
  typedef NTSTATUS (__stdcall *HidPGetValueCapsFunc)(
      HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps,
      PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
  typedef NTSTATUS(__stdcall* HidPGetUsagesExFunc)(
      HIDP_REPORT_TYPE ReportType,
      USHORT LinkCollection,
      PUSAGE_AND_PAGE ButtonList,
      ULONG* UsageLength,
      PHIDP_PREPARSED_DATA PreparsedData,
      PCHAR Report,
      ULONG ReportLength);
  typedef NTSTATUS (__stdcall *HidPGetUsageValueFunc)(
      HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
      USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
      PCHAR Report, ULONG ReportLength);
  typedef NTSTATUS (__stdcall *HidPGetScaledUsageValueFunc)(
      HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
      USAGE Usage, PLONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
      PCHAR Report, ULONG ReportLength);
  typedef BOOLEAN (__stdcall *HidDGetStringFunc)(
      HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
  
  
  bool GetHidDllFunctions();
  base::ScopedNativeLibrary hid_dll_;
  scoped_ptr<base::win::MessageWindow> window_;
  bool rawinput_available_;
  bool filter_xinput_;
  bool events_monitored_;
  std::map<HANDLE, RawGamepadInfo*> controllers_;
  
  
  HidPGetCapsFunc hidp_get_caps_;
  HidPGetButtonCapsFunc hidp_get_button_caps_;
  HidPGetValueCapsFunc hidp_get_value_caps_;
  HidPGetUsagesExFunc hidp_get_usages_ex_;
  HidPGetUsageValueFunc hidp_get_usage_value_;
  HidPGetScaledUsageValueFunc hidp_get_scaled_usage_value_;
  HidDGetStringFunc hidd_get_product_string_;
  DISALLOW_COPY_AND_ASSIGN(RawInputDataFetcher);
};
}  
#endif