/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#include "PickedPixelMap.h"
#include <ImageComponent.h>
#include <Log.h>

#include <QFileInfo>
#include <QTextStream>

using namespace camitk;

//-------------------------- Constructor ---------------------
PickedPixelMap::PickedPixelMap(ImageComponent* imageComp) {
    image = imageComp;
    pixelIndexList = new QList<QVector3D>();
    coordIndexList = new QList<QVector3D>();
    realCoordList  = new QList<QVector3D>();
    pixelValueList = new QList<double>();

}

//------------- Destructor -------------
PickedPixelMap::~PickedPixelMap() {
    if (pixelIndexList != nullptr) {
        delete pixelIndexList;
    }
    if (coordIndexList != nullptr) {
        delete coordIndexList;
    }
    if (realCoordList != nullptr) {
        delete realCoordList;
    }
    if (pixelValueList != nullptr) {
        delete pixelValueList;
    }
}

//---------------- addPixel --------------------
void PickedPixelMap::addPixel() {
    int whereToInsert = pixelIndexList->size();

    // get the last picked pixel index
    int i, j, k;
    image->getLastPixelPicked(&i, &j, &k);

    // check validity
    if (i != -1 && j != -1 && k != -1) {
        // If the point is actually within the image
        QVector3D lastPoint = QVector3D(i, j, k);

        //insert the new point in the list
        pixelIndexList->insert(whereToInsert, lastPoint);

        double x, y, z;
        image->getLastPointPickedDataFrame(&x, &y, &z);
        lastPoint = QVector3D(x, y, z);
        coordIndexList->insert(whereToInsert, lastPoint);

        image->getLastPointPickedWorldFrame(&x, &y, &z);
        lastPoint = QVector3D(x, y, z);
        realCoordList->insert(whereToInsert, lastPoint);

        // We consider here only gray level images, so we take the first component.
        double value = image->getImageData()->GetScalarComponentAsDouble(i, j, k, 0);
        pixelValueList->insert(whereToInsert, value);

    }
}

//-------------------- getCoordIndexList -----------------------
QList<QVector3D>* PickedPixelMap::getCoordIndexList() {
    return coordIndexList;
}

QList<double>* PickedPixelMap::getPixelValueList() {
    return pixelValueList;
}

//----------------------- getCoordIndexList --------------------
QList<QVector3D>* PickedPixelMap::getPixelIndexList() {
    return pixelIndexList;
}

//----------------------- getRealWorldList --------------------
QList<QVector3D>* PickedPixelMap::getRealWorldList() {
    return realCoordList;
}

//-------------- modifyPixel -----------------------------------
void PickedPixelMap::modifyPixel(int index) {
    if ((index >= 0) && (index < pixelIndexList->size())) {
        // get the last picked pixel index
        int i, j, k;
        image->getLastPixelPicked(&i, &j, &k);

        // check validity
        if (i != -1 && j != -1 && k != -1) {
            // If the point is actually within the image
            QVector3D lastPoint = QVector3D(i, j, k);

            //replace the new point in the list
            pixelIndexList->replace(index, lastPoint);

            double x, y, z;
            image->getLastPointPickedDataFrame(&x, &y, &z);
            lastPoint = QVector3D(x, y, z);
            coordIndexList->replace(index, lastPoint);

            image->getLastPointPickedWorldFrame(&x, &y, &z);
            realCoordList->replace(index, lastPoint);

            // We consider here only gray level images, so we take the first component.
            double value = image->getImageData()->GetScalarComponentAsDouble(i, j, k, 0);
            pixelValueList->replace(index, value);

        }
    }

}

//------------------ removePixel ----------------------------
void PickedPixelMap::removePixel(int index) {
    if (index >= 0 && index < pixelIndexList->size()) {
        pixelIndexList->removeAt(index);
        coordIndexList->removeAt(index);
        realCoordList->removeAt(index);
        pixelValueList->removeAt(index);
    }
}

//------------------ savePixelList ---------------------
void PickedPixelMap::savePixelList(QString fileName) {
    //-- prepare filename (add .csv if needed)
    QFileInfo fileNameInfo(fileName);

    if (fileNameInfo.suffix() != "csv") {
        fileName += ".csv";
    }

    // write the points in a csv file
    // the form is : index (int) | i (int) | j (int) | k (int) | x (double) | y (double) | z (double) |
    std::ofstream myFile;

    // open the file to write
    char separator = ',';
    myFile.open(fileName.toStdString().c_str());
    myFile << "index" << separator << "i" << separator << "j" << separator << "k" << separator << "x" << separator << "y" << separator << "z" << separator << "rx" << separator << "ry" << separator << "rz" << separator << "val" << endl;

    if (pixelIndexList != nullptr) {
        for (int idx = 0; idx < pixelIndexList->size(); idx++) {
            myFile << idx << separator;
            // Pixel Index
            myFile << pixelIndexList->value(idx).x() << separator;
            myFile << pixelIndexList->value(idx).y() << separator;
            myFile << pixelIndexList->value(idx).z() << separator;

            // Image Coords
            myFile << coordIndexList->value(idx).x() << separator;
            myFile << coordIndexList->value(idx).y() << separator;
            myFile << coordIndexList->value(idx).z() << separator;

            // Real Coords
            myFile << realCoordList->value(idx).x() << separator;
            myFile << realCoordList->value(idx).y() << separator;
            myFile << realCoordList->value(idx).z() << separator;

            // Value
            myFile << pixelValueList->value(idx) << endl;

        }

    }

    // close after
    myFile.close();
}

//----------------- openPixelList -------------------
void PickedPixelMap::openPixelList(QString fileName) {

    // Read the input file
    QFile file(fileName);

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        CAMITK_WARNING_ALT(tr("Could not open file \"%1\".").arg(fileName))
        return;
    }

    QTextStream in(&file);

    resetPixelList();

    while (! in.atEnd()) {
        int i, j, k;
        double x, y, z;
        double rx, ry, rz;
        double val;

        // We process the file line by line
        QString line = in.readLine();

        if (! line.isEmpty()) {
            QStringList liste = line.split(",");
            QString s = liste.at(0);

            if ((s != QString("index")) && (liste.size() == 11)) {
                s = liste.at(1);
                i = s.toInt();
                s = liste.at(2);
                j = s.toInt();
                s = liste.at(3);
                k = s.toInt();
                s = liste.at(4);
                x = s.toDouble();
                s = liste.at(5);
                y = s.toDouble();
                s = liste.at(6);
                z = s.toDouble();
                s = liste.at(7);
                rx = s.toDouble();
                s = liste.at(8);
                ry = s.toDouble();
                s = liste.at(9);
                rz = s.toDouble();
                s = liste.at(10);
                val = s.toDouble();

                //insert the new points in the list
                int whereToInsert = pixelIndexList->size();
                pixelIndexList->insert(whereToInsert, QVector3D(i, j, k));
                coordIndexList->insert(whereToInsert, QVector3D(x, y, z));
                realCoordList->insert(whereToInsert, QVector3D(rx, ry, rz));
                pixelValueList->insert(whereToInsert, val);
            }
        }
    }
}


//-----------------getImage-------------------
ImageComponent* PickedPixelMap::getImage() {
    return image;
}

//----------------- resetPixelList -------------------
void PickedPixelMap::resetPixelList() {
    pixelIndexList->clear();
    coordIndexList->clear();
    realCoordList->clear();
    pixelValueList->clear();
}

