#include <QDebug>
#include "mycustomwidget2.h"
#include <QPainter>
#include <QPaintEvent>
#include <QFontMetrics>

#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

#include <math.h>

static const double g=9.80665;
static const double abstandPunkte=0.001;
static const double verfahrweg_max = 0.5;
static const double motor_hoehe_max = 0.67;

const double S_MAX_X = 1.381;
const double S_MAX_Y = 0.65;
const double V_MAX_X = 2.1;
const double V_MAX_Y = 5.2;
const double A_MAX_X = 50.0;
const double A_MAX_Y = 155.0;

MyCustomWidget2::MyCustomWidget2(QWidget *parent) :
    QWidget(parent),
    m_buffer(size()),
    m_backgroundColor(Qt::white),
    m_mousePoint(),
    m_move(false),
    alpha(0),
    m_curve(),
    m_laengeMax(1.381),
    m_hoeheMax(2.0),
    m_scaleFactorX(0),
    m_scaleFactorY(0),
    m_text(),
    m_hilfe(false),
    m_startPositionX(0),
    m_startPositionY(0),
    m_error(false),
    m_font(QFont("Courier", 16)),
    textHeight(0),
    m_valid(false),
    m_sw_end_pos_x(1.4),
    m_sw_end_neg_x(0),
    m_sw_end_pos_y(0.7),
    m_sw_end_neg_y(0),
    drawStartPoint(false),
    m_isEnabled(isEnabled()),
    m_widthGesamt(0),
    m_offset_x(0),
    m_moveStartPoint(false)
{
    //draw();
    m_endPoint = m_startPoint;
    m_gestell=QPixmap(QString::fromUtf8(":/ressources/Grundgestell.png"));
    m_ausgabetrichter=QPixmap(QString::fromUtf8(":/ressources/Ausgabetrichter.png"));

    m_text[0][0] = trUtf8("x:");
    m_text[4][0] = trUtf8("z:");

    m_text[1][0] = trUtf8("Höhe:");
    m_text[5][0] = trUtf8("Weite:");

    m_text[2][0] = trUtf8("Wurfgeschw.:");
    m_text[6][0] = trUtf8("Winkel:");

    m_text[3][0] = trUtf8("Geschw. X:");
    m_text[7][0] = trUtf8("Geschw. Z:");

    m_text[0][2] = trUtf8("m");
    m_text[4][2] = trUtf8("m");

    m_text[1][2] = trUtf8("m");
    m_text[5][2] = trUtf8("m");

    m_text[2][2] = trUtf8("m/s");
    m_text[6][2] = trUtf8("°");

    m_text[3][2] = trUtf8("m/s");
    m_text[7][2] = trUtf8("m/s");

    QFontMetrics fm(m_font);
    textWidth[0][0] = fm.boundingRect("x:").width()+10;
    textWidth[1][0] = fm.boundingRect("Weite:").width()+10;
    textWidth[2][0] = fm.boundingRect("Wurfgeschw.:").width()+10;
    textWidth[3][0] = fm.boundingRect("Geschw. Z:").width()+10;

    textWidth[0][1] = fm.boundingRect("-000.000").width()+10;
    textWidth[1][1] = fm.boundingRect("-000.000").width()+10;
    textWidth[2][1] = fm.boundingRect("-000.0").width()+10;
    textWidth[3][1] = fm.boundingRect("-00.0").width()+10;

    textWidth[0][2] = fm.boundingRect("m").width()+10;
    textWidth[1][2] = fm.boundingRect("m").width()+10;
    textWidth[2][2] = fm.boundingRect("m/s").width()+10;
    textWidth[3][2] = fm.boundingRect("m/s").width()+10;

    textHeight = fm.boundingRect("Wurfgeschw.:").height();

    m_widthGesamt =     textWidth[0][0] + textWidth[0][1] + textWidth[0][2] +
                        textWidth[1][0] + textWidth[1][1] + textWidth[1][2] +
                        textWidth[2][0] + textWidth[2][1] + textWidth[2][2] +
                        textWidth[3][0] + textWidth[3][1] + textWidth[3][2];

    for(int i=0; i<4; i++){
        for(int k=0; k<2; ++k){
            m_errorValue[i][k]=false;
        }
    }

}

void MyCustomWidget2::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.drawPixmap(0, 0, m_buffer);
    painter.drawRect(this->rect().adjusted(1, 1, -1, -1));
}

