#include <QPainter>
#include <QCursor>
#include <QMessageBox>
#include <QResizeEvent>
#include <QClipboard>

#include "qtdpuser.h"
#include "fitting.h"
#include "QFitsTools.h"
#include "QFitsSingleBuffer.h"
#include "QFitsMainWindow.h"
#include "galfit.h"
#include "dialogs.h"
#include "events.h"

#include "gsl/gsl_sf_gamma.h"

//------------------------------------------------------------------------------
//         QFitsToolsWidget
//------------------------------------------------------------------------------
QFitsToolsWidget::QFitsToolsWidget(QWidget *parent)
    : QStackedWidget(parent) {
    myparent = parent;
    floating = false;
    hideButton = new QFitsSimplestButton(QIcon(":/xicon.svg").pixmap(10, 10), this);
    hideButton->setGeometry(width() - 12, 0, 12, 12);
    hideButton->setToolTip("Close");
    connect(hideButton, SIGNAL(clicked()),
            this, SLOT(hide()));
    floatButton = new QFitsSimplestButton(QIcon(":/raise.svg").pixmap(10, 10), this);
    floatButton->setGeometry(width() - 28, 0, 12, 12);
    floatButton->setToolTip("Float");
    connect(floatButton, SIGNAL(clicked()),
            this, SLOT(setFloating()));

    oldflags = windowFlags();
}

void QFitsToolsWidget::resizeEvent(QResizeEvent *e) {
    hideButton->setGeometry(e->size().width() - 12, 0, 12, 12);
    floatButton->setGeometry(e->size().width() - 28, 0, 12, 12);
}

void QFitsToolsWidget::setCurrentWidget(QWidget *w) {
    QStackedWidget::setCurrentWidget(w);
    hideButton->raise();
    floatButton->raise();
}

void QFitsToolsWidget::setFloating() {
    bool wasVisible = isVisible();
    if (floating) {
        setParent(mysplitter);
        setWindowFlags(oldflags);
        floatButton->setPixmap(QIcon(":/raise.svg").pixmap(10, 10));
    } else {
        QPoint curPos = mapToGlobal(pos());
        setParent(myparent);
        move(mapFromParent(curPos));
        floatButton->setPixmap(QIcon(":/lower.svg").pixmap(10, 10));
        setWindowFlags(Qt::Tool);
    }
    if (wasVisible) show();
    floating = !floating;
}

void QFitsToolsWidget::setSplitter(QSplitter *thesplitter) {
    mysplitter = thesplitter;
}

