/*
    libodsstream is a library to read and write ODS documents as streams
    Copyright (C) 2017  Olivier Langella <Olivier.Langella@moulon.inra.fr>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
/**
 * \file ods2csv.cpp
 * \date 12/1/2017
 * \author Olivier Langella
 * \brief convert ods files to TSV
 */

#include "ods2csv.h"
#include "config.h"
#include <QCommandLineParser>
#include <QDateTime>
#include <QTimer>
#include <QFile>
#include <QFileInfo>
#include <odsstream/odsdocreader.h>
#include <odsstream/odsexception.h>
#include <odsstream/tsvdirectorywriter.h>

class CustomHandler: public OdsDocHandlerInterface
{
public:
    CustomHandler(QFileInfo & fi) {
        _p_writer = new TsvDirectoryWriter(QDir(QString("%1.d").arg(fi.completeBaseName())));
    }

    ~CustomHandler() {
        delete _p_writer;
    }

    /**
     * callback that indicates the begining of a data sheet. Override it in
     * order to retrieve information about the current data sheet.
     *
     */
    virtual void startSheet(const QString & sheet_name)  {
        _p_writer-> writeSheet(sheet_name);
    } ;

    /**
    * callback that indicates the end of the current data sheet. Override it if
    * needed
    */
    virtual void endSheet()  {
        //_p_writer-> endSheet();
    } ;

    /**
     * callback that indicates a new line start. Override it if needed.
     */

    virtual void startLine() {
        //_p_writer-> writeLine();
    } ;

    /**
     * callback that indicates a line ending. Override it if needed.
     */

    virtual void endLine()  {
        _p_writer-> writeLine();
    } ;

    /**
     * callback that report the content of the current cell in a dedicated Cell
     * object. Override it if you need to retrieve cell content.
     */
    virtual void setCell(const OdsCell & cell)  {
        qDebug() << "CustomHandler::setCell " << cell.toString();
        if (cell.isBoolean()) {
            _p_writer-> writeCell(cell.getBooleanValue());
        } else if (cell.isDate()) {
            _p_writer-> writeCell(cell.getDateTimeValue());
        } else if (cell.isDouble()) {
            _p_writer-> writeCell(cell.getDoubleValue());
        } else if (cell.isEmpty()) {
            _p_writer-> writeEmptyCell();
        } else {
            _p_writer-> writeCell(cell.toString());
        }
    } ;

    /**
     * callback that report the end of the ODS document. Override it if you need
     * to know that reading is finished.
     */
    virtual void endDocument() {
        _p_writer-> close();
    } ;

private :
    TsvDirectoryWriter * _p_writer;
};

Ods2Csv::Ods2Csv(QObject *parent) :
    QObject(parent)
{
    // get the instance of the main application
    app = QCoreApplication::instance();
    // setup everything here
    // create any global objects
    // setup debug and warning mode
}

// 10ms after the application starts this method will run
// all QT messaging is running at this point so threads, signals and slots
// will all work as expected.
void Ods2Csv::run()
{

    QTextStream errorStream(stderr, QIODevice::WriteOnly);

    try {
        qDebug() << "Ods2Csv::run() begin";
        QCommandLineParser parser;

        //throw pappso::PappsoException("test");
        parser.setApplicationDescription(QString(SOFTWARE_NAME).append(" ").append(LIBODSSTREAM_VERSION));
        parser.addHelpOption();
        parser.addVersionOption();
        parser.addPositionalArgument("ODS files", QCoreApplication::translate("main", "ODS file to convert."));

        qDebug() << "Ods2Csv::run() 1";

        // Process the actual command line arguments given by the user
        parser.process(*app);

        // QCoreApplication * app(this);
        // Add your main code here
        qDebug() << "Ods2Csv.Run is executing";

        const QDateTime dt_begin = QDateTime::currentDateTime();
        const QStringList args = parser.positionalArguments();


        QStringList ods_list = parser.positionalArguments();
        for (QString & ods_file:ods_list) {
            QFileInfo fi(ods_file);
            if (!fi.exists()) {
                throw OdsException(QObject::tr("file %1 does not exists").arg(fi.absoluteFilePath()));
            }
            QFile file(ods_file);
            CustomHandler handler(fi);
            OdsDocReader reader(handler);
            reader.parse(&file);
            file.close();
        }


    }
    catch (OdsException & error) {
        errorStream << "Oops! an error occurred in Ods2Csv. Dont Panic :" << endl;
        errorStream << error.qwhat() << endl;
        exit(1);
        app->exit(1);
    }

    catch (std::exception& error)
    {
        errorStream << "Oops! an error occurred in Ods2Csv. Dont Panic :" << endl;
        errorStream << error.what() << endl;
        exit(1);
        app->exit(1);
    }


    // you must call quit when complete or the program will stay in the
    // messaging loop
    quit();
}

// call this routine to quit the application
void Ods2Csv::quit()
{
    // you can do some cleanup here
    // then do emit finished to signal CoreApplication to quit
    emit finished();
}

// shortly after quit is called the CoreApplication will signal this routine
// this is a good place to delete any objects that were created in the
// constructor and/or to stop any threads
void Ods2Csv::aboutToQuitApp()
{
    // stop threads
    // sleep(1);   // wait for threads to stop.
    // delete any objects
}


int main(int argc, char **argv)
{
    //QTextStream consoleErr(stderr);
    //QTextStream consoleOut(stdout, QIODevice::WriteOnly);
    //ConsoleOut::setCout(new QTextStream(stdout, QIODevice::WriteOnly));
    //ConsoleOut::setCerr(new QTextStream(stderr, QIODevice::WriteOnly));
    qDebug() << "main begin";
    QCoreApplication app(argc, argv);
    qDebug() << "main 1";
    QCoreApplication::setApplicationName("ods2tsv");
    QCoreApplication::setApplicationVersion(LIBODSSTREAM_VERSION);
    QLocale::setDefault(QLocale::system());

    // create the main class
    Ods2Csv myMain;
    // connect up the signals
    QObject::connect(&myMain, SIGNAL(finished()),
                     &app, SLOT(quit()));
    QObject::connect(&app, SIGNAL(aboutToQuit()),
                     &myMain, SLOT(aboutToQuitApp()));
    qDebug() << "main 2";


    // This code will start the messaging engine in QT and in
    // 10ms it will start the execution in the MainClass.run routine;
    QTimer::singleShot(10, &myMain, SLOT(run()));
    return app.exec();
}