void MyCustomWidget2::resizeEvent(QResizeEvent *event)
{
    // resize and repaint the buffer:
    m_buffer = QPixmap(event->size());
    m_baseRect.setTopLeft(QPointF(rect().width()/2-event->size().width()/4, rect().height()/2-event->size().height()/4));
    m_baseRect.setSize(QSize(event->size().width()/2, event->size().height()/2));
    m_curve.clear();
    m_scaleFactorX=m_baseRect.width()/(m_laengeMax);
    m_scaleFactorY=m_baseRect.height()/(m_hoeheMax);

    double posX=m_baseRect.x()+(m_sw_end_neg_x+0.1)*m_scaleFactorX;
    double posY=(m_baseRect.y()/m_scaleFactorY+m_hoeheMax-m_sw_end_pos_y)*m_scaleFactorY;
    double width=(m_sw_end_pos_x-0.2-m_sw_end_neg_x)*m_scaleFactorX;
    double height=(m_sw_end_pos_y-m_sw_end_neg_y)*m_scaleFactorY;
    m_moveableRect.setX(posX);
    m_moveableRect.setY(posY);
    m_moveableRect.setSize(QSizeF(width, height));

    int count1=ceil(m_laengeMax/abstandPunkte);
    m_curve.resize(count1);
    m_gridV.resize(m_baseRect.height()/20+1);
    m_gridH.resize(m_baseRect.width()/20+1);

    m_offset_x = (rect().width()-m_widthGesamt-10)/3;
    draw();
}

void MyCustomWidget2::mousePressEvent(QMouseEvent *event)
{
    m_valid=false;
    m_backgroundColor = QColor(Qt::yellow);
    m_mousePoint= event->pos();
    if(abs(m_mousePoint.x()-m_endPoint.x())<10 && abs(m_mousePoint.y()-m_endPoint.y())<10){
        m_move=true;
        drawStartPoint=true;
        m_endPoint=m_mousePoint;
        m_moveStartPoint=false;
    }else if(abs(m_mousePoint.x()-m_startPoint.x())<10 && abs(m_mousePoint.y()-m_startPoint.y())<10){
        m_move=true;
        drawStartPoint=true;
        m_startPoint=m_mousePoint;
        m_moveStartPoint=true;
    }else{
        if(m_moveableRect.contains(m_mousePoint)){
            m_move=true;
            drawStartPoint=true;
        }else{
            m_move=false;
            drawStartPoint=false;
        }
        m_moveStartPoint=false;
        m_startPoint=m_mousePoint;
        m_endPoint=m_mousePoint;
        m_startPositionX = (m_startPoint.x()-m_baseRect.x())/m_scaleFactorX;
        m_startPositionY = (m_baseRect.y()+m_baseRect.height()-m_startPoint.y())/m_scaleFactorY;
    }

    calc();
    draw();
    update();
    event->accept();
}