QFits2dFit::QFits2dFit(QFitsMainWindow *parent) :
                                       QWidget(dynamic_cast<QWidget*>(parent)) {
    myParent = parent;
    int i, maxheight, maxwidth;
    zoom = zoomIndex+1;
    cenx = ceny = 0;
    QLabel *widthlabel = new QLabel("Fit window radius:", this);
    widthlabel->adjustSize();
    maxheight = widthlabel->height();
    fitwindow = new QSpinBox(this);
    fitwindow->setMinimum(2);
    fitwindow->setMaximum(999);
    fitwindow->setSingleStep(1);
    fitwindow->setValue(20);
    savefitwidth = 20;
    fitwindow->adjustSize();
    if (fitwindow->height() > maxheight) {
        maxheight = fitwindow->height();
    }
//    refitButton = new QPushButton("Fit again", this);
//    refitButton->adjustSize();
//    if (refitButton->height() > maxheight) {
//        maxheight = refitButtond->height();
//    }
    widthlabel->setGeometry(10, 155, widthlabel->width(), maxheight);
    fitwindow->setGeometry(widthlabel->x() + widthlabel->width() + 5,
                           widthlabel->y(),
                           fitwindow->width(),
                           maxheight);
//    refitButton->setGeometry(fitwindow->x() + fitwindow->width() + 5,
//                             widthlabel->y(),
//                             refitButton->width(),
//                             maxheight);
    fitfunction = new QComboBox(this);
    fitfunction->addItem("Gauss");
//    fitfunction->addItem("Moffat");
    fitfunction->addItem("Sersic");
    fitfunction->adjustSize();
    fitfunction->setGeometry(10, fitwindow->y() + fitwindow->height() + 5, fitfunction->width() * 1.3, fitfunction->height());
//    fitfunction->setGeometry(10, fitwindow->y() + fitwindow->height() + 5, 280, 25);

    fitslm = new QCheckBox("fix sersic index at:", this);
    fitslm->adjustSize();
    maxheight = fitslm->height();
    slm = new QDoubleSpinBox(this);
    slm->setRange(0.1, 5.0);
    slm->setValue(1.0);
    slm->setSingleStep(0.1);
    slm->adjustSize();
    if (slm->height() > maxheight) {
        maxheight = slm->height();
    }
    fitslm->setGeometry(10, fitfunction->y() + fitfunction->height() + 5,
                        fitslm->width(), maxheight);
    fitslm->hide();
    slm->setGeometry(fitslm->x() + fitslm->width() + 5, fitslm->y(),
                     slm->width(),maxheight);
    slm->hide();

// TODO QT6
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
		int lw = fontMetrics().boundingRect("Sersic Index: ").width();
#else
    int lw = fontMetrics().horizontalAdvance("Sersic Index: ");
#endif /* QT_VERSION */

    for (i = 0; i < 10; i++) {
        fitresults[i] = new dpFitResult(this);
        fitresults[i]->adjustSize();
        resultlabels[i] = new QLabel(this);
        resultlabels[i]->setGeometry(10, slm->y() + slm->height() + 10 + i*fitresults[i]->height(), lw, fitresults[i]->height());
        fitresults[i]->move(lw, resultlabels[i]->y());
    }

//    resultLabel1 = new QLabel(" \n \n \n \n \n \n \n \n \n ", this);
//    resultLabel1->adjustSize();
//    resultLabel1->move(10, fitslm->y() + fitslm->height() + 5);
//    resultLabel2 = new QLabel(" \n \n \n \n \n \n \n ", this);
//    resultLabel2->move(resultLabel1->x() + 10, resultLabel1->y());
//    resultLabel2->setAlignment(Qt::AlignRight);
//    resultLabel2->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
//    resultLabel2->setCursor(Qt::IBeamCursor);
//    resultLabelPM = new QLabel(" \n \n \n \n \n \n \n ", this);
//    resultLabelPM->move(resultLabel2->x() + 10, resultLabel1->y());
//    resultLabel3 = new QLabel(" \n \n \n \n \n \n \n ", this);
//    resultLabel3->move(resultLabelPM->x() + 10, resultLabel1->y());
//    resultLabel3->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
//    resultLabel3->setCursor(Qt::IBeamCursor);
    resultLabelCuts = new QLabel(" \n \n", this);
    resultLabelCuts->adjustSize();
    resultLabelCuts->move(10, resultlabels[9]->y() + resultlabels[9]->height() + 10);

    maxwidth = slm->x() + slm->width() + 10;
    maxwidth = fitresults[0]->width() + resultlabels[0]->width();
    if (maxwidth < 170) {
        maxwidth = 170;
    }

    QLabel *copyFitResultLabel = new QLabel("<b>Copy fit result to:</b>", this);
    copyFitResultLabel->adjustSize();
    copyFitResultLabel->move(10, resultLabelCuts->y() + resultLabelCuts->height() + 10);
    QPushButton *copyFitResultButton = new QPushButton("Clipboard", this);
    copyFitResultButton->adjustSize();
    copyFitResultButton->setGeometry(10, copyFitResultLabel->y() + copyFitResultLabel->height(), (maxwidth-30) / 2, copyFitResultButton->height());
    QPushButton *bufferFitResultButton = new QPushButton("new Buffer", this);
    bufferFitResultButton->adjustSize();
    bufferFitResultButton->setGeometry((maxwidth-30) / 2 + 20, copyFitResultLabel->y() + copyFitResultLabel->height(), (maxwidth-30) / 2, bufferFitResultButton->height());
    createButton = new QPushButton("new buffer from fit", this);
    createButton->adjustSize();
    createButton->setGeometry(10, copyFitResultButton->y() + copyFitResultButton->height() + 10,
                              maxwidth - 20, createButton->height());
    QPushButton *galfitButton = new QPushButton("pass to Galfit", this);
    galfitButton->setGeometry(fitfunction->x() + fitfunction->width() + 5, fitfunction->y(), maxwidth-(fitfunction->x() + fitfunction->width() + 10), fitfunction->height());

//    closeButton = new QPushButton("Close", this);
//    closeButton->setGeometry(maxwidth / 2 - 50,
//                             createButton->y() + createButton->height() + 10,
//                             100, 30);

    connect(fitwindow, SIGNAL(valueChanged(int)),
            this, SLOT(zoomChanged(int)));
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    connect(fitfunction, SIGNAL(activated(const QString &)),
            this, SLOT(fitfunctionChanged(const QString &)));
#else
    connect(fitfunction, SIGNAL(textActivated(const QString &)),
            this, SLOT(fitfunctionChanged(const QString &)));
#endif /* QT_VERSION */
//    connect(closeButton, SIGNAL(clicked()),
//            this, SLOT(hide()));
//    connect(closeButton, SIGNAL(clicked()),
//            myParent->toolsWidget, SLOT(hide()));
    connect(fitslm, SIGNAL(clicked(bool)), this, SLOT(refit()));
    connect(slm, SIGNAL(valueChanged(double)), this, SLOT(refit()));
//    connect(refitButton, SIGNAL(clicked()),
//            this, SLOT(refit()));
    connect(copyFitResultButton, SIGNAL(clicked()),
            this, SLOT(copyFitResult()));
    connect(bufferFitResultButton, SIGNAL(clicked()),
            this, SLOT(newBufferFromFitResult()));
    connect(createButton, SIGNAL(clicked()),
            this, SLOT(createFitFunction()));
    connect(galfitButton, SIGNAL(clicked()), this, SLOT(passToGalfit()));

//    resize(maxwidth, closeButton->y() + closeButton->height() + 20);
    resize(maxwidth, createButton->y() + createButton->height() + 20);
//    resultwidget->setGeometry(0, createButton->y() + createButton->height() + 5, maxwidth, 200);
//    resultwidget->adjustSize();
    setFixedSize(size());

    Qt::WindowFlags flags = windowFlags();
    flags |= Qt::WindowStaysOnTopHint;
    setWindowFlags(flags);
}

