#include "AVReceiverDevice.h"
#include "GlobalDefine.h"
#include "ProtocolDefs.h"
#include <QDataStream>


/**
  Command syntax

 @ SUBUNIT : FUNCNAME = Parameter [CR/LF]
[1] [2] [3] [4] [5] [6] [7]
[1] Start Delimiter (@) : The beginning of a command
[2] Sub Unit Name : Indicating whether the command is for System, any zones or
any internal input sources as iPod, Tuner, Sirius, and
Rhapsody etc
[3] Command Delimiter (:) : Sub Unit Name and Function name are separated by this
delimiter
[4] Function Name : Specifying actual operations, some of them are abbreviated
[5] Parameter Delimiter (=) : Separating the Function Name and its Parameter (Value)
[6] Parameter : Showing a parameter value of the command
[7] End Delimiter : The end of a command, Carriage
*/

CAVReceiverDevice::CAVReceiverDevice()
{
    mReceiverSocket = new QTcpSocket;
    mDisconnectTimer = new QTimer;
    mStateRequestTimer = new QTimer;
//    mSyncDelayTimer = new QTimer;

    mDisconnectTimer->setSingleShot(true);
    mDisconnectTimer->stop();

    mStateRequestTimer->setSingleShot(true);
    mStateRequestTimer->setInterval(RECEIVER_STATE_UPDATE_TIMEOUT);

//    mSyncDelayTimer->setSingleShot(true);
//    mSyncDelayTimer->setInterval(500);


    connect(mDisconnectTimer,SIGNAL(timeout()),this,SLOT(DisconnectTimerExpired()));

    connect(mReceiverSocket,SIGNAL(connected()),this,SLOT(SocketConnected()));
    connect(mReceiverSocket,SIGNAL(disconnected()),this,SLOT(SocketDisconnected()));
    connect(mReceiverSocket,SIGNAL(readyRead()),this,SLOT(SocketRX()));

    connect(mStateRequestTimer,SIGNAL(timeout()),this,SLOT(StateRequestTimerExpired()));

//    connect(mSyncDelayTimer,&QTimer::timeout,this,&CAVReceiverDevice::SyncTimerExpired);
}


CAVReceiverDevice::~CAVReceiverDevice()
{
    mReceiverSocket->disconnectFromHost();
    mReceiverSocket->waitForDisconnected(100);

    delete mReceiverSocket;
    delete mDisconnectTimer;
    delete mStateRequestTimer;
  //  delete mSyncDelayTimer;
}

int CAVReceiverDevice::Start()
{
    mStateRequestTimer->start();
    return RET_OK;
}

int CAVReceiverDevice::ConnectToReceiver()
{
    if(mReceiverSocket->state() != QAbstractSocket::ConnectedState)
    {
        mReceiverSocket->connectToHost("192.168.50.101",50000);
    }

    return RET_OK;
}

int CAVReceiverDevice::DisconnectReceiver()
{
    if(mReceiverSocket->state() != QAbstractSocket::ConnectedState)
        return RET_ERROR;

    mReceiverSocket->disconnectFromHost();
    return RET_OK;
}

int CAVReceiverDevice::AnalyseRxData(QByteArray data)
{
    QString Data(data);
    if(data == "\r\n")
    {
       // qDebug("AV Receiver: Heartbeat received");
        return RET_OK;
    }

    QStringList Commands = Data.split("\r\n",QString::SkipEmptyParts);


    for(int i = 0; i<Commands.size();i++)
    {
        QString Cmd = Commands.at(i);
        Cmd.remove("@");
        QString SubUnit = Cmd.left(Cmd.indexOf(QChar(':')));
        Cmd.remove(SubUnit + ":");
        QString Function = Cmd.left(Cmd.indexOf(QChar('=')));
        Cmd.remove(Function + "=");
        QString Param = Cmd.remove("\r\n");

        UpdateReceiverStateParam(SubUnit,Function,Param);

   //     qDebug("Received SubUnit:[%s], Function:[%s], Param:[%s]",qPrintable(SubUnit),qPrintable(Function),qPrintable(Param));

    }



    return RET_OK;
}

