#include "observerclientmodel.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWebFrame>

QString
ws2qs(const std::wstring& str)
{
    return (QString((const QChar*)str.c_str(), str.length()));
}

// Convert a QString to a wstring
std::wstring
qs2ws(const QString& str)
{
    return (std::wstring((wchar_t*)str.unicode(), str.length()));
}


TObserverClientModel::TObserverClientModel(QObject *parent)
  : QObject(parent)
  , MapType(0)
  , Connected(false)
{
}


void TObserverClientModel::Start(std::string address, std::string port)
{
    if (!Connected)
    {
        ClientSocket = boost::shared_ptr<TClientSocket>(new TClientSocket(IoService));

        ClientSocket->ReceiveMapSignal.connect(boost::bind(&TObserverClientModel::OnReceiveMapUpdate, this, _1));

        ClientSocket->ReceiveAlarmMapSignal.connect(boost::bind(&TObserverClientModel::OnReceiveAlarmMapUpdate, this, _1));

        ClientSocket->ReceiveForceCloseSignal.connect(boost::bind(&TObserverClientModel::OnSocketClosed, this));

        ClientSocket->ReceiveMessageSignal.connect(boost::bind(&TObserverClientModel::OnReceiveChatMessage, this, _1, _2));

        ClientSocket->ReceiveAutorizationSentSignal.connect(boost::bind(&TObserverClientModel::OnAutorizationSent, this));

        ClientSocket->Open(address, port);

        IoServiceThread = boost::thread(boost::bind(&TObserverClientModel::DoRunIoService, this));

        Timer.TimerSignal.connect(boost::bind(&TObserverClientModel::OnUpdateMapTimer, this));

        Timer.start(1000);

        Connected = true;
    }
}

void TObserverClientModel::OnAutorizationSent()
{

    RestartHeartbeatTimer();
    RestartMapHeartbeatTimer();

}

void TObserverClientModel::RestartHeartbeatTimer()
{
    HeartbeatTimer = boost::shared_ptr<boost::asio::deadline_timer>(new boost::asio::deadline_timer(IoService, boost::posix_time::seconds(3)));

    HeartbeatTimer->async_wait(boost::bind(&TObserverClientModel::OnHeartbeat, this, boost::asio::placeholders::error));

}

void TObserverClientModel::RestartMapHeartbeatTimer()
{
    MapHeartbeatTimer = boost::shared_ptr<boost::asio::deadline_timer>(new boost::asio::deadline_timer(IoService, boost::posix_time::seconds(3)));

    MapHeartbeatTimer->async_wait(boost::bind(&TObserverClientModel::OnMapHeartbeat, this, boost::asio::placeholders::error));

}


void TObserverClientModel::Finish()
{
    if (Connected)
    {
        Connected = false;

        Timer.stop();
        HeartbeatTimer->cancel();
        MapHeartbeatTimer->cancel();

        ClientSocket->CloseImmediate();
    }



}

void TObserverClientModel::OnSocketClosed()
{
    //ClientSocket->BlockCloseOnError = true;
    //ClientSocket->CloseImmediate();
    ClientSocket = boost::shared_ptr<TClientSocket>();
}