void QFits2dFit::paintEvent(QPaintEvent *) {
    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    if (sb != NULL) {
        double  fitx        = 0.,
                fity        = 0.,
                fitw1       = 0.,
                fitw2       = 0.,
                fitangle    = 0.;
        int     x           = savex - 1,
                y           = sb->getImage()->height() - savey,
                imagesize   = 0,
                imageoffset = 0,
                xoff        = 0,
                yoff        = 0;

        if (fitfunction->currentText() == "Gauss") {
            fitx = fitresult[2];
            fity = fitresult[3];
            fitw1 = fitresult[4];
            fitw2 = fitresult[5];
            fitangle = fitresult[6];
        } else if (fitfunction->currentText() == "Sersic") {
            fitx = fitresult[3];
            fity = fitresult[4];
            fitw1 = fitresult[2] * 2.;
            fitw2 = fitresult[2] * fitresult[6] * 2.;
            fitangle = fitresult[5];
        }

        if (zoom > zoomIndex) {
            imagesize = 150 / (zoom - (zoomIndex-1));
        } else if (zoom < zoomIndex) {
            imagesize = 150 * (zoomIndex+1 - zoom);
        } else {
            imagesize = 150;
        }
        if (imagesize % 2) {
            imagesize++;
        }

        QImage subimage = sb->getImage()->copy(x - imagesize / 2, y - imagesize / 2,
                                               imagesize + 1, imagesize + 1);
        if (zoom > zoomIndex) {
            subimage = subimage.scaled(imagesize * (zoom - (zoomIndex-1)),
                                       imagesize*(zoom - (zoomIndex-1)));
        } else if (zoom < zoomIndex) {
            subimage = subimage.scaled(imagesize / (zoomIndex+1-zoom),
                                       imagesize/(zoomIndex+1-zoom));
        }

        imageoffset = (150 - subimage.width());

        QPainter p;
        p.begin(this);
        p.drawImage((width() - 150 + imageoffset) / 2, imageoffset / 2, subimage);
        p.setPen(QColor(0, 200, 0));
        p.translate(width() / 2, 150 / 2);
        if (zoom >= zoomIndex) {
            p.drawRect(-savefitwidth*(zoom - (zoomIndex-1)),
                       -savefitwidth*(zoom - (zoomIndex-1)),
                       (savefitwidth*2+1)*(zoom - (zoomIndex-1)),
                       (savefitwidth*2+1)*(zoom - (zoomIndex-1)));
            p.translate((fitx - savex) * (double)(zoom - (zoomIndex-1)) - 1,
                        -(fity - savey) * (double)(zoom - (zoomIndex-1)));
            p.rotate(-fitangle);
            p.rotate(-sb->getRotation());
            if ((sb->getRotation() == 90) || (sb->getRotation() == 180))
            {
                p.translate(0, -(zoom - (zoomIndex-1))/2);
            }
            if ((sb->getRotation() == 180) || (sb->getRotation() == 270))
            {
                p.translate((zoom - (zoomIndex-1))/2, 0);
            }
            xoff = fitw1 * (zoom - (zoomIndex-1));
            yoff = fitw2 * (zoom - (zoomIndex-1));
        } else if (zoom < zoomIndex) {
            p.drawRect(-savefitwidth/(zoomIndex+1 - zoom),
                       -savefitwidth/(zoomIndex+1 - zoom),
                       (savefitwidth*2+1)/(zoomIndex+1 - zoom),
                       (savefitwidth*2+1)/(zoomIndex+1 - zoom));
            p.translate((fitx - savex) / (double)(zoomIndex+1 - zoom) - 1,
                        -(fity - savey) / (double)(zoomIndex+1 - zoom));
            p.rotate(-fitangle);
            p.rotate(-sb->getRotation());
            xoff = fitw1 / (zoomIndex+1 - zoom);
            yoff = fitw2 / (zoomIndex+1 - zoom);
            if ((sb->getRotation() == 90) || (sb->getRotation() == 180))
            {
                p.translate(0, -(zoomIndex+1 - zoom)/2);
            }
            if ((sb->getRotation() == 180) || (sb->getRotation() == 270)) {
                p.translate((zoomIndex+1 - zoom)/2, 0);
            }
        }
        p.drawEllipse(-(int)(xoff/2.-.5), -(int)(yoff/2.-.5),
                      (int)(xoff+.5), (int)(yoff+.5));
        p.end();
    }
}