int CAVReceiverDevice::UpdateReceiverStateParam(QString SubUnit, QString Fcn, QString Param)
{
    static bool AllValid = false;
    CAvReceiverMainStatus *UnitStatus = 0;
    if(SubUnit == "MAIN")
    {
        UnitStatus = &mReceiverStatus;
    }
    else if(SubUnit == "ZONE2")
    {
        UnitStatus = &mZone2Status;
    }

    if(UnitStatus != 0)
    {
        if(Fcn == "PWR")
        {
            if(Param == "On")
            {
                UnitStatus->mMainPwrStatus = true;
            }
            else
                UnitStatus->mMainPwrStatus = false;
        }
        if(Fcn == "SLEEP")
        {
            if(Param == "On")
            {
                UnitStatus->mMainSleepStatus = true;
            }
            else
            {
                UnitStatus->mMainSleepStatus = false;
            }
        }
        else if(Fcn == "VOL")
        {
            bool OK;
            float Vol = Param.toFloat(&OK);
            if(OK)
            {
                UnitStatus->mMainVolume = Vol;
            }
            else
            {
                UnitStatus->mMainPwrStatus = 0xDEADBEEF;
            }
        }
        else if(Fcn == "MUTE")
        {
            if(Param == "On")
            {
                UnitStatus->mIsMute = true;
            }
            else
            {
                UnitStatus->mIsMute = false;
            }
        }
        else if (Fcn == "INP")
        {
            UnitStatus->mInput = Param;
        }
        else if (Fcn == "SOUNDPRG")
        {
            UnitStatus->mProgram = Param;
        }
    }
    return RET_OK;
}

int CAVReceiverDevice::SendReceiverCommand(QString Command)
{
    //Make sure the escape sequence is correct.
//    Command.remove("\r");
//    Command.remove("\n");
//    Command.append("\r\n");


    if(mReceiverSocket->state() == QAbstractSocket::ConnectedState)
    {
        mReceiverSocket->write(Command.toUtf8());
//        qDebug("Sent command to receiver : %s",qPrintable(mPendingCommand));
    }
    else
    {
        mPendingCommand = Command;
        ConnectToReceiver();
    }
    return RET_OK;
}


void CAVReceiverDevice::SocketConnected()
{
    if(mPendingCommand.isEmpty() == false)
    {
        QByteArray data =mPendingCommand.toLatin1();
        int ret = mReceiverSocket->write(data);
//        qDebug("Sent command to receiver : %s",qPrintable(mPendingCommand));
        mPendingCommand.clear();
        return;
    }

   qDebug("Receiver Connected");
}

void CAVReceiverDevice::SocketDisconnected()
{
//    qDebug("Receiver Disconnected");
}

void CAVReceiverDevice::SocketRX()
{
 //   qDebug("Receiver response:");
    QByteArray Data = mReceiverSocket->readAll();
//    qDebug("%s",qPrintable(Data));
    AnalyseRxData(Data);

}

void CAVReceiverDevice::DisconnectTimerExpired()
{
    DisconnectReceiver();
    mDisconnectTimer->stop();
}

int CAVReceiverDevice::DisconnectReceiverDelayed(int Delay)
{
    if(Delay > 5000)
    {
        Delay = 5000;
    }

    mDisconnectTimer->start(Delay);

    return RET_OK;
}

void CAVReceiverDevice::StateRequestTimerExpired()
{
    if(mReceiverSocket->state() != QAbstractSocket::ConnectedState)
    {
        SendReceiverCommand("@MAIN:BASIC=?\r\n@ZONE2:BASIC=?\r\n");
        mStateRequestTimer->start(RECEIVER_STATE_UPDATE_TIMEOUT);
        DisconnectReceiverDelayed(1000);
    }
    else
    {
        //A transaction is going on... wait and retry later
        mStateRequestTimer->start(500);
    }
}

