// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// 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.

#pragma once

#include "soc/soc_caps.h"
#if SOC_USB_OTG_SUPPORTED

#include "USBHID.h"
#if CONFIG_TINYUSB_HID_ENABLED

/// Standard Gamepad Buttons Naming from Linux input event codes
/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
#define BUTTON_A      0
#define BUTTON_B      1
#define BUTTON_C      2
#define BUTTON_X      3
#define BUTTON_Y      4
#define BUTTON_Z      5
#define BUTTON_TL     6
#define BUTTON_TR     7
#define BUTTON_TL2    8
#define BUTTON_TR2    9
#define BUTTON_SELECT 10
#define BUTTON_START  11
#define BUTTON_MODE   12
#define BUTTON_THUMBL 13
#define BUTTON_THUMBR 14

#define BUTTON_SOUTH BUTTON_A
#define BUTTON_EAST  BUTTON_B
#define BUTTON_NORTH BUTTON_X
#define BUTTON_WEST  BUTTON_Y

/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
#define HAT_CENTER     0
#define HAT_UP         1
#define HAT_UP_RIGHT   2
#define HAT_RIGHT      3
#define HAT_DOWN_RIGHT 4
#define HAT_DOWN       5
#define HAT_DOWN_LEFT  6
#define HAT_LEFT       7
#define HAT_UP_LEFT    8

class USBHIDGamepad : public USBHIDDevice {
private:
  USBHID hid;
  int8_t _x;          ///< Delta x  movement of left analog-stick
  int8_t _y;          ///< Delta y  movement of left analog-stick
  int8_t _z;          ///< Delta z  movement of right analog-joystick
  int8_t _rz;         ///< Delta Rz movement of right analog-joystick
  int8_t _rx;         ///< Delta Rx movement of analog left trigger
  int8_t _ry;         ///< Delta Ry movement of analog right trigger
  uint8_t _hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
  uint32_t _buttons;  ///< Buttons mask for currently pressed buttons
  bool write();

public:
  USBHIDGamepad(void);
  void begin(void);
  void end(void);

  bool leftStick(int8_t x, int8_t y);
  bool rightStick(int8_t z, int8_t rz);

  bool leftTrigger(int8_t rx);
  bool rightTrigger(int8_t ry);

  bool hat(uint8_t hat);

  bool pressButton(uint8_t button);
  bool releaseButton(uint8_t button);

  bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);

  // internal use
  uint16_t _onGetDescriptor(uint8_t *buffer);
};

#endif /* CONFIG_TINYUSB_HID_ENABLED */
#endif /* SOC_USB_OTG_SUPPORTED */
