#include <QPainter>

#include "QFitsMarkers.h"
#include "QFitsSingleBuffer.h"
#include "QFitsMultiBuffer.h"

QFitsMarkers::QFitsMarkers(QColor sourceBorder,
                           QColor sourceFill,
                           QColor continuumBorder,
                           QColor continuumFill,
                           QColor lockBorder,
                           QColor lockFill,
                           Qt::PenStyle ps,
                           Qt::BrushStyle bs)
{
    sourcePen = new QPen(sourceBorder);
    sourcePen->setStyle(ps);
    continuumPen = new QPen(continuumBorder);
    continuumPen->setStyle(ps);
    lockPen = new QPen(lockBorder);
    lockPen->setStyle(ps);

    sourceBrush = new QBrush(sourceFill);
    sourceBrush->setStyle(bs);
    continuumBrush = new QBrush(continuumFill);
    continuumBrush->setStyle(bs);
    lockBrush = new QBrush(lockFill);
    lockBrush->setStyle(bs);

    initVal = 0;
    initCenter();
    bufferToPaint = NULL;

    markerLockX = -1;
    markerLockY = -1;
}

bool QFitsMarkers::hasSourceMarkers() {
    bool ret = false;
    if (getSizeSource() > 0) {
        ret = true;
    }
    return ret;
}

bool QFitsMarkers::hasAnyMarkers() {
    bool ret = false;
    if ((getSizeSource() > 0) || (getSizeContinuum() > 0)){
        ret = true;
    }
    return ret;
}

// either add positive values (x,y) OR (negative values (-x, -y)
// and NEVER mixed values like (x,-y)!!
void QFitsMarkers::addMarkerSource(long x, long y) {
    // delete point (x,y) or its negative if it is already marked
    deleteMarker(x, y);

    // now append the new value
    markersSourceX.append(x);
    markersSourceY.append(y);
}

void QFitsMarkers::addMarkerContinuum(long x, long y) {
    // delete point (x,y) or its negative if it is already marked
    deleteMarker(x, y);

    // now append the new value
    markersContinuumX.append(x);
    markersContinuumY.append(y);
}

void QFitsMarkers::addMarkerLock(long x, long y) {
    markerLockX = x;
    markerLockY = y;
}


void QFitsMarkers::setupPointMarker() {
    deleteAllMarkers();

    addMarkerSource(centerX, centerY);
}

void QFitsMarkers::setupCircleMarkers(int r1) {
    deleteAllMarkers();

    for (long i = centerX - r1; i <= centerX + r1; i++) {
        for (long j = centerY - r1; j <= centerY + r1; j++) {
            if ((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY) <= r1*r1) {
                addMarkerSource(i, j);
            }
        }
    }
}

void QFitsMarkers::setupCircleAnnularMarkers(int r1, int r2) {
    setupCircleMarkers(r1);

    if (r1 <= r2) {
        // outer circle
        for (long i = centerX - r2; i <= centerX + r2; i++) {
            for (long j = centerY - r2; j <= centerY + r2; j++) {
                if (((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY) <= r2*r2) &&
                    ((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY) > r1*r1))
                {
                    // surrounding sky
                    addMarkerContinuum(i, j);
                }
            }
        }
    }
}

int QFitsMarkers::getSizeSource() {
    return markersSourceX.size();
}

int QFitsMarkers::getSizeContinuum() {
    return markersContinuumX.size();
}

void QFitsMarkers::getMarkerSource(int i, long *x, long *y) {
    *x = markersSourceX.at(i);
    *y = markersSourceY.at(i);
}

void QFitsMarkers::getMarkerContinuum(int i, long *x, long *y) {
    *x = markersContinuumX.at(i);
    *y = markersContinuumY.at(i);
}

void QFitsMarkers::deleteMarker(long x, long y) {
    for (int i = 0; i < getSizeContinuum(); i++) {
        if ((markersContinuumX.at(i) == x) &&
            (markersContinuumY.at(i) == y))
        {
            markersContinuumX.remove(i);
            markersContinuumY.remove(i);
            break;
        }
    }

    for (int i = 0; i < getSizeSource(); i++) {
        if ((markersSourceX.at(i) == x) &&
            (markersSourceY.at(i) == y))
        {
            markersSourceX.remove(i);
            markersSourceY.remove(i);
            break;
        }
    }
}