void TObserverClientModel::OnUpdateMapTimer()
{
    UpdatingMapMutex.lock();

    MainWindowPtr->GetUi()->webView->page()->mainFrame()->evaluateJavaScript("Clear();");

    if (MapType == 0)
    {


        for (std::vector<TUserInfo>::iterator i = UserInfoArr.begin(); i != UserInfoArr.end(); ++i)
        {
            QString posX = QString::number( i->PosX );
            QString posY = QString::number( i->PosY );
            QString mapState = QString::number(i->MapState);

            if (i->PosX != 0.f  && i->PosY != 0.f)
            {
                MainWindowPtr->GetUi()->webView->page()->mainFrame()->evaluateJavaScript("AddMarker("+posX+", "+posY+", "+ mapState + ");");
            }
        }
    }
    else
    {
        MainWindowPtr->GetUi()->PlayerListWidget->clear();

        for (std::vector<TUserInfo>::iterator i = AlarmUserInfoArr.begin(); i != AlarmUserInfoArr.end(); ++i)
        {
            QString posX = QString::number( i->PosX );
            QString posY = QString::number( i->PosY );
            QString mapState = QString::number(i->MapState);



            std::wstring Uik = L"УИК №";
            std::wstring StateHeader = L"Состояние: ";

            QString lastName = QString::fromUtf8(i->LastName.c_str());
            QString firstName = QString::fromUtf8(i->FirstName.c_str());
            QString middleName = QString::fromUtf8(i->MiddleName.c_str());

            QString text = ws2qs(Uik);
            text = text + QString::number(i->Uik)+"\\n";
            text = text + lastName;
            text = text +"\\n" + firstName;
            text = text + "\\n"+middleName;
            text = text + "\\n"+QString::fromUtf8(i->PhoneNumber.c_str());
            text = text + "\\n";
            text = text +ws2qs(StateHeader);

            std::wstring State;

            if (i->MapState == 2)
            {
                State = L"Тревога";
            }
            else if (i->MapState == 3)
            {
                State = L"Тревога - Удаление с УИК";
            }
            else if (i->MapState == 4)
            {
                State = L"Тревога - Вброс";
            }
            else if (i->MapState == 5)
            {
                State = L"Тревога - Карусель";
            }
            else if (i->MapState == 6)
            {
                State = L"Тревога - Нападение";
            }

            text += ws2qs(State);

            if (i->PosX != 0.f  && i->PosY != 0.f)
            {
                MainWindowPtr->GetUi()->webView->page()->mainFrame()->evaluateJavaScript("AddMarkerWithPopup("+posX+", "+posY+", "+ mapState + ", \"" +text+ "\");");
            }
            MainWindowPtr->GetUi()->PlayerListWidget->addItem(QString("LastName: "+lastName + " FirstName: " + firstName+" MiddleName: "+middleName));

        }
    }

    Timer.start(1000);

    UpdatingMapMutex.unlock();
}


void TObserverClientModel::DoRunIoService()
{
    IoService.run();

    ReceiveCloseSignal();
    ReceiveCloseSignal.disconnect_all_slots();
}

void TObserverClientModel::OnConnectButtonPressed()
{
    std::string address(MainWindowPtr->GetUi()->AddressField->text().toAscii());
    std::string port(MainWindowPtr->GetUi()->PortField->text().toAscii());

    Start(address, port);
}

void TObserverClientModel::OnUpdateInfoButtonPressed()
{

    std::string lastName(MainWindowPtr->GetUi()->LastNameField->text().toUtf8());
    std::string firstName(MainWindowPtr->GetUi()->FirstNameField->text().toUtf8());
    std::string middleName(MainWindowPtr->GetUi()->MiddleNameField->text().toUtf8());

    std::string phoneNumber(MainWindowPtr->GetUi()->PhoneNumberField->text().toUtf8());

    int uik = MainWindowPtr->GetUi()->UikSpinBox->value();

    int status = MainWindowPtr->GetUi()->StatusComboBox->currentIndex();

    float posX = MainWindowPtr->GetUi()->PosXSpinBox->value();
    float posY = MainWindowPtr->GetUi()->PosYSpinBox->value();

    int mapState = MainWindowPtr->GetUi()->MapStateComboBox->currentIndex();
    if (status == 1)
    {
        mapState = 0;
    }

    ClientSocket->UserInfo.LastName = lastName;
    ClientSocket->UserInfo.FirstName = firstName;
    ClientSocket->UserInfo.MiddleName = middleName;
    ClientSocket->UserInfo.PhoneNumber = phoneNumber;
    ClientSocket->UserInfo.Uik = uik;
    ClientSocket->UserInfo.Status = status;
    ClientSocket->UserInfo.MapState = mapState;

    ClientSocket->UserInfo.PosX = posX;
    ClientSocket->UserInfo.PosY = posY;

    ClientSocket->SendUserinfoUpdateThreaded();

}