void QFits2dFit::resizeEvent(QResizeEvent *e) {
    update();
}

void QFits2dFit::zoomChanged(int value) {
    if (value > 8) zoom = 150 / (value * 2) + 8;
    else if (value > 4) zoom = 15;
    else zoom = 20;

    update();
    refit();
}

void QFits2dFit::fitfunctionChanged(const QString &newfunction) {
    if (newfunction == "Sersic") {
        fitwindow->setMinimum(3);
        slm->show();
        fitslm->show();
    } else {
        fitwindow->setMinimum(2);
        slm->hide();
        fitslm->hide();
    }
    refit();
}

void QFits2dFit::centre(int cx, int cy, int rx, int ry) {
    cenx = rx;
    ceny = ry;
    cencx = cx;
    cency = cy;
}

void QFits2dFit::fitGauss() {
    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    if (sb != NULL) {
        if ((sb->Naxis(1) < 4) || (sb->Naxis(2) < 4)) {
            QMessageBox::information(this, "QFitsView", "Gaussfit needs at least a "
                                           "4 pixel wide image");
            return;
        }
        savex = cencx;
        savey = cency;
        fitx = cenx;
        fity = ceny;
        int maxwidth = sb->Naxis(1);
        if (sb->Naxis(2) < sb->Naxis(1)) {
            maxwidth = sb->Naxis(2);
        }
        fitwindow->setMaximum(maxwidth / 2 - 1);

        refit();
    }
}

