#include "map.h"
#include <QDebug>
#include <QDesktopWidget>
#include <QPainter>
#include <QPen>

Map::Map(QWidget *parent) :
    QWidget(parent)
{
    srand(time(NULL));


    myCountry = new Country;
    myCountry->readInfoFromJSON(":/data/cityLimitsPR.json");

    cityColorMap = NULL;
    gisLocations = NULL;
    drawRoutes = false;

    qDebug() << "Computing limits...";
    myCountry->limits();

    QDesktopWidget widget;
    QRect mainScreenSize = widget.availableGeometry(widget.primaryScreen());

    double diffX = myCountry->maxX - myCountry->minX > 0 ? myCountry->maxX - myCountry->minX : myCountry->minX - myCountry->maxX;
    double diffY = myCountry->maxY - myCountry->minY > 0 ? myCountry->maxY - myCountry->minY : myCountry->minY - myCountry->maxY;

    if (diffX > diffY) resize(mainScreenSize.width() * 0.5 , 0.5 * mainScreenSize.width()*(diffY/diffX));
    else               resize(mainScreenSize.width() * 0.5,  0.5 * mainScreenSize.width()*(diffX/diffY));
}


Map::~Map() {
    if (myCountry    != NULL)    delete myCountry;
    if (cityColorMap != NULL)    delete cityColorMap;
    if (gisLocations != NULL)    delete [] gisLocations;
}

QPoint **qpA = new QPoint*[100];
unsigned int qpASize = 0;