void MyCustomWidget2::calc()
{
    double dy = m_startPoint.y()-m_endPoint.y();
    double dx = m_startPoint.x()-m_endPoint.x();
    if(!dx || !dy){
        for(int i=0; i<m_curve.size(); ++i){
            double x = 0;
            double y = 0;
            m_curve[i] = QPointF(m_startPoint.x() + x*m_scaleFactorX, m_startPoint.y() - y*m_scaleFactorX);
        }
        m_valid=false;
        return;
    }

    alpha = -arcusTangens((dx), (dy));
    double diagonale = sqrt(dx*dx+dy*dy);
    double diagonaleMax = sqrt(m_baseRect.width()*m_baseRect.width()+m_baseRect.height()*m_baseRect.height()*1.0)/2;
    double alphaB = alpha*M_PI/180.0;
    double v0 = diagonale*10.0/diagonaleMax;

    double x_max=v0*v0*sin(2*alphaB)/(9.81);
    double y_max=v0*v0*sin(alphaB)*sin(alphaB)/(2.0*9.81);
    double v_x=v0*cos(alphaB);
    double v_y=v0*sin(alphaB);

    double tx=v_x/2.0/A_MAX_X;
    tx*=3;
    tx*=2.0;
    double s_x=0.5*A_MAX_X*tx*tx;
    //s_x=max(s_x, 0.1);

    double t_beschl_y;

    double s_beschl;
    double r;
    {
        t_beschl_y=v_y/(2*A_MAX_Y);
        r=A_MAX_Y/t_beschl_y;

        double v1 = 0.5*r*t_beschl_y*t_beschl_y;
        double v2 = v1 + A_MAX_Y * t_beschl_y;
        double s1 = 1.0/6.0*r*t_beschl_y*t_beschl_y*t_beschl_y;
        double s2 = s1 + v1*t_beschl_y + 0.5*A_MAX_Y*t_beschl_y*t_beschl_y;
        double s3 =  s2 + v2*t_beschl_y + 0.5*A_MAX_Y*t_beschl_y*t_beschl_y+1.0/6.0*r*t_beschl_y*t_beschl_y*t_beschl_y;
        s_beschl = s1 + s2 + s3;
    }

    if( /*(m_startPositionX+x_max)>m_laengeMax
        || (m_startPositionY+y_max)>m_hoeheMax
        || */(dx<0)
        || (dy>0)
        || (m_startPositionY>=m_sw_end_pos_y)
        || (m_startPositionX>=m_sw_end_pos_x)
        || ((m_startPositionX-s_x)<m_sw_end_neg_x)
        || ((m_startPositionY-s_beschl)<m_sw_end_neg_y)
        || (v_x>V_MAX_X)
        || (v_y>V_MAX_Y)
        || (v0>5.0)
      )
    {
        m_valid=false;
        m_error=true;
    }else{
        m_error=false;
        m_valid=true;
    }

    if((m_startPositionY>=m_sw_end_pos_y || ((m_startPositionY-s_beschl)<m_sw_end_neg_y))){
        m_errorValue[1][0]=true;
    }else{
        m_errorValue[1][0]=false;
    }

    if((m_startPositionX>=m_sw_end_pos_x) || ((m_startPositionX-s_x)<m_sw_end_neg_x)){
        m_errorValue[0][0]=true;
    }else{
        m_errorValue[0][0]=false;
    }

    if((v_x>V_MAX_X)){
        m_errorValue[3][0]=true;
    }else{
        m_errorValue[3][0]=false;
    }

    if((v_y>V_MAX_Y)){
        m_errorValue[3][1]=true;
    }else{
        m_errorValue[3][1]=false;
    }

    if(alpha<0){
        m_errorValue[2][1]=true;
    }else{
        m_errorValue[2][1]=false;
    }

    if((v0>5.0)){
        m_errorValue[2][0]=true;
    }else{
        m_errorValue[2][0]=false;
    }

    emit error(m_error);

    for(int i=0; i<m_curve.size(); ++i){
        double x = i*abstandPunkte;
        double y = (tan(alphaB)*x - (g*x*x/(2*v0*v0*cos(alphaB)*cos(alphaB))));
        m_curve[i] = QPointF(m_startPoint.x() + x*m_scaleFactorX, m_startPoint.y() - y*m_scaleFactorY);
    }
//    qDebug() << trUtf8("dx: %1, dy: %2")
//                .arg(dx)
//                .arg(dy);
    emit startSpiel(y_max, x_max);

    m_text[0][1] = trUtf8("%1 ").arg(m_startPositionX, 7, 'f', 3,' ');
    m_text[4][1] = trUtf8("%1 ").arg(m_startPositionY, 7, 'f', 3,' ');
    m_text[1][1] = trUtf8("%1 ").arg(y_max, 7, 'f', 3,' ');
    m_text[5][1] = trUtf8("%1 ").arg(x_max, 7, 'f', 3,' ');
    m_text[2][1] = trUtf8("%1 ").arg(v0, 5, 'f', 1,' ');
    m_text[6][1] = trUtf8("%1 ").arg(alpha, 5, 'f', 1,' ');
    m_text[3][1] = trUtf8("%1 ").arg(v_x, 5, 'f', 1,' ');
    m_text[7][1] = trUtf8("%1 ").arg(v_y, 5, 'f', 1,' ');

}

double MyCustomWidget2::arcusTangens(double x, double y)
{
    double result=0;
    if(x>0){
        result = atan(y/x);
    }else if(x<0 && y>0){
        result = atan(y/x)+M_PI;
    }else if(x<0 && y<0){
        result = atan(y/x)/*-M_PI*/;
    }else if(x==0 && y>0){
        result = M_PI/2;
    }else if(x==0 && y<0){
        result = -M_PI/2;
    }else{
        result = 0;
    }

    return result * 180.0/M_PI;
}

void MyCustomWidget2::setHilfe(bool on)
{
    m_hilfe=on;
    calc();
    draw();
    update();
}

bool MyCustomWidget2::isValid() const
{
    return m_valid;
}

void MyCustomWidget2::setSoftwareEndschalter(double plus_x, double minus_x, double plus_y, double minus_y)
{
    m_sw_end_pos_x = plus_x;
    m_sw_end_neg_x = minus_x;
    m_sw_end_pos_y = plus_y;
    m_sw_end_neg_y = minus_y;
    resize(size());

}