////// Network Interface Implementation

int CAVReceiverDevice::SetZone2(bool OnOff)
{
    QString Cmd = "@ZONE2:PWR=";
    if(OnOff)
    {
        Cmd += "On\r\n";
    }
    else
        Cmd += "Standby\r\n";

    SendReceiverCommand(Cmd);

    DisconnectReceiverDelayed();
    return RET_OK;
}

int CAVReceiverDevice::SetMainZone(bool OnOff)
{
    QString Cmd = "@MAIN:PWR=";
    if(OnOff)
    {
        Cmd += "On\r\n";
    }
    else
        Cmd += "Standby\r\n";

    SendReceiverCommand(Cmd);
    DisconnectReceiverDelayed();
    return RET_OK;
}
int CAVReceiverDevice::SetSpeakers(int SpeakerA, int SpeakerB)
{
    //First, speaker A.
    if(SpeakerA != RECEIVER_DONT_CHANGE_SPK)
    {
        QString Cmd = "@MAIN:SPEAKERA=";
        if(SpeakerA == RECEIVER_SET_SPK_ON)
        {
            Cmd += "On\r\n";
        }
        else if(SpeakerA == RECEIVER_SET_SPK_OFF)
        {
            Cmd += "Off\r\n";
        }
        else if(SpeakerA == RECEVIVER_TOGGLE_SPK)
        {
//            if(mReceiverStatus.mSpeakerAState == true)
//            {
//                Cmd += "Off";
//            }
//            else
//            {
//                 Cmd += "On";
//            }
        }
        else
        {
            qDebug("Got a SetSpeakers() command with invalid parameter for Speaker A.  Weirds stuff!!");
        }

        SendReceiverCommand(Cmd);
    }

    //Then, speaker B.
    if(SpeakerB != RECEIVER_DONT_CHANGE_SPK)
    {
        QString Cmd = "@MAIN:SPEAKERB=";
        if(SpeakerB == RECEIVER_SET_SPK_ON)
        {
            Cmd += "On";
        }
        else if(SpeakerB == RECEIVER_SET_SPK_OFF)
        {
            Cmd += "Off";
        }
        else if(SpeakerB == RECEVIVER_TOGGLE_SPK)
        {
//            if(mReceiverStatus.mSpeakerAState == true)
//            {
//                Cmd += "Off";
//            }
//            else
//            {
//                 Cmd += "On";
//            }
        }
        else
        {
            qDebug("Got a SetSpeakers() command with invalid parameter for Speaker B.  Weirds stuff!!");
        }

        SendReceiverCommand(Cmd);
    }
    DisconnectReceiverDelayed();

    return RET_OK;
}

int CAVReceiverDevice::SendRawCommand(QString Cmd)
{
    return SendReceiverCommand(Cmd);
    DisconnectReceiverDelayed(2000);

}

QByteArray CAVReceiverDevice::GetReceiverStatus()
{
    QByteArray StatusArray;
    QDataStream Strm(&StatusArray,QIODevice::WriteOnly | QIODevice::Unbuffered);
    Strm.device()->seek(0);

    Strm << mReceiverStatus
         << mZone2Status ;

    if(mReceiverStatus.mSyncZonesVolumes == true &&
       (    (mReceiverStatus.mMainVolume != mLastMainZoneVolume) ||
            (mReceiverStatus.mMainVolume != mZone2Status.mMainVolume)))
    {
        SetZone2Volume(mReceiverStatus.mMainVolume);
    }

    mLastMainZoneVolume = mReceiverStatus.mMainVolume;
    return StatusArray;
}

QByteArray CAVReceiverDevice::GetReceiverStatusForConsole()
{
    QByteArray StatusArray;

    StatusArray = mReceiverStatus.ToConsoleStatusByteArray();
    StatusArray.append(mZone2Status.ToConsoleStatusByteArray());

    if(mReceiverStatus.mSyncZonesVolumes == true &&
       (    (mReceiverStatus.mMainVolume != mLastMainZoneVolume) ||
            (mReceiverStatus.mMainVolume != mZone2Status.mMainVolume)))
    {
        SetZone2Volume(mReceiverStatus.mMainVolume);
    }

    mLastMainZoneVolume = mReceiverStatus.mMainVolume;
    return StatusArray;
}