void QFits2dFit::refit() {
    int i;

    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    if ((sb != NULL) && (sb->getDpData()->type == typeFits)) {
//        Fits    result;
        QString text1, text2, text3, textPM;
        double  slmvalue = -1.0;
        const char **lab = NULL,
                *labgauss[]  = {"Offset:", "Height:", "Image X:", "Image Y:",
                                "FWHM1:", "FWHM2:", "Angle:" },
                *labmoffat[] = {"Offset:", "Height:", "Power:", "Image X:", "Image Y:",
                                "FWHM1:", "FWHM2:", "Angle:" },
                *labsersic[] = {"Offset:", "Height:", "Re:", "Image X:", "Image Y:",
                                "Angle:", "Diskiness:", "Sersic index:" };

        if (fitslm->isChecked()) {
            slmvalue = slm->value();
        }

        savefitwidth = fitwindow->value();
        if (sb->getDpData()->fvalue->Naxis(3) > 1) {
            if (fitfunction->currentText() == "Gauss") {
                chisq = gauss2dsimplefit(result, *(sb->getCubeDisplay2D()),
                                         fitx, fity, fitwindow->value());
//            } else if (fitfunction->currentText() == "Moffat") {
//                chisq = moffat2dsimplefit(result, *(sb->getCubeDisplay2D()),
//                                          fitx, fity, fitwindow->value());
            } else if (fitfunction->currentText() == "Sersic") {
                chisq = sersic2dsimplefit(result, *(sb->getCubeDisplay2D()),
                                          fitx, fity, fitwindow->value(), slmvalue);
            }
        } else {
            QReadLocker locker(&buffersLock);
            if (fitfunction->currentText() == "Gauss") {
                chisq = gauss2dsimplefit(result, *(sb->getDpData()->fvalue),
                                         fitx, fity, fitwindow->value());
    //        } else if (fitfunction->currentText() == "Moffat") {
    //            chisq = moffat2dsimplefit(result, *(sb->getDpData()->fvalue),
    //                                      fitx, fity, fitwindow->value());
            } else if (fitfunction->currentText() == "Sersic") {
                chisq = sersic2dsimplefit(result, *(sb->getDpData()->fvalue),
                                          fitx, fity, fitwindow->value(), slmvalue);
            }
        }

        for (int i = 0; i < result.Nelements(); i++) {
            fitresult[i] = result.r8data[i];
        }

        if (fitfunction->currentText() == "Gauss") {
            lab = labgauss;
        } else if (fitfunction->currentText() == "Moffat") {
            lab = labmoffat;
        } else if (fitfunction->currentText() == "Sersic") {
            lab = labsersic;
        }

        for (i = 0; i < result.Nelements() / 2; i++) {
            resultlabels[i]->setText(lab[i]);
            fitresults[i]->setResult(result(i+1, 1), result(i+1, 2));
            resultlabels[i]->show();
            fitresults[i]->show();
            text1 += QString(lab[i]) + "\n";
            text2 += QString::number(result.r8data[i], 'g', 5) + "\n";
            textPM += "+-\n";
            text3 += QString::number(result.r8data[i+result.Nelements() / 2], 'g', 3) + "\n";
        }
        if (fitfunction->currentText() == "Gauss") {
            resultlabels[i]->setText("Flux:");
            fitresults[i]->setResult(M_PI * result.r8data[1] *
                    fabs(result.r8data[4] * result.r8data[5]) /
                                    (4.0*log(2.0)), -1);
            resultlabels[i]->show();
            fitresults[i]->show();
            i++;
            text1 += "flux:\n";
            text2 += QString::number(M_PI * result.r8data[1] *
                                     fabs(result.r8data[4] * result.r8data[5]) /
                                                     (4.0*log(2.0)), 'g', 7) + "\n";
        }

        resultlabels[i]->setText("Chisq:");
        fitresults[i]->setResult(chisq, -1);
        resultlabels[i]->show();
        fitresults[i]->show();

        text1 += "chisq:";
        text2 += QString::number(chisq, 'g', 3);

        for (int j = i+1; j < 10; j++) {
            resultlabels[j]->hide();
            fitresults[j]->hide();
        }

//        resultLabel1->setText(text1);
//        resultLabel1->adjustSize();
//        resultLabel2->setText(text2);
//        resultLabel2->adjustSize();
//        resultLabel2->move(resultLabel1->x() + resultLabel1->width() + 5,
//                           resultLabel1->y());
//        resultLabelPM->setText(textPM);
//        resultLabelPM->adjustSize();
//        resultLabelPM->move(resultLabel2->x() + resultLabel2->width() + 5,
//                           resultLabel2->y());
//        resultLabel3->setText(text3);
//        resultLabel3->adjustSize();
//        resultLabel3->move(resultLabelPM->x() + resultLabelPM->width() + 5,
//                           resultLabelPM->y());

// also fit horizontal and vertical cut and show result of FWHM
        Fits xvalues, yvalues, errors;
        double cenx, ceny, fwhmx, fwhmy;
        xvalues.create(fitwindow->value() * 2 + 1, 1);
        for (int i = 0; i < xvalues.Naxis(1); i++) xvalues.r4data[i] = i + 1;
        errors.copy(xvalues);
        errors.mul(0.);
        errors.add(.1);
        Fits estimate;
        estimate.create(4,1,R8);
        text1 = "";

// horizontal
        if (sb->getDpData()->fvalue->Naxis(3) > 1) {
            sb->getCubeDisplay2D()->extractRange(yvalues, fitx-fitwindow->value(), fitx+fitwindow->value(), fity, fity, 1, 1);
        } else {
            sb->getDpData()->fvalue->extractRange(yvalues, fitx-fitwindow->value(), fitx+fitwindow->value(), fity, fity, 1, 1);
        }
        estimate.r8data[0] = yvalues.get_min();
        estimate.r8data[1] = yvalues.get_max() - estimate.r8data[0];
        yvalues.centroid(&cenx, &ceny);
        estimate.r8data[2] = cenx;
        estimate.r8data[3] = 5.;
        text1 += "Horizontal Cut FWHM: ";
        if (gaussfit(estimate, xvalues, yvalues, errors) == -1.0) text1 += "N/A";
        else text1 += QString::number(estimate.r8data[3]);

// vertical
        if (sb->getDpData()->fvalue->Naxis(3) > 1) {
            sb->getCubeDisplay2D()->extractRange(yvalues, fitx, fitx, fity-fitwindow->value(), fity+fitwindow->value(), 1, 1);
        } else {
            sb->getDpData()->fvalue->extractRange(yvalues, fitx, fitx, fity-fitwindow->value(), fity+fitwindow->value(), 1, 1);
        }
        estimate.r8data[0] = yvalues.get_min();
        estimate.r8data[1] = yvalues.get_max() - estimate.r8data[0];
        yvalues.centroid(&cenx, &ceny);
        estimate.r8data[2] = cenx;
        estimate.r8data[3] = 5.;
        text1 += "\nVertical Cut FWHM: ";
        if (gaussfit(estimate, xvalues, yvalues, errors) == -1.0) text1 += "N/A";
        else text1 += QString::number(estimate.r8data[3]);

        resultLabelCuts->setText(text1);
        resultLabelCuts->adjustSize();
//        resultLabelCuts->move(10, resultLabel1->y() + resultLabel1->height() + 10);

        show();
//        raise();
        dynamic_cast<QWidget*>(parent())->show();
        update();

//        resultLabel1->hide();
//        resultLabel2->hide();
//        resultLabel3->hide();
//        resultLabelPM->hide();
    }
}