void MyCustomWidget2::invalidate()
{
    m_move=false;
    drawStartPoint=false;
    m_startPoint=m_endPoint;
    calc();
    draw();
    update();
}

void MyCustomWidget2::mouseReleaseEvent(QMouseEvent *event)
{
    m_backgroundColor = QColor(Qt::white);
    if(m_move){
//        m_endPoint=m_rect.center();
//        m_startPoint=m_rect.center();
        calc();
    }

    m_move=false;
    if(m_valid && drawStartPoint && !m_error){
        emit startPositionChanged(QPointF(m_startPositionX, m_startPositionY));
    }

    calc();
    draw();
    update();
    event->accept();
}

void MyCustomWidget2::mouseMoveEvent(QMouseEvent *event)
{
    if(m_move){
        if(m_moveStartPoint){
            m_startPoint=event->pos();
            if(event->pos().x()>m_moveableRect.right())
                m_startPoint.setX(m_moveableRect.right());
            if(event->pos().x()<m_moveableRect.left())
                m_startPoint.setX(m_moveableRect.left());
            if(event->pos().y()>m_moveableRect.bottom())
                m_startPoint.setY(m_moveableRect.bottom());
            if(event->pos().y()<m_moveableRect.top())
                m_startPoint.setY(m_moveableRect.top());
            m_startPositionX = (m_startPoint.x()-m_baseRect.x())/m_scaleFactorX;
            m_startPositionY = (m_baseRect.y()+m_baseRect.height()-m_startPoint.y())/m_scaleFactorY;
        }else{
            m_endPoint=event->pos();
        }
        calc();
        draw();
        update();
    }
}