int CAVReceiverDevice::SelectScene(char Zone, char Scene)
{
    QString Cmd;
    if(Zone == AV_RECEIVER_MAIN_ZONE)
    {
        Cmd = QString("@MAIN:SCENE=Scene %1\r\n").arg((int)Scene,1);

    }
    else if(Zone == AV_RECEIVER_ZONE_2)
    {
         Cmd = QString("@ZONE2:SCENE=Scene %1\r\n").arg((int)Scene,1);
    }
    else
    {
        return RET_ERROR;
    }

    SendReceiverCommand(Cmd);
    DisconnectReceiverDelayed(2000);

    return RET_OK;
}

int CAVReceiverDevice::SetMainVolume(float Volume)
{
    QString Cmd;
    Cmd = QString("@MAIN:VOL=%1\r\n").arg(Volume,1,'f',1);

 //   qDebug("%s",qPrintable(Cmd));

    SendReceiverCommand(Cmd);
  //  DisconnectReceiverDelayed();

    if(mReceiverStatus.mSyncZonesVolumes == true)
    {
        SetZone2Volume(Volume);
    }

    return RET_OK;
}

int CAVReceiverDevice::SetZone2Volume(float Volume)
{
    QString Cmd;
    Cmd = QString("@ZONE2:VOL=%1\r\n").arg(Volume,1,'f',1);

    SendReceiverCommand(Cmd);
 //   DisconnectReceiverDelayed();
    return RET_OK;
}

int CAVReceiverDevice::SetZone2Input(QString InputString)
{
    QString Cmd;
    Cmd = QString("@ZONE2:INP=%1\r\n").arg(InputString);

    SendReceiverCommand(Cmd);

    return RET_OK;
}

int CAVReceiverDevice::SetSyncZ2withZ1(bool Sync)
{
    mReceiverStatus.mSyncZonesVolumes = Sync;
    if(Sync == true)
    {
        SetZone2Volume(mReceiverStatus.mMainVolume);
    }
  //  qDebug("Sync Z2 with Z1: %d",Sync);
    return RET_OK;
}

int CAVReceiverDevice::IncrementMainVolume(bool Increment)
{

    float NewVolume = mReceiverStatus.mMainVolume;

    if(Increment)
    {
        if(NewVolume >= RECEIVER_MAXIMUM_VOLUME)
        {
            return RET_OK;
        }
        NewVolume += RECEIVER_VOLUME_INCREMENT_STEP;
        SetMainVolume(NewVolume);
    }
    else
    {
        if((NewVolume - RECEIVER_VOLUME_INCREMENT_STEP) < RECEIVER_MINIMUM_VOLUME)
        {
            return RET_OK;
        }
        NewVolume -= RECEIVER_VOLUME_INCREMENT_STEP;
        SetMainVolume(NewVolume);

    }
    mReceiverStatus.mMainVolume = NewVolume;
    return RET_OK;

}
int CAVReceiverDevice::IncrementZ2Volume(bool Increment)
{
    float NewVolume = mZone2Status.mMainVolume;

    if(Increment)
    {
        if(NewVolume >= RECEIVER_MAXIMUM_VOLUME)
        {
            return RET_OK;
        }
        NewVolume += RECEIVER_VOLUME_INCREMENT_STEP;
        SetZone2Volume(NewVolume);
     }
    else
    {
        if((NewVolume - RECEIVER_VOLUME_INCREMENT_STEP) < RECEIVER_MINIMUM_VOLUME)
        {
            return RET_OK;
        }
        NewVolume -= RECEIVER_VOLUME_INCREMENT_STEP;
        SetZone2Volume(NewVolume);

    }
    mZone2Status.mMainVolume = NewVolume;
    return RET_OK;
}
