// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | bytran@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// Version 1.0 Release information
// Release history (Android), Version 5.6.1-1 of Qt was used to compile the software under Android to keep older interface:
//      Version 1.0 Alpha for Android uploaded to GooglePlay on May 16, 2016.
//      Version 1.0 Beta for Android uploaded to GooglePlay on May 31, 2016, submitted to production (publicly available) on Google Play on June 4, 2016
//      Version 1.0 for Android released on Google Play on July 4, 2016
// Release history (iOS):
//      Didn't record when the application was first tested on an iOS device (Alpha testing)
//      Version 1.0 Beta for iOS first submitted to AppStore on August 3, 2016 as a Beta TestFlight
//      Version 1.0 Beta for iOS published to the App Store on September 30, 2016
// Release history (WinRT, Windows Phone):
//      Version 1.0 Alpha for Windows Phone (WinRT) first tested on a Windows phone device on August 11, 2016.
//      Version 1.0 Beta for Windows Phone (WinRT) first uploaded to the Windows App Store on September 14, 2016
// Release history (Windows):
//      Version 1.0 Alpha for Windows first made available as a ZIP file on May 26, 2016
//      Version 1.0 Beta made available as a ZIP file on June 13, 2016
//      Version 1.0 made available as a ZIP file on August 1, 2016
// Release history (OS X):
//      Version 1.0 Alpha for OS X released as a DMG archive on June 10, 2016
//      Version 1.0 Beta for OS X released as a DMG archive on June 13, 2016
//      Version 1.0 for OS X released as a DMG archive on September 23, 2016
// Release history (Linux):
//      Version 1.0 Alpha for Linux first made available as a TAR archive on June 10, 2016
//      Version 1.0 Beta for Linux released as a TAR archive on June 13, 2016
//      Version 1.0 released as a TAR archive on September 8, 2016
// Source code release history:
//      Version 1.0 Beta placed online on September 16, 2016
//
// Version 1.1 Release information
// Release history for Android (Qt 5.9.1 used), iOS (Qt 5.7.1 used), and Windows Phone (Qt 5.7.1 used)
//      Version 1.1 submitted to the app stores on July 10, 2017 for all 3 platforms
// Release history for Windows (Qt 5.9.1 used) and Mac (Qt 5.7.1 used)
//      Version 1.1 for Windows and Mac placed online on July 11, 2017
// Release history for Linux (Qt 5.9.0 Beta 3 used)
//      Version 1.1 for Linux placed online on July 13, 2017
// Source code release history:
//      Version 1.1 placed online on July 14, 2017
//
// Version 1.2 Release information
// Released April - May, 2018 (Qt usage is now maintained at a separate ChangeLog web page)
//
// Version 1.3 Release information
// Released September 14 through 20, 2018 depending on platform (See the ChangeLog webpage for Qt version usage)
//
// The bytran logo is distributed under the Creative Commons 3.0 Attribution License: https://creativecommons.org/licenses/by/3.0/us/
//
//
// 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.



