// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | contact@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// Share results methods (Android and iOS) are based on the tutorial and code Copyrighted (c) 2014 Nicolas Froment
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
//
// The MIT License (MIT)
// Copyright (c) 2016 Dzianis Pliutau
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



// Object linking the Data save QML component with the core calculation components
// This has to use platform specific implementations (Android or iOS etc.)
#include "shareresultsdataobject.h"
#include <QDesktopServices>
#include <QApplication>
#include <QMessageBox>
#include <QString>
#include <QStringList>
#include <QFileDialog>

#ifdef Q_OS_ANDROID
    #include <QAndroidJniObject>
    #include <QAndroidJniEnvironment>
#endif

ShareResultsDataObject::ShareResultsDataObject(QObject *parent, BytranCore *inCore) : QObject(parent)
{
    // Passing a reference to the core object into the internal variable
    core = inCore;

    // Setting default parameters
    m_attachImage = true;
    m_attachDataFile = false;
    m_shareResults = false;

    // Method to create actions
    createActions();

    // Object to share results of the calculations on the iOS platform (iOS only)
    #if defined(Q_OS_IOS)
        iosShareDataAndText = new iosShare();
    #endif

    // Save is not in progess at the beginning
    saveInProgress = false;
}

// Method to create actions
void ShareResultsDataObject::createActions()
{
    connect(this->core->getResultsSaver(), SIGNAL(savingFilesToDiskComplete()), this, SLOT(fileSavedToDisk()));
    connect(this->core->getResultsSaver(), SIGNAL(saveConfigToDocuments(QString)), this, SLOT(saveConfigForSharing(QString)));
}

// Slot to save the configuration file for sharing
void ShareResultsDataObject::saveConfigForSharing(QString path)
{
    QString savedPath;

    savedPath = this->core->getConfigIO()->getConfigFilePath();
    this->core->getConfigIO()->setConfigFilePath(path);
    this->core->getConfigIO()->saveToConfig();
    this->core->getConfigIO()->setConfigFilePath(savedPath);
}

// Informting the QML components that file writing is complete
void ShareResultsDataObject::fileSavedToDisk()
{
    // This is to notify the QML that file writing has finished
    emit fileWritingCompleteChanged();
    saveInProgress = false;
}

// Invocable method to save the results of the calculations to the Documents folder
void ShareResultsDataObject::saveToDocuments()
{
    QString message;

    if (saveInProgress == false)
    {
        saveInProgress = true;
        if (core->getHorizSpectra()->getComp()->getY()->count() > 0)
        {
            #if defined(Q_OS_ANDROID)
                message = "Saving data and image\ncurrently displayed and\nnon-zero in current scale\n( > 1 vertical axis pixel )\ndate and time stamped\nto 'Documents/bytran'";
            #else
                message = "Saving data and image\ncurrently displayed and\nnon-zero in current scale\n( > 1 vertical axis pixel )\ndate and time stamped\nto the internal app folder";
            #endif

            core->displayNotification(message, 0, true, false);
            QApplication::processEvents();

            // Getting the file names and the top string generated
            core->getResultsSaver()->generateFilePathsAndTopString();

            // Setting the top string
            m_topString = core->getResultsSaver()->getTopString();
            emit topStringChanged();

            // Changing the path where an image is to be saved to (main plot)
            m_saveImage = core->getResultsSaver()->getImageFilePath();
            emit saveImageChanged();

            // Saving of the text file is carried out through a timer and a signal / slot connection
        }
        else
        {
            core->displayOkDialog("No calculation has been performed.\nThere are no data to save.\n");
        }
    }
}

