#include "arbeitsview.h"
#include <QLayout>
#include "object.h"
#include "frametreemodel.h"
#include "mainwindow.h"
#include <QDebug>
#include "kmath.h"
#include <QToolTip>

// Errechnet die Farbe eines Objektes, so dass Objekte mit ähnlicher ID unterschiedliche Farben bekommen
//  start: Die Farbe des ersten Objektes
//  index: Die Id des Objektes, zu dem die Farbe ermittelt werden soll
QColor colorFunction( QColor start, int index )
{
    if( index < 0 )
        return start;
    if( index % 2 == 0 )
        return colorFunction( QColor( (start.green() + 10 * index) % 255, (start.blue() + 10 * index) % 255, (start.red() + 10 * index) % 255, start.alpha() ), index - 1 );
    else
        return colorFunction( QColor( (start.green() * index + 70) % 255, (start.blue() * index + 40) % 255, (start.red() * index + 60) % 255, start.alpha() ), index - 1 );
}

// Errechnet den Mittelpunkt eines Polygons
QPointF centerOfPolygon( QPolygon p )
{
    QPointF res;
    for( QPoint po : p )
    {
        res.setX( po.x() + res.x() );
        res.setY( po.y() + res.y() );
    }
    res /= p.size();
    return res;
}

// Inhalt der Arbeitsview Klasse
//-------------------------------
ArbeitsView::ArbeitsView(ArbeitsModel *model, QWidget *parent)
    : QWidget(parent),
      m( model ),
      c( 0 ),
      selectArea( 0 )
{
    parent->layout()->addWidget( this );
    this->setMouseTracking( true );
}

ArbeitsView::~ArbeitsView()
{
    delete selectArea;
}

// Setzt den Controller, der die Nutzereingaben verarbeiten soll
void ArbeitsView::setController( ArbeitsController *controller )
{
    c = controller;
}

