// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | bytran@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// The MIT License (MIT)
// Copyright (c) 2016 Dzianis Pliutau
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



// The class is used to control bytran remotely i.e. over Bluetooth or RS-232 and retrieve the calculation results for possible integration with other systems
#ifndef REMOTECONTROL_H
#define REMOTECONTROL_H

#include <QObject>
#include <QString>
#include <QByteArray>
#include <QDataStream>
#include "wavelength.h"
#include "params.h"
#include "sensors.h"
#include "instrumentfunction.h"
#include "atmosphere.h"
#include "hitranonlinedownloader.h"
#include "yaxis.h"
#include "serialport.h"
#include "bluetoothspp.h"
#include "websockets.h"
#include "resultssaver.h"

class RemoteControl : public QObject
{
    Q_OBJECT

public:

    explicit RemoteControl(QObject *parent = nullptr);

    // Methods to get and set the communication mode
    int getCommunicationMode();
    void setCommunicationMode(int newCommunicationMode);

    // Method gets and sets the broadcast manual input variable
    void setBroadcastManualInput(bool broadcastManualInput);
    bool getBroadcastManualInput();

    // Method to broadcast manual input values
    void broadcastCommand(QString command, int index);

    // Method to determine if any device is connected (over Bluetooth, WiFi/Ethernet, or the serial port)
    bool getRemoteDeviceIsConnected();

    // Method to send data to a remote device using the currently used connection method
    void sendMessage(const QString &message);
    void sendMessage(const QByteArray &message);

    // Methods to get the objects containing the variables to modify and transfer the value of
    void setWavelength(Wavelength *wavelengthIn);
    void setParams(Params *paramsIn);
    void setSensors(Sensors *sensorsIn);
    void setInstrumentFunction(InstrumentFunction *instrFunctIn);
    void setAtmModel(Atmosphere *atmIn);
    void setHitranOnlineDownloader(HitranOnlineDownloader *hitranIn);
    void setYAxis(YAxis *yaxisIn);

    // Method to obtain a reference to the results saver object to be able to return the results of the calculations
    void setResultsSaver(ResultsSaver *inResultsSaver);

    // Method to get access to the serial port data object
    SerialPort *getSerialPort();

    // Method to get access to the bluetooth data object
    BluetoothSpp *getBluetooth();

    // Method to get a reference to the WebSockets object
    WebSockets *getWebSockets();

private:

    // Setting the value according to the command and the supplied values
    void setValueStr(QString command, QString value, int index);
    void setValueBin(QString command, QByteArray value, int index);

    // Returning the current value for a given command to the remote device
    QString getValueStr(QString command, int index, bool broadcastMode);
    QByteArray getValueBin(QString command, int index);

    // Methods to convert from byte array to Double and Int values (the byte array contains the Double and Int number representations)
    double fromByteArrayToDouble(QByteArray byteArr);
    int fromByteArrayToInt(QByteArray byteArr);
    quint8 fromByteArrayToUInt8(QByteArray byteArr);
    bool fromByteArrayToBoolean(QByteArray byteArr);

    // Methods to convert from regular data types to byte array representations to be transfered over the communication channel in binary form
    QByteArray fromDoubleToByteArray(double value);
    QByteArray fromIntToByteArray(int value);
    QByteArray fromBooleanToByteArray(bool value);

    // Method to convert to quint8 (and checking the range)
    quint8 toQuint8CheckRange(QString value, quint8 maxValue, quint8 prevValue, QString command, QString allowedRange);

signals:

    // Signal is emitted to run a calculation
    void calculate();

    // Signal is used to update the value in the dialogs if they have been changed through remote control commands
    void valuesUpdated();

    // Signal is called to assign values from the currently selected atmospheric model
    void applyCurrentAtmModel();

    // Signal is emitted after the calculations or when the magnification of the spectrum is needed in order to plot spectra
    void updateSpectra(bool updateScale, bool updateTotal);

    // Signal is emitted when the show total variable is changed
    void showTotalChanged(bool newShowTotal);
    // Signal is emitted when the show high resoltuion spectrum display variable is changed
    void showPlainTotalChanged(bool newShowPlainTotal);
    // Signal is emitted when the show instrument function spectrum display variable is changed
    void showInstrTotalChanged(bool newShowInstrTotal);

    // Signal is emitted to indicate that the next command may now start processing
    void ready();

public slots:

    // Method is used to append the newly received commands to the pending commands string and process all available complete commands
    void bufferAndProcessCommands(const QString &message);

    // Slot is used to set a parameter value based on the message received (the command and the value assigned)
    void processCommandString(const QString &message);

    // Slot to emit a ready message
    void emitReadyMessage();

    // Slot to set the BUSY variable
    void setReady();

private slots:

private:

    // String containing the incoming commands and data
    QString incomingString;

    // Variable indicates if the remote control is active and the means of communication (bluetooth vs. serial port) if so
    int communicationMode;  // 0 - Disabled, 1 - Bluetooth, 2 - Serial port, 3 - Wifi / Ethernet

    // Variable indicates if the manual input needs to be broadcast as well
    // If this option is selected, then the options selected in the phone will be broadcast through the active connection (buetooth or the serial port)
    bool broadcastManualInput;

    // Pointers to objects to get and modify the calculation and other variables
    Params *params;     // Object with the main calculation parameters
    Sensors *sensors;   // Object related to humidity, pressure and temperature sensors
    Atmosphere *atm;    // Object with the atmospehric model parameters
    Wavelength *wavelength;  // Object with the wavelength parameters
    InstrumentFunction *instrFunct;  // Object with the instrument function parameters
    HitranOnlineDownloader *hitran;    //  Object related to the downlaod of the HITRAN database and related tasks
    YAxis *yaxis;  // Vertical axis parameters

    // Object used to perform communication over the serial channel
    SerialPort *serial;

    // Object used to perform communication over bluetooth
    BluetoothSpp *bluetooth;

    // Object for communication over web sockets
    WebSockets *webSockets;

    // Results saver object to return calculation results to a remote device
    ResultsSaver *resultsSaver;

    // String with all the pending commands
    QString pendingCommands;

};

#endif // REMOTECONTROL_H
