/*
    Speed Climbing Stopwatch - Simple Stopwatch for Climbers
    Copyright (C) 2018  Itsblue Development - Dorian Zeder

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, version 3 of the License.

    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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include "headers/buzzerconn.h"

BuzzerConn::BuzzerConn(QObject *parent) : QObject(parent)
{
    this->networkManager = new QNetworkAccessManager();
    this->reloadNetworkManager = new QNetworkAccessManager();

    this->date = new QDateTime;
    this->latest_button_pressed = 0;
    this->connected = false;

    this->buzz_url = "https://api.itsblue.de/test/buzzerem.php";
    // "http://192.168.4.1"
}

bool BuzzerConn::connect()
{
    qDebug() << "connecting to buzzer...";
    QList<double> times = gettimes(1000);
    qDebug() << times[0];
    if(times[0] == 200.0){
        this->latest_button_pressed = times[2];
        for(int i=0;i<=100;i++){
            this->connection_progress = i;
            if(!calcoffset(this->gettimes(1000))){
                this->connection_progress = 100;
                this->connected = false;
                return(false);
            }
        }
        this->connected = true;
        return(true);
    }
    else{
        this->connected = false;
        return(false);
    }
}

bool BuzzerConn::calcoffset(QList<double> times)
{
    if(times.length() != 3){
        return(false);
    }
    if(times[0] == 200.0){
        this->latest_button_pressed = times[2];
        double offset = date->currentMSecsSinceEpoch() - times[1];
        if(this->latest_offsets.length()>=100){
            this->latest_offsets.removeFirst();
        }
        this->latest_offsets.append(offset);

        double mem = 0;
        for(int i=0;i<latest_offsets.length();i++){
            mem += latest_offsets[i];
        }
        this->offset = mem / double(latest_offsets.length());
        qDebug("%20f", this->offset);
        return(true);
    }
    else {
        //this->connected = false;
        return(false);
    }
}

QList<double> BuzzerConn::gettimes(int timeout)
{
    QList<double> times;
    ReturnData_t ret = senddata(this->networkManager, QUrl(this->buzz_url), timeout);
    times.append(double(ret.status_code));

    if(ret.status_code == 200){
        ret.text.replace("\n","");
        ret.text.replace("\r","");
        QStringList times_cache = ret.text.split("<br>");
        times.append(times_cache[0].toDouble());
        times.append(times_cache[1].toDouble());

        return(times);
    }
    else{
        return(times);
    }
}

bool BuzzerConn::buzzer_triggered()
{

    if(!this->connected){
        return(false);
    }
    QList<double> times = this->gettimes(1000);
    if(times[0] == 200.0){
        if(times[2] > this->latest_button_pressed){
            this->latest_button_pressed = times[2];

            return(true);
        }
        else {
            return(false);
        }
    }
    else{
        //this->connected = false;
        return(false);
    }
}

bool BuzzerConn::start()
{
    if(!this->connected){
        return(false);
    }
    QList<double> times = this->gettimes(1000);
    if(times[0] == 200.0 && this->connected){
        this->latest_button_pressed = times[2];
        return(true);
    }
    else{
        this->connected = false;
        return(false);
    }
}

double BuzzerConn::get(QString key)
{
    if(key == "offset"){
        return(this->offset);
    }
    else if (key == "lastpressed") {
        return(this->latest_button_pressed);
    }
    else if( key == "currtime") {
        return(this->date->currentMSecsSinceEpoch());
    }
    else if( key == "connection_progress") {
        return(this->connection_progress);
    }
    else if( key == "connected") {
        if(this->connected){
            return(1);
        }
        return(0);
    }
}

QString BuzzerConn::test()
{
    ReturnData_t ret = this->senddata(this->networkManager, QUrl("http://www.google.de"), 500);
    return(ret.text);
}

bool BuzzerConn::refresh()
{
    if(!this->connected){
        return(false);
    }
    QList<double> times;
    ReturnData_t ret = senddata(this->reloadNetworkManager, QUrl(this->buzz_url), 1000);
    times.append(double(ret.status_code));

    if(ret.status_code == 200){
        ret.text.replace("\n","");
        ret.text.replace("\r","");
        QStringList times_cache = ret.text.split("<br>");
        times.append(times_cache[0].toDouble());
        times.append(times_cache[1].toDouble());
        calcoffset(times);
        return(true);
    }
    else{
        this->connected = false;
        return(false);
    }
}

ReturnData_t BuzzerConn::senddata(QNetworkAccessManager * NetMan, QUrl serviceUrl, int timeout)
{

    ReturnData_t ret; //this is a custom type to store the returned data
    // Call the webservice

    QNetworkRequest request(serviceUrl);
    request.setHeader(QNetworkRequest::ContentTypeHeader,
        "application/x-www-form-urlencoded");

    //send a POST request with the given url and data to the server
    QUrlQuery pdata;
    QNetworkReply* reply;

    //wait until the request has finished
    QEventLoop loop;
    QTimer timer;

    timer.setSingleShot(true);
    loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    loop.connect(NetMan, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));

    timer.start(timeout);
    reply = NetMan->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
    loop.exec();
    timer.stop();

    //get the status code
    QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

    ret.status_code = status_code.toInt();
    if(ret.status_code == 0){ //if the statuscode is zero, the connecion to the server was not possible
        ret.status_code = 444;
    }
    //get the full text response
    ret.text = QString::fromUtf8(reply->readAll());

    //return the data
    return(ret);
}