void QFits2dFit::createFitFunction() {
    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    if (sb != NULL) {
        QString cmd = freeBufferName().c_str();
        cmd += " = ";
        cmd += QString::number(fitresult[0]) + " + ";
        cmd += QString::number(fitresult[1]) + " * ";

        if (fitfunction->currentText() == "Gauss") {
            cmd += "gauss(";
            cmd += QString::number(fitresult[2]) + ", ";
            cmd += QString::number(fitresult[3]) + ", ";
            cmd += QString::number(fitresult[4]) + ", ";
            cmd += QString::number(fitresult[5]) + ", ";
            cmd += QString::number(fitresult[6]) + ", ";
            cmd += "naxis1 = " + QString::number(sb->Naxis(1));
            cmd += ", naxis2 = " + QString::number(sb->Naxis(2));
            cmd += ")";
        } else if (fitfunction->currentText() == "Sersic") {
            cmd += "sersic2d(";
            cmd += QString::number(fitresult[2]) + ", ";
            cmd += QString::number(fitresult[3]) + ", ";
            cmd += QString::number(fitresult[4]) + ", ";
            cmd += QString::number(fitresult[5]) + ", ";
            cmd += QString::number(fitresult[6]) + ", ";
            if (fitslm->isChecked()) {
                cmd += QString::number(slm->value()) + ", ";
            } else {
                cmd += QString::number(fitresult[7]) + ", ";
            }
            cmd += "naxis1 = " + QString::number(sb->Naxis(1));
            cmd += ", naxis2 = " + QString::number(sb->Naxis(2));
            cmd += ")";
        }

        dpuser_widget->executeCommand(cmd);
    }
}