// Share results methods are based on the tutorial and code Copyrighted (c) 2014 Nicolas Froment - http://blog.lasconic.com/share-on-ios-and-android-using-qml/
// Other resources were used as well but were less helpful:
// http://stackoverflow.com/questions/27094100/how-to-use-qandroidjniobject-to-call-java-code-from-inside-qt
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
// http://www.kdab.com/qt-android-episode-5/
// http://stackoverflow.com/questions/2264622/android-multiple-email-attachment-using-intent-question
// https://amin-ahmadi.com/2015/12/07/how-to-mix-c-and-java-code-in-qt-for-android/
void ShareResultsDataObject::shareImageAndText()
{
    // Only initiating the share if the user has chosen for the sahring to be performed
    if (m_shareResults == true) {

        #if defined(Q_OS_IOS)  // Sharing the results under the iOS

            QString imagePath;
            QString textPath;

            // Setting the image path
            imagePath = "";
            if (this->m_attachImage) { imagePath = this->m_saveImage; }

            // Setting the text path
            textPath = "";
            if (this->m_attachDataFile) { textPath = core->getResultsSaver()->getTextFilePath(); }

            // Sharing the results of the calculations (image and text on the iOS platform)
            iosShareDataAndText->share(imagePath, textPath, core->getResultsSaver()->getConfigFilePath());

        #elif defined(Q_OS_ANDROID)  // Sharing the results under Android

            // Sharing image and data
            QAndroidJniObject jImagePath;
            QAndroidJniObject jTextPath;
            QAndroidJniObject jConfigPath;

            if (this->m_attachImage) { jImagePath = QAndroidJniObject::fromString(this->m_saveImage); }
                                else { jImagePath = QAndroidJniObject::fromString(""); }

            if (this->m_attachDataFile)
            {
                jTextPath = QAndroidJniObject::fromString(core->getResultsSaver()->getTextFilePath());
                jConfigPath = QAndroidJniObject::fromString(core->getResultsSaver()->getConfigFilePath());
            }
            else
            {
                jTextPath = QAndroidJniObject::fromString("");
                jConfigPath = QAndroidJniObject::fromString("");
            }

            QAndroidJniObject::callStaticMethod<void>(
                "org/bytran/bytran/ShareIntent",            // Class
                "share",                                    // Method name
                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",  // Method signature
                jImagePath.object<jstring>(),
                jTextPath.object<jstring>(),
                jConfigPath.object<jstring>()
            );

            QAndroidJniEnvironment env;
            if (env->ExceptionCheck()) {
                // Handle exception here.
                env->ExceptionClear();
            }

        #elif defined(Q_OS_WINPHONE)  // Sharing the results under Windows Phone (WinRT)


        #endif
    }
}

// Methods to get and set the save image path
QString ShareResultsDataObject::saveImage() const
{
    return this->m_saveImage;
}
void ShareResultsDataObject::setSaveImage(const QString &saveImage)
{
    if (saveImage != m_saveImage)
    {
        this->m_saveImage = saveImage;
        emit saveImageChanged();
    }
}

// Methods to get and set the top string with the information about the total pressure, pathlegth and temperature
QString ShareResultsDataObject::topString() const { return this->m_topString; }
void ShareResultsDataObject::setTopString(const QString &topString)
{
    if (topString != m_topString)
    {
        m_topString = topString;
        emit topStringChanged();
    }
}

// Methods to get and set values indicating if an image file is to be attached to the share message
bool ShareResultsDataObject::attachImage() const { return this->m_attachImage; }
void ShareResultsDataObject::setAttachImage(const bool attachImage)
{
    if (attachImage != m_attachImage)
    {
        m_attachImage = attachImage;
        emit attachImageChanged();
    }
}

// Methods to get and set the values indicating if a data file is to be attached to the share message
bool ShareResultsDataObject::attachDataFile() const { return this->m_attachDataFile; }
void ShareResultsDataObject::setAttachDataFile(const bool attachDataFile)
{
    if (attachDataFile != m_attachDataFile)
    {
        m_attachDataFile = attachDataFile;
        emit attachDataFileChanged();
    }
}

// Method to set a variable indicating if the results need to be shared after they have been saved to the local storage
bool ShareResultsDataObject::shareResults() const { return this->m_shareResults; }
void ShareResultsDataObject::setShareResults(const bool &shareResults)
{
    if (shareResults != m_shareResults)
    {
        m_shareResults = shareResults;
        emit shareResultsChanged();
    }
}

// Method to expose the state of the data available valriable
bool ShareResultsDataObject::dataAvailable() const { return (core->getHorizSpectra()->getComp()->getY()->count() > 0); }

// Methods to get and set the state when file writing is complete (this could be implemented in a different was as aprameter passing is not needed)
bool ShareResultsDataObject::fileWritingComplete() const { return this->m_fileWritingComplete; }
void ShareResultsDataObject::setFileWritingComplete(const bool &fileWritingComplete)
{
    if (fileWritingComplete != m_fileWritingComplete)
    {
        m_fileWritingComplete = fileWritingComplete;
        emit fileWritingCompleteChanged();
    }
}

// Method to let the user know that no data is available for saving
void ShareResultsDataObject::showNoDataAlert()
{
    core->displayOkDialog("No calculation has been performed.\nThere are no data to save.");
}