void QFitsMarkers::deleteMarkerLock() {
    markerLockX = -1;
    markerLockY = -1;
}

void QFitsMarkers::setCenter(QFitsSingleBuffer *sb, long newCenterX, long newCenterY) {

    setBufferToPaint(sb);

    long xshift = newCenterX - centerX;
    long yshift = newCenterY - centerY;

    centerX = newCenterX;
    centerY = newCenterY;

    long valX = 0, valY = 0;
    for (int i = 0; i < getSizeSource(); i++) {
        valX = markersSourceX.at(i);
        valY = markersSourceY.at(i);

        markersSourceX.replace(i, valX + xshift);
        markersSourceY.replace(i, valY + yshift);
    }

    for (int i = 0; i < getSizeContinuum(); i++) {
        valX = markersContinuumX.at(i);
        valY = markersContinuumY.at(i);

        markersContinuumX.replace(i, valX + xshift);
        markersContinuumY.replace(i, valY + yshift);
    }
}

void QFitsMarkers::setBufferToPaint(QFitsSingleBuffer *sb) {
    bufferToPaint = sb;
}

void QFitsMarkers::deleteAllMarkers() {
    markersSourceX.clear();
    markersSourceY.clear();
    markersContinuumX.clear();
    markersContinuumY.clear();

    initCenter();
}

void QFitsMarkers::drawAllMarkers(QPainter *pa,
                                  int xoffset, int yoffset, QFitsSingleBuffer *sb)
{
    if (bufferToPaint == NULL) {
        return;
    }

    // get zoom factor
    double w = 1.;
    if (bufferToPaint->getZoomFactor() > 1.) {
        // > 100%
        w = bufferToPaint->getZoomFactor();
    }

    // loop points and draw them
    int xw = w,
        yw = w,
        x = 0, y = 0;
    pa->translate(xoffset, yoffset);

    if ((/*sb->underMouse() && */(sb->getLockedSingleBuffer() == NULL)) || (sb->getLockedSingleBuffer() == sb)) {
    // paint continuum markers
        for (int i = 0; i < getSizeContinuum(); i++) {
            x = markersContinuumX.at(i);
            y = markersContinuumY.at(i);

            if ((x >= 1) && (x <= bufferToPaint->Naxis(1)) &&
                (y >= 1) && (y <= bufferToPaint->Naxis(2)))
            {
                bufferToPaint->imageToWidget(&x, &y);

                pa->setPen(*continuumPen);
                pa->setBrush(*continuumBrush);

                pa->drawRect(x, y, xw, yw);
            }
        }

        // paint source markers
        for (int i = 0; i < getSizeSource(); i++) {
            x = markersSourceX.at(i);
            y = markersSourceY.at(i);

            if ((x >= 1) && (x <= bufferToPaint->Naxis(1)) &&
                (y >= 1) && (y <= bufferToPaint->Naxis(2)))
            {
                bufferToPaint->imageToWidget(&x, &y);

                pa->setPen(*sourcePen);
                pa->setBrush(*sourceBrush);

                pa->drawRect(x, y, xw, yw);
            }
        }
    }

    bool isMBchild = bufferToPaint->isMultiBufferChild();

    if (!isMBchild ||
        (isMBchild && (sb == sb->getMyMultiBuffer()->getLockedSingleBuffer())))
    {
        // paint lock marker
        x = markerLockX;
        y = markerLockY;
        if ((x >= 1) && (x <= bufferToPaint->Naxis(1)) &&
            (y >= 1) && (y <= bufferToPaint->Naxis(2)))
        {
            bufferToPaint->imageToWidget(&x, &y);
            pa->setPen(*lockPen);
            pa->setBrush(*lockBrush);
            pa->drawRect(x, y, xw, yw);
        }
    }
}

void QFitsMarkers::initCenter() {
    centerX = initVal;
    centerY = initVal;
}