// #include <QGuiApplication>  // http://www.qtcentre.org/threads/60203-QApplication-QGuiApplication-and-QCoreApplication
#include <QApplication>        // Using QWidgets because the plot is currently plotted using QWidget, maybe could replace this in the future
#include <QQmlApplicationEngine>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include <QSplashScreen>
#include <QTimer>
#include <QFontDatabase>
#include "aboutqml.h"
#include "atmospherelistviewmodel.h"
#include "bluetoothlistviewmodel.h"
#include "bytrancore.h"
#include "colorplot.h"
#include "hitrandownloadoptionsqml.h"
#include "instrumentfunctionqml.h"
#include "lineoptionsqml.h"
#include "mollistviewmodel.h"
#include "mollistviewreducedmodel.h"
#include "notifierqml.h"
#include "pathlengthqml.h"
#include "plot.h"
#include "remotecontrolqml.h"
#include "sensorsqml.h"
#include "serialportqml.h"
#include "serialportslistmodel.h"
#include "shareresultsqml.h"
#include "spectraresultsqml.h"
#include "spectrum.h"
#include "temperatureqml.h"
#include "totalpressqml.h"
#include "wavelengthqml.h"
#include "yaxis.h"
#include "yaxisqml.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);  // A the application creation time this was a QGuiApplication

    // Registering type for plotting the results of the calculations
    qmlRegisterType<Plot>("Plot", 1, 0, "Plot");
    qmlRegisterType<ColorPlot>("ColorPlot", 1, 0, "ColorPlot");
    qRegisterMetaType<Spectrum>("Spectrum");

    // Setting the application name
    app.setApplicationName("bytran");

    // Initializing the Core calculation class
    BytranCore *core;
    core = new BytranCore();

    #ifdef QT_SENSEHAT_LIB  // This is only when the compilation is done for the Raspberry Pi (Sense HAT library is then also linked), see the PRO file for the conditional include statements)
            QString fontPath = ":/fonts/DejaVuSans.ttf";
            int fontId;
            fontId = QFontDatabase::addApplicationFont(fontPath);
            if (fontId != -1)
            {
                QFont font("DejaVuSans");
                app.setFont(font);
            }
    #endif

    // Need to adjust font for the iOS (Maybe remove this approach completely and adjust the interface on the main page the same way as in the modal dialogs)
    #if defined(Q_OS_IOS)

        QFont font;
        font = app.font();
        int fontSize = font.pointSize();

        // This adjustment is for the iOS case only (to make the components fit within the device screen)
        if (core->iPhone())
        {
            // iPhone is a bit smaller in size than iPad
            fontSize = fontSize - 4;
        }
        else
        {
            // iPad text is a little larger in size
            fontSize = fontSize - 1;
        }

        // Font adjustment for the iPhone and iPad
        font.setPointSize(fontSize);
        app.setFont(font);

    #endif 

    // Initializing objects used to interatc between C++ code and the QML
    AboutQml *aboutQml;
        aboutQml = new AboutQml(nullptr, core);
    AtmosphereListViewModel *atmListViewModel;
        atmListViewModel = new AtmosphereListViewModel(nullptr, core);
    HitranDownloadOptionsQml *hitranDownloadOptionsQml;
        hitranDownloadOptionsQml = new HitranDownloadOptionsQml(nullptr, core);
    InstrumentFunctionQml *instrFunctQml;
        instrFunctQml = new InstrumentFunctionQml(nullptr, core);
    LineOptionsQml *lineOptQml;
        lineOptQml = new LineOptionsQml(nullptr, core);
    MolListViewModel *moleculesModel;
        moleculesModel = new MolListViewModel(nullptr, core);
    MolListViewReducedModel *moleculesReducedModel;
        moleculesReducedModel = new MolListViewReducedModel(nullptr, core);
    NotifierQml *notifyQml;
        notifyQml = new NotifierQml(nullptr, core);
    PathlengthQml *pathlengthQml;
        pathlengthQml = new PathlengthQml(nullptr, core);
    RemoteControlQml *remoteControlQml;
        remoteControlQml = new RemoteControlQml(nullptr, core->getRemoteControl());
    BluetoothListViewModel *remoteControlBluetoothListModel;
        remoteControlBluetoothListModel = new BluetoothListViewModel(nullptr, core->getRemoteControl()->getBluetooth()->getBluetoothDevicesDiscover());
    SerialPortQml *serialPortQml;
        serialPortQml = new SerialPortQml(nullptr, core);
    SerialPortsListModel *serialPortsListModel;
        serialPortsListModel = new SerialPortsListModel(nullptr, core);
    SensorsQml *sensorsQml;
        sensorsQml = new SensorsQml(nullptr, core);
    BluetoothListViewModel *sensorTagBluetoothListModel;
        sensorTagBluetoothListModel = new BluetoothListViewModel(nullptr, core->getSensors()->getSensorTag()->getBluetooth()->getBluetoothDevicesDiscover());
    ShareResultsQml *shareResultsQml;
        shareResultsQml = new ShareResultsQml(nullptr, core);
    TemperatureQml *tempQml;
        tempQml = new TemperatureQml(nullptr, core);
    TotalPressQml *totalPressQml;
        totalPressQml = new TotalPressQml(nullptr, core);
    WavelengthQml *wlQml;
        wlQml = new WavelengthQml(nullptr, core);
    YAxisQml *yaxisQml;
        yaxisQml = new YAxisQml(nullptr, core);
    SpectraResultsQml *specResultsQml;
        specResultsQml = new SpectraResultsQml(nullptr, core);

    // Registering the initialized classes with the QML
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("coreObj", core);          // Core calculation object used to invoke calculations etc.
    engine.rootContext()->setContextProperty("aboutQml", aboutQml);     // Data object to open a link to the bytran website
    engine.rootContext()->setContextProperty("atmListViewModel", atmListViewModel);     // Linking the atmospehric model QML components with the C++ data objects
    engine.rootContext()->setContextProperty("hitranDownloadOptionsQml", hitranDownloadOptionsQml);     // Object to interface the C++ objects realated to the HITRAN use with the QML interface
    engine.rootContext()->setContextProperty("instrFunctQml", instrFunctQml);           // Object interfaces C++ with QML to change the selected instrument function and related paramters
    engine.rootContext()->setContextProperty("lineOptQml", lineOptQml);                 // Linking line options QML interface component with the C++ code
    engine.rootContext()->setContextProperty("molListViewModel", moleculesModel);       // This is done to register the model component for the molecules QML "window"
    engine.rootContext()->setContextProperty("molListViewReducedModel", moleculesReducedModel);         // This is done to register the model component for the molecules QML "window"
    engine.rootContext()->setContextProperty("notifyQml", notifyQml);                   // Object to display notification messages by interfacing C++ with QML
    engine.rootContext()->setContextProperty("pathlengthQml", pathlengthQml);           // This is done to register the pathlength data object with the corresponding QML interface component
    engine.rootContext()->setContextProperty("remoteControlQml", remoteControlQml);     // Object to interface with the remote control QML component and the corresponding C++ class
    engine.rootContext()->setContextProperty("remoteControlBluetoothListModel", remoteControlBluetoothListModel);   // Object to provide a list of available bluetooth devices to the QML interface
    engine.rootContext()->setContextProperty("serialPortQml", serialPortQml);           // Object to interface the QML with the serial port configuration C++ code
    engine.rootContext()->setContextProperty("serialPortListModel", serialPortsListModel);     // Registering the model component to display a list of available COM ports
    engine.rootContext()->setContextProperty("sensorsQml", sensorsQml);             // Data object to interface QML with the sensors C++ class
    engine.rootContext()->setContextProperty("sensorTagBluetoothListModel", sensorTagBluetoothListModel);    // Object to provide a list of available bluetooth devices to connect to the SensorTag device
    engine.rootContext()->setContextProperty("shareResultsQml", shareResultsQml);   // Object linking the QML component for saving the results with the core C++ component classes performing calculations and data saving
    engine.rootContext()->setContextProperty("tempQml", tempQml);                   // Linking the temperature QML component with the C++ object
    engine.rootContext()->setContextProperty("totalPressQml", totalPressQml);       // Linking C++ classes for the total pressure interface components with the QML interface to be used for total pressure specification
    engine.rootContext()->setContextProperty("wlQml", wlQml);                       // Linking the wavelengths QML interface component with the C++ code
    engine.rootContext()->setContextProperty("yAxisQml", yaxisQml);                 // Object to change the vertical scale boundaries (minimum to maximum)
    engine.rootContext()->setContextProperty("specResultsQml", specResultsQml);     // Object to enable internaction between the core class and the spectrum plot

    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    return app.exec();
}