void MyCustomWidget2::draw()
{
    QPainter painter;
    if(painter.begin(&m_buffer)){
        painter.setRenderHint(QPainter::Antialiasing);

        //Hintergrund malen
        QBrush br(QColor(240, 240, 240));

        painter.setBrush(br);
        painter.drawRect(rect());

        //Hilfsrechteck Spielbereich
        painter.drawRect(m_baseRect);

        painter.setBrush(QBrush(QColor(255, 252, 167), Qt::BDiagPattern));
        painter.setPen(QPen(Qt::yellow, 2));
        painter.drawRect(m_baseRect/*.adjusted(0, 0, 0, -m_moveableRect.height())*/);

        if(m_isEnabled){
            //Bewegungsspielraum Antriebe
            painter.setPen(QPen(Qt::green));
            painter.setBrush(QBrush(QColor(209, 255, 209), Qt::SolidPattern));
            painter.drawRect(m_moveableRect);
        }


        painter.drawPixmap(m_baseRect.right()-(0.31/2.0)*m_scaleFactorX, m_moveableRect.top()+0.04*m_scaleFactorY , 0.31*m_scaleFactorX, 0.56*m_scaleFactorY, m_ausgabetrichter);
        painter.drawPixmap(m_baseRect.x()-20, m_baseRect.bottom()-20, m_baseRect.width()+40, rect().height() - m_baseRect.bottom()+20, m_gestell);
        painter.setPen(Qt::black);

        //Wenn Hilfe aktiviert, wird die Flugkurve angezeigt
        if(m_hilfe && alpha>0)
            painter.drawPolyline(m_curve);

        if(drawStartPoint){
            //Daten anzeigen
            double offsetX=10;
            double offsetY=10;
            painter.setPen(Qt::NoPen);
            painter.setBrush(QColor(156, 200, 217));
            painter.drawRect(QRectF(1, 1,    rect().width(), (textHeight+offsetY)*2));

            painter.setPen(Qt::black);
            QFont saveFont = painter.font();
            painter.setFont(m_font);
            for(int i=0; i<4; ++i){
                if(m_errorValue[i][0])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);

                painter.drawText(QRectF(offsetX, offsetY, textWidth[i][0], textHeight), Qt::AlignLeft, m_text[i][0]);

                if(m_errorValue[i][1])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);

                painter.drawText(QRectF(offsetX, offsetY+textHeight, textWidth[i][0], textHeight), Qt::AlignLeft, m_text[i+4][0]);
                offsetX += textWidth[i][0];

                if(m_errorValue[i][0])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);

                painter.drawText(QRectF(offsetX, offsetY, textWidth[i][1], textHeight), Qt::AlignRight, m_text[i][1]);
                if(m_errorValue[i][1])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);
                painter.drawText(QRectF(offsetX, offsetY+textHeight, textWidth[i][1], textHeight), Qt::AlignRight, m_text[i+4][1]);
                offsetX += textWidth[i][1];

                if(m_errorValue[i][0])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);
                painter.drawText(QRectF(offsetX, offsetY, textWidth[i][2], textHeight), Qt::AlignLeft, m_text[i][2]);

                if(m_errorValue[i][1])
                    painter.setPen(Qt::red);
                else
                    painter.setPen(Qt::black);
                painter.drawText(QRectF(offsetX, offsetY+textHeight, textWidth[i][2], textHeight), Qt::AlignLeft, m_text[i+4][2]);
                offsetX += textWidth[i][2]+m_offset_x;
            }
            painter.setFont(saveFont);
        }

        painter.setPen(Qt::black);

        //Skalierungslinien anzeigen
        painter.drawLine(m_baseRect.x(), m_baseRect.y()+m_baseRect.height(), m_baseRect.x()+m_baseRect.width(), m_baseRect.y()+m_baseRect.height());
        double abstand=0.25;
        int count1=floor(m_laengeMax/abstand);

        for(int i=0; i<=count1; ++i){
            QFontMetrics fm(painter.font());
            if(i>=0 && i<=count1){
                QString text=QString::number(i*abstand, 'f', 3);

                painter.drawText(i*abstand*m_scaleFactorX+m_baseRect.x()-fm.tightBoundingRect(text).width()/2, m_baseRect.y()+m_baseRect.height()+15, text);
            }
            painter.drawLine(i*abstand*m_scaleFactorX+m_baseRect.x(), m_baseRect.y()+m_baseRect.height()-5, i*abstand*m_scaleFactorX+m_baseRect.x(), m_baseRect.y()+m_baseRect.height()+5);
        }

        int count = ceil(m_hoeheMax/abstand);
        painter.drawLine(m_baseRect.x(), m_baseRect.y(), m_baseRect.x(), m_baseRect.y()+m_baseRect.height());
        for(int i=0; i<=count; ++i){
            QFontMetrics fm(painter.font());
            if(i>=0 && i<=count){
                QString text=QString::number(i*abstand, 'f', 3);

                painter.drawText(m_baseRect.x()-fm.tightBoundingRect(text).width()-10, m_baseRect.y()+m_baseRect.height() - i*abstand*m_scaleFactorY+fm.tightBoundingRect(text).height()/2, text);
            }
            painter.drawLine(m_baseRect.x()-5, m_baseRect.y() + i*abstand*m_scaleFactorY, m_baseRect.x()+5, m_baseRect.y() + i*abstand*m_scaleFactorY);
        }
        if(m_startPoint != m_endPoint){
            m_error ? painter.setPen(QPen(Qt::red, 5)) : painter.setPen(QPen(Qt::darkBlue, 5));
            painter.drawLine(m_startPoint, m_endPoint);
            painter.setPen(Qt::black);
            painter.setBrush(Qt::green);
            painter.drawEllipse(m_endPoint, 6, 6);
            painter.drawEllipse(m_startPoint, 5, 5);
        }else{
            if(drawStartPoint){
                painter.setPen(Qt::black);
                painter.setBrush(Qt::green);
                painter.drawEllipse(m_startPoint, 5, 5);
            }
        }
    }
    painter.end();
}

void MyCustomWidget2::createGrid()
{
    QPainter painter;
    for(int i=0; i<m_gridV.size(); ++i){
        m_gridV[i] = QLineF(0, i*20, m_baseRect.width(), i*20);
    }

    for(int i=0; i<m_gridH.size(); ++i){
        m_gridH[i] = QLineF(i*20, 0, i*20, m_baseRect.height());
    }

    if(painter.begin(&m_buffer)){
        QRectF rect1 = this->m_baseRect;

        painter.setBrush(QBrush(Qt::gray));
        painter.drawRect(rect1);

        painter.drawLines(m_gridH);
        painter.drawLines(m_gridV);
    }

}

void MyCustomWidget2::timerEvent(QTimerEvent *event)
{
    QWidget::timerEvent(event);
}


void MyCustomWidget2::setError(bool val)
{
    if(!m_error){
        m_error=val;
        m_endPoint = m_startPoint;
        draw();
        update();
    }
}

void MyCustomWidget2::setEnabled(bool val)
{
    m_isEnabled=val;
    QWidget::setEnabled(val);
    draw();
    update();
}

void MyCustomWidget2::setDisabled(bool val)
{
    m_isEnabled=!val;
    QWidget::setDisabled(val);
    draw();
    update();
}