void QFits2dFit::copyFitResult() {
    QString text;
    QStringList labels, values, errors;
    int i, nfit = 7;

    text = "QFitsView 2D Fit\n================\nType,";
//    labels = resultLabel1->text().split("\n");
//    values = resultLabel2->text().split("\n");
//    errors = resultLabel3->text().split("\n");
//    for (i = 0; i < nfit; i++) text += labels.at(i).left(labels.at(i).size()-1) + ",";
    for (i = 0; i < nfit; i++) text += resultlabels[i]->text() + ",";
    if (fitfunction->currentText() == "Sersic") text += "Sersic Index,";
    for (i = 0; i < nfit; i++) {
//        text += "d_" + labels.at(i).left(labels.at(i).size()-1);
        text += "d_" + resultlabels[i]->text();
        if (i < nfit - 1) text += ",";
    }
    if (fitfunction->currentText() == "Sersic") text += ",d_Sersic Index";
    text += ",Chi Squared\n";

    text += fitfunction->currentText() + ",";
//    for (i = 0; i < nfit; i++) text += values.at(i) + ",";
    for (i = 0; i < nfit; i++) text += fitresults[i]->getValue() + ",";
    if (fitfunction->currentText() == "Sersic") {
        if (fitslm->isChecked()) text += QString::number(slm->value()) + ",";
//        else text += values.at(nfit) + ",";
        else text += fitresults[nfit]->getValue() + ",";
    }
    for (i = 0; i < nfit; i++) {
//        text += errors.at(i);
        text += fitresults[i]->getError();
        if (i < nfit - 1) text += ",";
    }
    if (fitfunction->currentText() == "Sersic") {
        text += ",";
        if (fitslm->isChecked()) text += "0";
//        else text += errors.at(nfit);
        else text += fitresults[nfit]->getError();
    }
    text += ",";
    text += QString::number(chisq);
    text += "\n";
    text.remove(':');

    QApplication::clipboard()->setText(text);
}