void Map::paintEvent(QPaintEvent *event) {

    // the QPainter is the 'canvas' to which we will draw
    // the QPen is the pen that will be used to draw to the 'canvas'

    this->setWindowTitle("PR Visualization");
    QDesktopWidget widget;
    QRect mainScreenSize = widget.availableGeometry(widget.primaryScreen());


    if (qpASize == 0) {
        //qDebug() << "creating the arrays " << qpArraySize;
        for (int i = 0; i < 100; i++) {
            qpA[i] = new QPoint[20000];
        }
    }

    QPainter *p = new QPainter(this);
    QPen myPen;

    double factorX, factorY;

    double diffX = myCountry->maxX - myCountry->minX > 0 ? myCountry->maxX - myCountry->minX : myCountry->minX - myCountry->maxX;
    double diffY = myCountry->maxY - myCountry->minY > 0 ? myCountry->maxY - myCountry->minY : myCountry->minY - myCountry->maxY;

    if (diffX > diffY) resize(mainScreenSize.width() * 0.5 , 0.5 * mainScreenSize.width()*(diffY/diffX));
    else               resize(mainScreenSize.width() * 0.5,  0.5 * mainScreenSize.width()*(diffX/diffY));

    factorX = this->width()  / diffX;
    factorY = this->height() / diffY;

    myPen.setWidth(1);
    myPen.setColor(QColor(0x100000));
    myPen.setBrush(QBrush(Qt::black));

    p->setPen(myPen);

    int colorCtr = 0;
    QMap<QString,City*>::iterator it;
    unsigned int randColor;
    int cityCounter = 0;

    for (it = myCountry->Cities.begin() ; it != myCountry->Cities.end(); ++it) {
        City *c = it.value();

        int x1 ,y1, x2, y2;
        x1 = factorX * (c->getGeometry()->at(0).x - myCountry->minX);
        y1 = height() - factorY*(c->getGeometry()->at(0).y - myCountry->minY)  ;

        DoublePoint p1 = c->getGeometry()->at(0);
        DoublePoint p2;
        int ctr = 0;

        QPoint *qp = qpA[cityCounter];
        QPoint *qpBegin = qp;

        // if no color map provided, we'll just color every city white.
        randColor = 0xffffff;

        if (cityColorMap)
            randColor = (cityColorMap->find(it.key()) == cityColorMap->end()) ?
                        0xffffff : (*cityColorMap)[it.key()];



        for(int i = 0; i < c->getSize() + 1; i++) {
            p2 = c->getGeometry()->at((i+1)%c->getSize());

            x2 = factorX * (p2.x - myCountry->minX);
            y2 = height() - factorY*(p2.y - myCountry->minY)  ;

            if (p2.x != 0 && p1.x != 0) {
                qp->setX(x2);
                qp->setY(y2);
                ctr++;
                qp++;
            }
            else if (p2.x == 0) {
                QPolygon yourPoly;
                for (int i = 0; i < ctr; i++) yourPoly.push_back(qpBegin[i]);
                QPainterPath tmpPath;
                tmpPath.addPolygon(yourPoly);


                    p->fillPath(tmpPath,QBrush(randColor));

                p->drawPolygon(qpBegin,ctr);
                ctr = 0;
                qpBegin = qp;
            }

            x1 = x2;
            y1 = y2;
            p1 = p2;

        }

        QPolygon yourPoly;
        for (int i = 0; i < ctr; i++) yourPoly.push_back(qpBegin[i]);
        QPainterPath *tmpPath = new QPainterPath;
        tmpPath->addPolygon(yourPoly);

        p->fillPath(*tmpPath,QBrush(randColor));

        p->drawPolygon(qpBegin,ctr,Qt::WindingFill);





        delete tmpPath;
        colorCtr++;
        cityCounter++;
    }
    qpASize = cityCounter;


    // Draw the city centers
    int circleRadius = (this->height() > this->width()) ? this->width()/20 : this->height()/20 ;

    int cX, cY, pX, pY;
    cX = cY = pX = pY = -1;

    //qDebug() << "gisLocations:" << gisLocations << endl;

    if(gisLocations) {
        myPen.setWidth(2);
        myPen.setColor(QColor(0x100000));
        myPen.setBrush(QBrush(Qt::black));

        p->setPen(myPen);
        for (int i = 0; i < numLocations; i++) {
            qDebug() << "name from locations:" << gisLocations[i].getName();

            cX = factorX * (gisLocations[i].getLon() - myCountry->minX);
            cY = height() - factorY*(gisLocations[i].getLat() - myCountry->minY);
            p->setBrush(Qt::SolidPattern);
            p->setBrush(QBrush(0xff0000));

            p->drawEllipse(cX, cY, circleRadius, circleRadius);
            p->setBrush(Qt::NoBrush);
            if (drawRoutes && pX > 0) {
                p->drawLine(pX+circleRadius/2,pY+circleRadius/2,cX+circleRadius/2,cY+circleRadius/2);
            }
            pX = cX; pY = cY;
        }
    }

     QVector < QPair<const GISPOI *,const GISPOI *> > ::iterator vit = this->cityLines.begin();
    for (; vit != this->cityLines.end(); vit++) {

//        qDebug() << "A line from " << linePair.first->getName() << " to " << linePair.second->getName() << endl;
        cX = factorX * (vit->first->getLon() - myCountry->minX);
        cY = height() - factorY*(vit->first->getLat()  - myCountry->minY);
        pX = factorX * (vit->second->getLon() - myCountry->minX);
        pY = height() - factorY*(vit->second->getLat()  - myCountry->minY);
        p->drawLine(pX+circleRadius/2,pY+circleRadius/2,cX+circleRadius/2,cY+circleRadius/2);
    }

//c++11 way
/*
    for (QPair<const GISPOI *, const GISPOI *> linePair: this->cityLines) {
//        qDebug() << "A line from " << linePair.first->getName() << " to " << linePair.second->getName() << endl;
        cX = factorX * (linePair.first->getLon() - myCountry->minX);
        cY = height() - factorY*(linePair.first->getLat()  - myCountry->minY);
        pX = factorX * (linePair.second->getLon() - myCountry->minX);
        pY = height() - factorY*(linePair.second->getLat()  - myCountry->minY);
        p->drawLine(pX+circleRadius/2,pY+circleRadius/2,cX+circleRadius/2,cY+circleRadius/2);
    }
*/
    delete p;
}


void Map::drawLine(const GISPOI &city01, const GISPOI &city02) {
    this->cityLines.push_back(QPair<const GISPOI *, const GISPOI *> (&city01, &city02));
}