// Zeichnet die View neu
void ArbeitsView::paintEvent(QPaintEvent *)
{
    m->setView( pos(), size() );
    QPainter painter( this );
    if( m->getFrame() )
    {
        if( m->getDeleteField() )
        {
            if( !selectArea )
            {
                selectArea = new QRubberBand( QRubberBand::Rectangle, this );
                selectArea->show();
            }
            selectArea->setGeometry( *m->getDeleteField() );
        }
        else if( selectArea )
        {
            selectArea->hide();
            delete selectArea;
            selectArea = 0;
        }
        // Zeichne Hintergrund Bild
        painter.drawImage( QRect( m->translate( QPoint( 0, 0 ) ), m->translate( QPoint( m->getImage().width(), m->getImage().height() ) ) ), m->getImage() );
        if( m->isMaskShown() && !m->getMask().isNull() )
        { // Zeichne Masken Overlay
            QPixmap img = m->getMask();
            painter.setOpacity( 0.75 );
            painter.drawPixmap( QRect( m->translate( QPoint( 0, 0 ) ), m->translate( QPoint( img.width(), img.height() ) ) ), img );
            painter.setOpacity( 1 );
        }
        QList<ObjectPolygon> objects = m->getFrame()->getObjects();
        QPen white( QColor( 255, 255, 255 ), 2 ); // Erstellt Stifte zum Zeichnen
        QPen grey( QColor( 200, 200, 200 ), 1 );
        QPen green( QColor( 0, 255, 0 ), 2 );
        QPen lightGreen( QColor( 100, 255, 100 ), 2 );
        QBrush blackBrush( QColor( 0, 0, 0 ), Qt::SolidPattern );
        for( ObjectPolygon o : objects )
        { // Schleife durch alle Objekte des Bildes
            if( o->isSelected() )
            {
                painter.setPen( white );
                int pIndex;
                if( o == m->getCopyedObject() || ( !m->getCopyedObject().isNull() && o->getId() != "-1" && o->getId() == m->getCopyedObject()->getId() ) )
                    painter.setPen( green );
                else if( o == m->getFrame()->getObjectAt( m->inverseTranslate( m->getMousePoint() ), pIndex ) )
                    painter.setPen( lightGreen );
                pIndex = 0;
                for( QPolygon pol : o->getPolygonList() )
                { // Schleife durch alle Polygone des Bildes
                    QBrush tmpB = painter.brush();
                    if( m->areColoresShown() )
                        painter.setBrush( QBrush( colorFunction( QColor( 255, 127, 0, 127 ), o->getId().toInt() ), Qt::SolidPattern ) );
                    painter.drawPolygon( m->translatePolygon( pol ) ); // Zeichne Polygon
                    if( m->areIdsShown() )
                    { // Zeichne Objekt ID
                        QFont f = painter.font();
                        f.setPointSize( 30 );
                        f.setWeight(QFont::DemiBold);
                        QPainterPath tPath;
                        tPath.addText( centerOfPolygon( m->translatePolygon( pol ) ), f, o->getId() );
                        painter.setBrush( blackBrush );
                        painter.drawPath( tPath );
                    }
                    painter.setBrush(tmpB);
                    int index = 0;
                    for( QPoint p : pol )
                    { // Schleife durch alle Eckpunkte des Polygons
                        QPen tmp = painter.pen();
                        if( ( o == m->getCopyedObject() ) ||
                            ( o == m->getMoveObject() && m->getMoveIndex() == index && m->getMovePolygon() == pIndex ) ||
                            ( index == m->getCutIndex() && o == m->getCutObject() && m->getCutPolygon() == pIndex ) )
                            painter.setPen( green );
                        painter.drawEllipse( m->translate( p ), 5, 5 ); // Zeichne Eckpunkt
                        index++;
                        painter.setPen( tmp );
                    }
                    pIndex++;
                }
            }
            else
            { // Falls das Objekt versteckt ist werden nur die Polygone gezeichnet
                painter.setPen( grey );
                if( o == m->getCopyedObject() )
                    painter.setPen( green );
                for( QPolygon pol : o->getPolygonList() )
                {
                    painter.drawPolygon( m->translatePolygon( pol ) );
                }
            }
        }
        if( m->getMode() == NEW )
        { // Zeichnen des neuen Objektes, welches noch nicht fertig erstellt wurde
            painter.setPen( QPen( QColor( 0, 255, 0 ), 2, Qt::DotLine ) );
            if( !m->getNewPolygon() )
                painter.drawEllipse( (int)(m->getMousePoint().x()) - 2, (int)(m->getMousePoint().y()) - 2, 5, 5 );
            else
            {
                for( auto p = m->getNewPolygon()->begin(); p != m->getNewPolygon()->end() - 1; p++ )
                    painter.drawLine( m->translate( *p ), m->translate( *(p + 1) ) );
                if( m->inverseTranslate( m->getMousePoint() ).x() > m->getNewPolygon()->begin()->x() - 10 &&
                        m->inverseTranslate( m->getMousePoint() ).x() < m->getNewPolygon()->begin()->x() + 10 &&
                        m->inverseTranslate( m->getMousePoint() ).y() > m->getNewPolygon()->begin()->y() - 10 &&
                        m->inverseTranslate( m->getMousePoint() ).y() < m->getNewPolygon()->begin()->y() + 10 )
                {
                    painter.drawLine( m->translate( *m->getNewPolygon()->begin() ), m->translate( *(m->getNewPolygon()->end() - 1) ) );
                }
                else
                {
                    painter.drawLine( m->translate( *m->getNewPolygon()->begin() ), m->getMousePoint() );
                    painter.drawLine( m->getMousePoint(), m->translate( *(m->getNewPolygon()->end() - 1) ) );
                    painter.drawEllipse( (int)(m->getMousePoint().x()) - 2, (int)(m->getMousePoint().y()) - 2, 5, 5 );
                }
            }
        }
        if( !m->getCopyedObject().isNull() )
        { // Zeichnet das Kopierte Objekt um die Maus herum
            QPoint mousePos = m->inverseTranslate( m->getMousePoint() );
            int pIndex;
            if( m->getFrame()->getObjectAt( mousePos, pIndex ).isNull() )
            {
                QMatrix m;
                m.QMatrix::translate( mousePos.x(), mousePos.y() );
                m.rotate( this->m->getCopyedRotation() );
                m.translate( -this->m->getCopyedCenter().x(), -this->m->getCopyedCenter().y() );
                painter.setPen( QPen( QColor( 0, 255, 0 ), 2, Qt::DotLine ) );
                for( QPolygon pol : this->m->getCopyedObject()->getPolygonList() )
                    painter.drawPolygon( this->m->translatePolygon( m.map( pol ) ) );
            }
        }
        if( !m->getMoveObject().isNull() && m->getInsertIndex() >= 0 )
        { // Zeichnet beim Bewegen den zu bewegenden Eckpunkt
            painter.setPen( green );
            painter.drawEllipse( m->translate(m->getNewVertex() ), 5, 5 );
        }
    }
}

// Leitet nutzereingaben an den Controller weiter
void ArbeitsView::mousePressEvent( QMouseEvent *e )
{
    if( c && m->getFrame() )
        c->mousePressEvent( e );
}

// Leitet nutzereingaben an den Controller weiter
void ArbeitsView::mouseMoveEvent( QMouseEvent *e )
{
    if( c && m->getFrame() )
        c->mouseMoveEvent( e );
}

// Leitet nutzereingaben an den Controller weiter
void ArbeitsView::mouseReleaseEvent( QMouseEvent *e )
{
    if( c && m->getFrame() )
        c->mouseReleaseEvent( e );
}

// Leitet nutzereingaben an den Controller weiter
void ArbeitsView::wheelEvent(QWheelEvent *e)
{
    if( c && m->getFrame() )
        c->wheelEvent( e );
}

// Zeigt tooltip für Objekte an
bool ArbeitsView::event( QEvent *e )
{
    if (e->type() == QEvent::ToolTip)
    {
        QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
        int pIndex;
        if( m->getFrame() )
        {
            ObjectPolygon p = m->getFrame()->getObjectAt( m->inverseTranslate( helpEvent->pos() ), pIndex );
            if ( !p.isNull() ) {
                QToolTip::showText(helpEvent->globalPos(), "Objekt: " + p->getId(), this);
            } else {
                QToolTip::hideText();
                e->ignore();
            }
            return true;
        }
    }
    return QWidget::event( e );
}
