#include<QPainter>
#include<QMouseEvent>
#include<QPen>
#include<iostream>
#include "toile.h"
#include<QPoint>
#include<QDebug>
#include<QtMath>
#include<QAction>
Toile::Toile(QWidget *parent) :
    QWidget(parent)
{
    this->setMinimumSize(800,600);
}

void Toile::paintEvent(QPaintEvent* e){
    QWidget::paintEvent(e);
    QPainter painter(this);


    this->pen.setStyle(this->penStyle);
    this->pen.setWidth(this->lineWidth);
    this->pen.setBrush(this->color);
    this->pen.setJoinStyle(this->joinStyle);
    this->pen.setCapStyle(this->capStyle);

    painter.setPen(this->pen);


    qDebug() <<QString("paintEvent:") << etat;
    switch(this->etat)
    {
        case Select:
        {
            if(currentPen != nullptr)
            {
                this->currentPen->setStyle(this->penStyle);
                this->currentPen->setWidth(this->lineWidth);
                this->currentPen->setBrush(this->color);
                this->currentPen->setJoinStyle(this->joinStyle);
                this->currentPen->setCapStyle(this->capStyle);
                painter.drawPath(*currentPath);
                painter.drawEllipse(mouseZone);
            }
            break;
        }
        case Line:
        case PolyLine:
            if(this->polyLinePath != nullptr)
                painter.drawPath(*this->polyLinePath);
            painter.drawLine(start_point, end_point);
            break;
        case Circle:
        {
            QPoint tmpPoint(end_point - start_point);
            int r = qSqrt(tmpPoint.x() * tmpPoint.x() + tmpPoint.y() * tmpPoint.y());
            painter.drawEllipse(start_point,r,r);
            break;
        }
        case Ellipse:
        {
            int rx = qAbs((end_point- start_point).x());
            int ry = qAbs((end_point - start_point).y());
            painter.drawEllipse(start_point,rx,ry);
            break;
        }
        case Square:
        {
            painter.drawRect(start_point.x(),
                             start_point.y(),
                             end_point.x() - start_point.x(),
                             end_point.x() - start_point.x()
                            );
            break;
        }
        case Rectangle:
        {
            painter.drawRect(start_point.x(),
                             start_point.y(),
                             end_point.x()-start_point.x(),
                             end_point.y()-start_point.y()
                            );
            break;
        }
    }


    int size = this->pathContiner.size();

    for(int i = 0; i< size;i++){
        painter.setPen(this->displayList.at(i));
        painter.drawPath(this->pathContiner.at(i));
    }
}

// Event Mouse
void Toile::mousePressEvent(QMouseEvent *event){
    if(event->button() == Qt::LeftButton){
        this->start_point= event->pos();
        switch(this->etat){
            case Select:
                //TODO
                if(findSelectedObjects(start_point)){
                    this->selectedMenu.clear();
                    selectedMenu.addActions(selectAG->actions());
                    selectedMenu.popup(event->globalPos());
                    selectedMenu.exec();
                }
                break;
            case PolyLine:
                this->setMouseTracking(true);
                if(polyLinePath == nullptr)
                    this->polyLinePath = new QPainterPath(start_point);
                else
                    this->polyLinePath->lineTo(start_point);
                break;
        }
    }
}

void Toile::mouseMoveEvent(QMouseEvent *event){
    this-> end_point = event->pos();
    updateMouseZone(event->pos());
    this-> update();
    if(this->etat == Select && event->button() == Qt::RightButton);
}

void Toile::mouseReleaseEvent(QMouseEvent *event){
    if(event->button() == Qt::LeftButton){
        this->end_point = event->pos();
        QPainterPath newPath(start_point);
        switch(this->etat)
        {
            case Select:
            {
                for(int i = displayList.count() -1; i>=0; i--){
                    if(this->pathContiner.at(i).contains(end_point)){

                    }
                }
                break;
            }
            case Line:
            {
                newPath.lineTo(end_point);
                pathNameList.append("Line");
                break;
            }
            case PolyLine:
            {
                break;
            }
           case Circle:
            {
                QPoint tmpPoint(end_point - start_point);
                int r = qSqrt(tmpPoint.x() * tmpPoint.x() + tmpPoint.y() * tmpPoint.y());
                newPath.addEllipse(start_point,r,r);
                tmpPoint.~QPoint();
                this->pathNameList.append("Circle");
                break;
            }

            case Ellipse:
            {
                int rx = qAbs((end_point- start_point).x());
                int ry = qAbs((end_point - start_point).y());
                newPath.addEllipse(start_point,rx,ry);
                this->pathNameList.append("Ellipse");
                break;
            }
            case Square:
            {
                newPath.addRect(start_point.x(),
                                start_point.y(),
                                end_point.x() - start_point.x(),
                                end_point.x() - start_point.x()
                                );

                this->pathNameList.append("Square");
                break;
            }
            case Rectangle:
            {
                newPath.addRect(start_point.x(),
                                start_point.y(),
                                end_point.x()-start_point.x(),
                                end_point.y()-start_point.y()
                               );
                this->pathNameList.append("Rectangle");
               break;
            }
        }
        if(!newPath.isEmpty()){
            this->pathContiner.append(newPath);
            this->displayList.append(this->pen);
        }
    }
    end_point.setX(start_point.x());
    end_point.setY(start_point.y());
    update();
 }

