/***
 * Warthog Robotics
 * University of Sao Paulo (USP) at Sao Carlos
 * http://www.warthog.sc.usp.br/
 *
 * This file is part of WRJoy project.
 *
 * 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 3 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/>.
 ***/

// Prevents multiple definitions
#ifndef WRJOY_JOYSTICK
#define WRJOY_JOYSTICK


// Includes WRJoy
#include <WRJoy/wrjoy.hh>


// Includes Qt library
#include <QtCore/QtCore>
#include <QtWidgets/QtWidgets>

// Includes SDL library
#include <SDL2/SDL.h>

// Includes GEARSystem
#include <GEARSystem/gearsystem.hh>


// Selects WRJoy namespace
using namespace WRJoy;


class WRJoy::Joystick : public QThread {
    Q_OBJECT

    public:
        enum AxisType {
            Standard = 0,
            PositiveOnly,
            StandardInverse,
            PositiveOnlyInverse
        };

    private:
        qint8 _team;
        qint8 _player;
        bool _kickEnabled;
        bool _chipKickEnabled;

        QString  _name;

        bool _hasGUI;
        QWidget* _widget;

        bool _isOpened;
        qint8 _sdlJoystickIndex;
        SDL_Joystick* _sdlJoystick;
        QMutex _sdlLock;

        GEARSystem::Controller* _controller;

        QMutex _runLock;
        bool   _keepRunning;

        double  _runSleepTime;
        qint16  _deadZoneStandardMaxZero;
        qint16  _deadZoneStandardMinOne;
        quint16 _deadZonePositiveOnlyMaxZero;
        quint16 _deadZonePositiveOnlyMinOne;

        QList<AxisType> _axesTypes;

        qint8 _moveXAnalogAxis;
        qint8 _moveYAnalogAxis;
        qint8 _turnClockwiseAnalogAxis;
        qint8 _turnCounterClockwiseAnalogAxis;

        qint8 _movePositiveXDigitalButton;
        qint8 _moveNegativeXDigitalButton;
        qint8 _movePositiveYDigitalButton;
        qint8 _moveNegativeYDigitalButton;
        qint8 _turnClockwiseDigitalButton;
        qint8 _turnCounterClockwiseDigitalButton;

        qint8 _runButton;
        qint8 _holdBallButton;

        qint8 _kickButton;
        qint8 _passButton;
        qint8 _chipKickButton;
        qint8 _chipPassButton;

        qint8 _playerDownButton;
        qint8 _playerUpButton;
        bool _lastPlayerDownButton;
        bool _lastPlayerUpButton;

        qint8 _kickOnTouchButton;
        qint8 _passOnTouchButton;
        qint8 _chipKickOnTouchButton;
        qint8 _chipPassOnTouchButton;

        double _speed;
        double _moveAnalogMaxSpeed;
        double _turnAnalogMaxSpeed;
        double _moveRunAnalogMaxSpeed;
        double _turnRunAnalogMaxSpeed;

        double _moveDigitalSpeed;
        double _turnDigitalSpeed;
        double _moveRunDigitalSpeed;
        double _turnRunDigitalSpeed;

        double _kickSpeed;
        double _passSpeed;
        double _chipKickSpeed;
        double _chipPassSpeed;


    public:
        Joystick(QString name, bool createGUI);
        ~Joystick();

    public:
        QString  name();
        QWidget* widget();

    private:
        void configureConnections();
        void initializeAxesConfiguration();
        void initializeButtonsConfiguration();

    public:
        void reset();
        void run();
        void stop();

    public:
        void open(qint8 sdlIndex);
        void close();
        bool isOpened();

    public:
        void   setSleepTime(double sleepTime);
        double sleepTime();
        void   setDeadZoneStandardMaxZero(qint16 maxZero);
        qint16 deadZoneStandardMaxZero();
        void   setDeadZoneStandardMinOne(qint16 minOne);
        qint16 deadZoneStandardMinOne();
        void   setDeadZonePositiveOnlyMaxZero(quint16 maxZero);
        quint16 deadZonePositiveOnlyMaxZero();
        void   setDeadZonePositiveOnlyMinOne(quint16 minOne);
        quint16 deadZonePositiveOnlyMinOne();
		void setTeam(quint8 team);
		void setPlayer(quint8 player);
        void setSpeed(double speed);
        void setKickEnable(bool state);
        void setKickChipEnable(bool state);

        bool getKickEnable();
        bool getChipKickEnable();
        double getMaxAnalogSpeed();

    signals:
        void reseted();
        void opened();
        void openFail(QString sdlError);
        void closed();
        void stateUpdated();

    public:
        QString  sdlJoystickName();
        qint8    sdlJoystickIndex();
        qint8    numberAxes();
        qint8    numberButtons();
        quint8   buttonState(quint8 button);
        double   axisState(quint8 axis);
        void     setAxisType(quint8 axis, AxisType type);
        AxisType axisType(quint8 axis);

    private:
        double conditionSignal(qint16 signal, AxisType axisType);

    signals:
        void setSpeedCommand(quint8 team, quint8 player, double xSpeed, double ySpeed, double thetaSpeed);
        void holdBallCommand(quint8 team, quint8 player, bool enable);
        void kickCommand(quint8 team, quint8 player, double speed);
        void chipKickCommand(quint8 team, quint8 player, double speed);
        void kickOnTouchCommand(quint8 team, quint8 player, bool enable, double speed);
        void chipKickOnTouchCommand(quint8 team, quint8 player, bool enable, double speed);

        void playerChanged(quint8 player);

    private slots:
        void processState();
        void executeSetSpeedCommand(quint8 team, quint8 player, double xSpeed, double ySpeed, double thetaSpeed);
        void executeHoldBallCommand(quint8 team, quint8 player, bool enable);
        void executeKickCommand(quint8 team, quint8 player, double speed);
        void executeChipKickCommand(quint8 team, quint8 player, double speed);
        void executeKickOnTouchCommand(quint8 team, quint8 player, bool enable, double speed);
        void executeChipKickOnTouchCommand(quint8 team, quint8 player, bool enable, double speed);
};


#endif