void QFits2dFit::newBufferFromFitResult() {
//    QString cmd = "view ";
//    cmd += QString(injectVariable(freeBufferName().c_str(), result).c_str());
//    dpuser_widget->executeCommand(cmd);
    QString bufName = QString(freeBufferName().c_str());
    Fits cresult;
    cresult.copy(result);
    if ((fitfunction->currentText() == "Sersic") && (fitslm->isChecked())) {
        cresult.resize(cresult.Naxis(1) + 1, 2);
        cresult.r8data[cresult.Naxis(1)-1] = slm->value();
        cresult.r8data[cresult.Nelements()-1] = 0;
    }
    cresult.extensionType = BINTABLE;
    injectVariable(bufName, cresult);
    fitsMainWindow->dpuserView(bufName.toStdString());
}

void QFits2dFit::passToGalfit() {
    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    if (sb != NULL) {
        fitsMainWindow->galfit->galfitControl->mzero->setText("0.0");
        fitsMainWindow->galfit->galfitControl->cdelt1->setText("1.0");
        fitsMainWindow->galfit->galfitControl->cdelt2->setText("1.0");
        fitsMainWindow->galfit->clearObjects();
        fitsMainWindow->galfit->addSky(fitresult[0]);
        if (fitfunction->currentText() == "Gauss") {
            double mag = -2.5 * log10(M_PI * fitresult[1] *
                    fabs(fitresult[4] * fitresult[5]) /
                                    (4.0*log(2.0)));
            fitsMainWindow->galfit->addGaussian(fitresult[2], fitresult[3], mag, fitresult[4], fitresult[5]/fitresult[4], 90.+fitresult[6]);
        } else if (fitfunction->currentText() == "Sersic") {
            double Ie = fitresult[1];
            double Re = fabs(fitresult[2]);
            dpuserType angle(fitresult[5]), range(360.);
            angle = modulo(angle, range);
            double a = 90. + angle.toDouble();
            if (a < 0.) a += 360.;
            double b = fabs(1. / fitresult[6]);
            double mag = -2.5 * log10(M_PI * fitresult[1] *
                    fabs(fitresult[2] * fitresult[2] * fitresult[6]) /
                                    (4.0*log(2.0)));
        //    mag = fitresult[1];
            double sersic = slm->value();
            if (!(fitslm->isChecked())) sersic = fitresult[7];
            sersic = fabs(sersic);
            mag = -2.5 * log10(Ie * M_PI * pow(b * pow((1./Re), 1./sersic), -2.*sersic) * gsl_sf_gamma(1.+2.*sersic) / (exp(1.) * sqrt(pow(cos(2.*a*M_PI/180.),2.))));
            fitsMainWindow->galfit->addSersic(fitresult[3], fitresult[4], mag, 2. * fitresult[2], sersic, 1. / fitresult[6], a, fitslm->isChecked());
        }
        fitsMainWindow->galfit->updateandshow();
        fitsMainWindow->galfit->galfitControl->xmin->setValue(fitx - fitwindow->value());
        fitsMainWindow->galfit->galfitControl->xmax->setRange(1, sb->Naxis(1));
        fitsMainWindow->galfit->galfitControl->xmax->setValue(fitx + fitwindow->value());
        fitsMainWindow->galfit->galfitControl->ymin->setValue(fity - fitwindow->value());
        fitsMainWindow->galfit->galfitControl->ymax->setRange(1, sb->Naxis(2));
        fitsMainWindow->galfit->galfitControl->ymax->setValue(fity + fitwindow->value());
    }
}