void Toile::mouseDoubleClickEvent(QMouseEvent *event){
    switch (this->etat){
        case PolyLine:
            this->setMouseTracking(false);
            if(this->polyLinePath == nullptr) break;
            pathContiner.append(*this->polyLinePath);
            displayList.append(this->pen);
            pathNameList.append("Polyline");
            update();
            this->polyLinePath = nullptr;
            break;
        default:
            break;
    }
}

// SLOTs
void Toile::changeColor(int colorIndex){
    QStringList colorList = QColor::colorNames();
    this->color.setColor(QColor(colorList[colorIndex]));
    repaint();
}

void Toile::changeTypeOfLine(int typeIndex){
    switch(typeIndex){
        case 0: this->penStyle = Qt::NoPen;break;
        case 1: this->penStyle = Qt::SolidLine;break;
        case 2: this->penStyle = Qt::DashLine;break;
        case 3: this->penStyle = Qt::DotLine;break;
        case 4: this->penStyle = Qt::DashDotLine;break;
        case 5: this->penStyle = Qt::DashDotDotLine;break;
    }
    std::cout << typeIndex;
    update();
}

void Toile::changeJoinStyle(int typeIndex){
    switch(typeIndex){
        case 0: this->joinStyle= Qt::BevelJoin;break;
        case 1: this->joinStyle= Qt::MiterJoin;break;
        case 2: this->joinStyle= Qt::RoundJoin;break;
    }
    update();
}


void Toile::changeCapStyle(int typeIndex){
    switch(typeIndex){
        case 0: this->capStyle= Qt::SquareCap;break;
        case 1: this->capStyle = Qt::FlatCap;break;
        case 2: this->capStyle = Qt::RoundCap;break;
    }
    update();
}

void Toile::changeEtat(int etat){
    this->etat = - etat -2 ;
    if(this->etat == Select){
        setMouseTracking((true));
    }else{
        setMouseTracking(false);
    }
    qDebug() <<"changeEtat:" <<etat;
    update();
}

void Toile::changeLineWidth(int width){
   this->lineWidth = width;
    update();
}
/** Find if there are some objects in the postion specified by arguments.
 * This fonction will update the list of action.
*@arg Position existe un position
*@return ture if there this
**/
bool Toile::findSelectedObjects(QPoint position){
    updateMouseZone(position);
    if(selectAG != nullptr){
        QList<QAction*> list = selectAG->actions();
        for(int i=0; i<list.size();i++){
            delete list.at(i);
        }

        delete selectAG;
        selectAG = nullptr;
    }

    selectAG = new QActionGroup(this);

    for(int i= this->displayList.size()-1;i>=0;i--){
        if(this->pathContiner.at(i).intersects(mouseZone)){
            QAction* action = new QAction(QString::number(i) + QString(" ") +pathNameList.at(i) );
            action->setData(QVariant(i));
            selectAG->addAction(action);
        }
    }

    if(selectAG->actions().size() > 0){
        connect(selectAG, SIGNAL(triggered(QAction*)), this, SLOT(selectObject(QAction*)));
        return true;
    }else{
        return false;
    }
}

/** Update the mouse zone
*@arg the position of the mouse
*/
void Toile::updateMouseZone(QPoint position){
    mouseZone.setCoords(position.x() - rayon,
                        position.y() - rayon,
                        position.x() + rayon,
                        position.y() + rayon);
}

bool Toile::findSelectedObject()
{
    for(int i = this->displayList.count()-1; i>=0;i--){
        if(this->pathContiner.at(i).intersects(mouseZone)){
            this->currentPath = & this->pathContiner[i];
            this->currentPen = & this->displayList[i];
            qDebug() << "Find object:" << i;
            return true;
        }
    }
    qDebug()<< "Don't fint any object" ;
    return false;
}

void Toile::modifyPathList(QAction* action){
    qDebug() << "Slot - modifyPathList :" << action->text();
    if(action->text() == "&Undo" && !displayList.isEmpty()){
        this->displayList.pop_back();
        this->pathContiner.pop_back();
        this->pathNameList.pop_back();
    }else if(action->text() == "&Clear"){
        this->displayList.clear();
        this->pathContiner.clear();
        this->pathNameList;
    }

    update();
}

void Toile::selectObject(QAction* sender){
    int i = sender->data().toInt();
    qDebug() << "Select object:" << i <<" "<< pathNameList.at(i);
    this->currentPath = & this->pathContiner[i];
    this->currentPen = & this->displayList[i];
    emit objectSelected(currentPen);
    update();
    qDebug() << "Find object:" << i;
}