void TObserverClientModel::OnHeartbeat(const boost::system::error_code& e)
{
    if (e)
    {
        return;
    }

    float posX = MainWindowPtr->GetUi()->PosXSpinBox->value();
    float posY = MainWindowPtr->GetUi()->PosYSpinBox->value();

    int uik = MainWindowPtr->GetUi()->UikSpinBox->value();
    int status = MainWindowPtr->GetUi()->StatusComboBox->currentIndex();
    int mapState = MainWindowPtr->GetUi()->MapStateComboBox->currentIndex() + 1;
    if (status == 1)
    {
        mapState = 0;
    }

    ClientSocket->UserInfo.Uik = uik;
    ClientSocket->UserInfo.MapState = mapState;

    ClientSocket->UserInfo.PosX = posX;
    ClientSocket->UserInfo.PosY = posY;

    ClientSocket->SendHeartbeatThreaded();

    RestartHeartbeatTimer();
}

void TObserverClientModel::OnMapHeartbeat(const boost::system::error_code& e)
{
    if (e)
    {
        return;
    }

    if (MapType == 0)
    {
        ClientSocket->SendMapQueryThreaded();
    }
    else
    {
        ClientSocket->SendAlarmMapQueryThreaded();
    }

    RestartMapHeartbeatTimer();
}

void TObserverClientModel::OnReceiveMapUpdate(std::vector<TUserInfo> userInfoArr)
{

    UpdatingMapMutex.lock();

    UserInfoArr = userInfoArr;

    UpdatingMapMutex.unlock();

}

void TObserverClientModel::OnReceiveAlarmMapUpdate(std::vector<TUserInfo> userInfoArr)
{
    UpdatingMapMutex.lock();

    AlarmUserInfoArr = userInfoArr;

    UpdatingMapMutex.unlock();
}


void TObserverClientModel::OnChangeMapTypeButtonPressed()
{
    MapType = MainWindowPtr->GetUi()->MapTypeComboBox->currentIndex();

    if (MapType == 0)
    {
        ClientSocket->SendMapQueryThreaded();
    }
    else
    {
        ClientSocket->SendAlarmMapQueryThreaded();
    }
}

void TObserverClientModel::OnChatSendClick()
{
    QString msg = MainWindowPtr->GetUi()->ChatTextLine->text();

    ClientSocket->SendMessageThreaded(std::string(msg.toUtf8()));
}

void TObserverClientModel::OnReceiveChatMessage(TUserInfo userInfo, std::string msg)
{
    QString qmsg;

    qmsg += QString::fromUtf8(userInfo.LastName.c_str()) + " ";
    qmsg += QString::fromUtf8(userInfo.FirstName.c_str()) + " ";
    qmsg += QString::fromUtf8(userInfo.MiddleName.c_str()) + " ";
    qmsg += QString::fromUtf8(userInfo.PhoneNumber.c_str()) + " ";
    qmsg += QString(ws2qs(L"УИК №")) + QString::number(userInfo.Uik) + ": ";


    qmsg += QString::fromUtf8(msg.c_str()) + "\n";


    MainWindowPtr->GetUi()->ChatList->insertPlainText(qmsg);

}


void TObserverClientModel::OnSendAlarmClick()
{
    ClientSocket->UserInfo.MapState = 2;

    QString msg = ws2qs(L"Тревога!");

    ClientSocket->SendMessageThreaded(std::string(msg.toUtf8()));
}


void TObserverClientModel::OnKickPlayerClick()
{
    QString lastName = MainWindowPtr->GetUi()->LastNameKickEdit->text();
    QString firstName = MainWindowPtr->GetUi()->FirstNameKickEdit->text();
    QString middleName = MainWindowPtr->GetUi()->MiddleNameKickEdit->text();

    ClientSocket->SendKickPlayerThreaded(std::string(lastName.toUtf8()), std::string(firstName.toUtf8()), std::string(middleName.toUtf8()));

}


void TObserverClientModel::OnSelectPlayerClick()
{
    int i = MainWindowPtr->GetUi()->PlayerListWidget->currentRow();

    QString lastName = QString::fromUtf8(AlarmUserInfoArr[i].LastName.c_str());
    QString firstName = QString::fromUtf8(AlarmUserInfoArr[i].FirstName.c_str());
    QString middleName = QString::fromUtf8(AlarmUserInfoArr[i].MiddleName.c_str());

    MainWindowPtr->GetUi()->LastNameKickEdit->setText(lastName);
    MainWindowPtr->GetUi()->FirstNameKickEdit->setText(firstName);
    MainWindowPtr->GetUi()->MiddleNameKickEdit->setText(middleName);
}
