#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)
{
}


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

    ClientSocket->Open(address, port);

    RestartHeartbeatTimer();
    RestartMapHeartbeatTimer();

    IoServiceThread = boost::thread(boost::bind(&boost::asio::io_service::run, &IoService));

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

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


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

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



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

    Timer.start(1000);
}

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()
{
    Timer.stop();
    HeartbeatTimer->cancel();
    MapHeartbeatTimer->cancel();
    //HeartbeatTimer = boost::shared_ptr<boost::asio::deadline_timer>();
    //MapHeartbeatTimer = boost::shared_ptr<boost::asio::deadline_timer>();

    ClientSocket->CloseImmediate();



}

void TObserverClientModel::OnSocketClosed()
{
    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
    {
        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 text = ws2qs(Uik);
            text = text + QString::number(i->Uik)+"\\n";
            text = text +QString::fromUtf8(i->LastName.c_str());
            text = text +"\\n" + QString::fromUtf8(i->FirstName.c_str());
            text = text + "\\n"+QString::fromUtf8(i->MiddleName.c_str());
            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 == 2)
            {
                State = L"Удаление с УИК";
            }
            else if (i->MapState == 3)
            {
                State = L"Вброс";
            }
            else if (i->MapState == 4)
            {
                State = L"Карусель";
            }
            else if (i->MapState == 5)
            {
                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()->webView->page()->mainFrame()->evaluateJavaScript("AddMarker("+posX+", "+posY+", "+ mapState + ");");
            }
        }
    }

    Timer.start(1000);

    UpdatingMapMutex.unlock();
}


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);


}
