/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include "LogLoadWidget.hpp"

#include <stdexcept>

#include <QDateTime>
#include <QElapsedTimer>
#include <QFileDialog>
#include <QFileInfo>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QSortFilterProxyModel>
#include <QSplitter>
#include <QStackedWidget>
#include <QTableView>
#include <QTextBrowser>
#include <QTimer>
#include <QToolBox>
#include <QToolButton>
#include <QTreeView>
#include <QVBoxLayout>
#include <QtGlobal>

#include "FileInfoLabel.hpp"
#include "LogLoadView.hpp"
#include "LogModel.hpp"
#include "ServerHandler.hpp"
#include "SuiteFilter.hpp"
#include "TextFormat.hpp"
#include "TimelinePreLoadDialog.hpp"
#include "UIDebug.hpp"
#include "UiLog.hpp"
#include "VConfig.hpp"
#include "VFileInfo.hpp"
#include "VFileTransfer.hpp"
#include "VSettings.hpp"
#include "ViewerUtil.hpp"
#include "ecflow/core/File.hpp"
#include "ecflow/core/File_r.hpp"
#include "ecflow/core/NodePath.hpp"
#include "ecflow/core/Str.hpp"
#include "ui_LogLoadWidget.h"

#define UI_LOGLOADWIDGET_DEBUG_

//=======================================================
//
// LogLoadWidget
//
//=======================================================

LogLoadWidget::LogLoadWidget(QWidget* /*parent*/) : ui_(new Ui::LogLoadWidget) {
    ui_->setupUi(this);

    // message label
    ui_->messageLabel->hide();

    connect(ui_->messageLabel, SIGNAL(loadStoppedByButton()), this, SLOT(slotCancelFileTransfer()));

    // Chart views
    viewHandler_ = new LogRequestViewHandler(this);
    for (int i = 0; i < viewHandler_->tabItems().count(); i++) {
        ui_->viewTab->addTab(viewHandler_->tabItems()[i], " h");
    }

    connect(
        viewHandler_->data(), SIGNAL(loadProgress(size_t, size_t)), this, SLOT(slotLogLoadProgress(size_t, size_t)));

    ui_->viewTab->setTabText(0, tr("Total charts"));
    ui_->viewTab->setTabText(1, tr("Other charts"));
    ui_->viewTab->setTabText(2, tr("Tables"));

    ui_->viewTab->setCurrentIndex(0);

    // TODO: the  period selection widgets are yet to be fully implemented.
    // At the moment, we just hide them and show the current period in a label.
    ui_->startTe->hide();
    ui_->endTe->hide();
    ui_->startLabel->hide();
    ui_->endLabel->hide();
    ui_->viewTab->setCornerWidget(ui_->cornerW);
    ui_->cornerHolderW->setVisible(false);

    ui_->timeLabel->setProperty("fileInfo", "1");
    ui_->timeLabel->setMargin(2);
    ui_->timeLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    ui_->timeLabel->setAutoFillBackground(true);
    ui_->timeLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard |
                                            Qt::TextSelectableByMouse);

    connect(ui_->showFullTb, SIGNAL(clicked()), viewHandler_, SLOT(showFullRange()));

    // Temporal resolution combo box
    ui_->resCombo->addItem("seconds", 0);
    ui_->resCombo->addItem("minutes", 1);
    ui_->resCombo->addItem("hours", 2);

    connect(ui_->resCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(resolutionChanged(int)));

    // Log contents
    logModel_ = new LogModel(this);

    ui_->logView->setProperty("log", "1");
    ui_->logView->setProperty("log", "1");
    ui_->logView->setRootIsDecorated(false);
    ui_->logView->setLogModel(logModel_);
    ui_->logView->setUniformRowHeights(true);
    ui_->logView->setAlternatingRowColors(false);
    ui_->logView->setItemDelegate(new LogDelegate(this));
    ui_->logView->setContextMenuPolicy(Qt::ActionsContextMenu);

    // make the horizontal scrollbar work
    ui_->logView->header()->setStretchLastSection(false);
    ui_->logView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);

    ui_->showLogTb->setChecked(false);
    ui_->logView->hide();
    connect(ui_->showLogTb, SIGNAL(clicked(bool)), this, SLOT(showLogView(bool)));

    // Define context menu
    // ui_->logView->addAction(actionCopyEntry_);
    // ui_->logView->addAction(actionCopyRow_);

    // Connect the views to the log model
    connect(viewHandler_, SIGNAL(timeRangeChanged(qint64, qint64)), logModel_, SLOT(setPeriod(qint64, qint64)));

    connect(viewHandler_, SIGNAL(timeRangeChanged(qint64, qint64)), this, SLOT(periodChanged(qint64, qint64)));

    connect(viewHandler_,
            SIGNAL(timeRangeHighlighted(qint64, qint64, qint64)),
            logModel_,
            SLOT(setHighlightPeriod(qint64, qint64, qint64)));

    connect(viewHandler_, SIGNAL(timeRangeReset()), logModel_, SLOT(resetPeriod()));

    connect(viewHandler_, SIGNAL(timeRangeReset()), this, SLOT(periodWasReset()));

    // log mode
    ui_->logModeCombo->addItem("Current log", "latest");
    ui_->logModeCombo->addItem("Archived log", "archive");
    ui_->logModeCombo->setCurrentIndex(0);
    ui_->loadFileTb->hide();

    // signal-slot
    connect(ui_->logModeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLogMode(int)));

    connect(ui_->reloadTb, SIGNAL(clicked()), this, SLOT(slotReload()));

    connect(ui_->loadFileTb, SIGNAL(clicked()), this, SLOT(slotLoadCustomFile()));

    // the icon for this button changes according to state
    ui_->expandFileInfoTb->setIcon(ViewerUtil::makeExpandIcon(false));
    ui_->expandFileInfoTb->setMaximumSize(QSize(16, 16));
    expandFileInfoProp_ = VConfig::instance()->find("panel.timeline.expandFileInfo");
    Q_ASSERT(expandFileInfoProp_);
    bool expandSt = expandFileInfoProp_->value().toBool();
    ui_->expandFileInfoTb->setChecked(expandSt);
    connect(ui_->expandFileInfoTb, SIGNAL(clicked(bool)), this, SLOT(slotExpandFileInfo(bool)));
    slotExpandFileInfo(expandSt);
}

LogLoadWidget::~LogLoadWidget() {
    delete ui_;
}

// void LogLoadWidget::initSplitter()
//{
//     if (!splitterInited_ && width() > 100) {
//         splitterInited_ = true;
//         if (splitterSavedState_.isEmpty()) {
//             auto w = width();
//             Q_ASSERT(ui_->splitter->count() == 3);
//             QList<int> sizes;
//             sizes << 300*1000/w << 600*1000/w;
//             sizes << w-(sizes[0]+sizes[1]);
//             ui_->splitter->setSizes(sizes);
//         } else {
//             ui_->splitter->restoreState(splitterSavedState_);
//         }
//     }
// }

void LogLoadWidget::clear() {
    beingCleared_ = true;
    if (fileTransfer_) {
        fileTransfer_->stopTransfer(true);
        ui_->messageLabel->stopLoadLabel();
    }

    ui_->messageLabel->clear();
    ui_->messageLabel->hide();

    ui_->logInfoLabel->clearIt();

    viewHandler_->clear();
    logModel_->clearData();
    logFile_.clear();
    serverName_.clear();
    host_.clear();
    port_.clear();
    suites_.clear();
    remoteUid_.clear();
    localLog_       = true;
    logLoaded_      = false;
    logTransferred_ = false;
    transferredAt_  = QDateTime();

    // prevState_.valid=false;
    tmpLogFile_.reset();
    //    ui_->startTe->clear();
    //    ui_->endTe->clear();
    ui_->timeLabel->clear();

    ui_->logModeCombo->setCurrentIndex(0);
    logMode_ = LatestMode;
    ui_->reloadTb->show();
    ui_->loadFileTb->hide();
    archiveLogList_.clear();
    ui_->logModeCombo->hide();

    setAllVisible(false);
    beingCleared_ = false;
}

void LogLoadWidget::clearData(bool usePrevState) {
    beingCleared_ = true;
    if (fileTransfer_) {
        fileTransfer_->stopTransfer(true);
        ui_->messageLabel->stopLoadLabel();
    }

    ui_->messageLabel->clear();
    ui_->messageLabel->hide();
    ui_->logInfoLabel->clearIt();

    viewHandler_->clear();
    logModel_->clearData();

    localLog_       = true;
    logLoaded_      = false;
    logTransferred_ = false;
    transferredAt_  = QDateTime();

    if (!usePrevState) {
        prevState_.valid = false;
        //        ui_->startTe->clear();
        //        ui_->endTe->clear();
        ui_->timeLabel->clear();
    }

    tmpLogFile_.reset();
    setAllVisible(false);
    beingCleared_ = false;
}

void LogLoadWidget::updateInfoLabel(bool showDetails) {
    QString txt, compactTxt;

    auto data = viewHandler_->data();

    if (logMode_ == LatestMode) {
        txt = FileInfoLabel::formatKwPair("Log file", logFile_) + FileInfoLabel::formatKwPair(" Server", serverName_) +
              FileInfoLabel::formatKwPair(" Host", host_) + FileInfoLabel::formatKwPair(" Port", port_);

        if (showDetails) {
            if (data->loadStatus() == LogLoadData::LoadDone) {
                if (localLog_) {
                    VFileInfo fi(logFile_);
                    txt += FileInfoLabel::formatKwPair(" Size", fi.formatSize());
                }
                else if (tmpLogFile_) {
                    VFileInfo fi(QString::fromStdString(tmpLogFile_->path()));
                    txt += FileInfoLabel::formatKwPair(" Size", fi.formatSize());
                }
            }

            txt += FileInfoLabel::formatKey(" Source");

            // fetch method and time
            if (localLog_) {
                txt += " read from disk ";
                if (data->loadedAt().isValid())
                    txt += FileInfoLabel::formatHighlight(" at ") + FileInfoLabel::formatDate(data->loadedAt());
            }
            else {
                if (logTransferred_) {
                    txt += " fetched from remote host ";
                }
                else {
                    txt += " fetch failed from remote host ";
                }
                if (transferredAt_.isValid())
                    txt += FileInfoLabel::formatHighlight(" at ") + FileInfoLabel::formatDate(transferredAt_);
            }

            if (data->loadStatus() == LogLoadData::LoadDone) {
                QColor warnCol(218, 142, 18);

                QString warnVerb;
                if (localLog_ && !data->isFullRead()) {
                    warnVerb = "parsed";
                }
                else if (tmpLogFile_) {
                    QFileInfo fi(QString::fromStdString(tmpLogFile_->path()));
                    if (maxReadSize_ > 0 && static_cast<size_t>(fi.size()) == maxReadSize_) {
                        warnVerb = "fetched";
                    }
                }

                if (!warnVerb.isEmpty()) {
                    txt += Viewer::formatItalicText(" (" + warnVerb + " last " +
                                                        QString::number(maxReadSize_ / (1024 * 1024)) +
                                                        " MB of file - maximum size reached)",
                                                    warnCol);
                }
            }
        }

        VFileInfo fInfo(logFile_);
        compactTxt = FileInfoLabel::formatKwPair("File", fInfo.fileName());
    }

    // archived
    else {
        if (archiveLogList_.loadableCount() == 1) {
            txt = FileInfoLabel::formatKwPair("Log file", archiveLogList_.firstLoadablePath());
        }
        else if (archiveLogList_.loadableCount() > 1) {
            txt = FileInfoLabel::formatKwPair("Log files",
                                              "multiple [" + QString::number(archiveLogList_.loadableCount()) + "]");
        }

        txt += FileInfoLabel::formatKwPair(" Server", serverName_) + FileInfoLabel::formatKwPair(" Host", host_) +
               FileInfoLabel::formatKwPair(" Port", port_);

        if (showDetails) {
            if (data->loadStatus() == LogLoadData::LoadDone) {
                if (archiveLogList_.loadableCount() == 1)
                    txt += FileInfoLabel::formatKwPair(" Size", VFileInfo::formatSize(archiveLogList_.totalSize()));
                else if (archiveLogList_.loadableCount() > 1)
                    txt +=
                        FileInfoLabel::formatKwPair(" Total size", VFileInfo::formatSize(archiveLogList_.totalSize()));
            }
            txt += FileInfoLabel::formatKwPair(" Source", "read from disk ");
        }

        compactTxt = FileInfoLabel::formatKwPair("Log files",
                                                 "multiple [" + QString::number(archiveLogList_.loadableCount()) + "]");
    }

    ui_->logInfoLabel->update(txt, compactTxt);

    checkButtonState();
}

void LogLoadWidget::showLogView(bool b) {
    if (b && ui_->resCombo->isVisible()) {
        ui_->logView->setVisible(true);
    }
    else {
        ui_->logView->setVisible(false);
    }
}

bool LogLoadWidget::shouldShowLog() const {
    return ui_->showLogTb->isChecked();
}

void LogLoadWidget::setAllVisible(bool b) {
    ui_->viewTab->setVisible(b);
    ui_->logView->setVisible(b && shouldShowLog());
    ui_->cornerW->setVisible(b);
}

void LogLoadWidget::slotLogMode(int) {
    if (beingCleared_)
        return;

#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    QString id = ui_->logModeCombo->currentData().toString();
#else
    QString id;
    if (ui_->logModeCombo->currentIndex() >= 0)
        id = ui_->logModeCombo->itemData(ui_->logModeCombo->currentIndex()).toString();
#endif
    if (id == "latest")
        setLogMode(LatestMode);
    else if (id == "archive")
        setLogMode(ArchiveMode);
}

void LogLoadWidget::setLogMode(LogMode logMode) {
    if (logMode_ == logMode)
        return;

    logMode_ = logMode;
    if (logMode_ == LatestMode) {
        ui_->reloadTb->show();
        ui_->loadFileTb->hide();
        archiveLogList_.clear();
        clearData(false);
        reloadLatest(false);
    }
    else if (logMode_ == ArchiveMode) {
        ui_->reloadTb->hide();
        ui_->loadFileTb->show();
        archiveLogList_.clear();
        clearData(false);
        updateInfoLabel();
        checkButtonState();
    }
    else {
        UI_ASSERT(0, "Invalid logMode=" << logMode);
    }
}

// The reload button was pressed in LatestMode
void LogLoadWidget::slotReload() {
    Q_ASSERT(logMode_ == LatestMode);
    reloadLatest(true);
}

// Reload the logfile in current mode.
// canUsePrevState: false when we come form ArchiveMode or initial load,
//                  true otherwise
void LogLoadWidget::reloadLatest(bool usePrevState) {
    Q_ASSERT(logMode_ == LatestMode);
    if (!serverName_.isEmpty()) {
        std::vector<std::string> suites;
        // we get the latest state of the suites and the remote uid
        if (ServerHandler* sh = ServerHandler::find(serverName_.toStdString())) {
            remoteUid_ = sh->uidForServerLogTransfer();
            setMaxReadSize(sh->maxSizeForTimelineData());

            if (SuiteFilter* sf = sh->suiteFilter()) {
                if (sf->isEnabled())
                    suites = sh->suiteFilter()->filter();
            }

            suites_ = suites;
        }

        loadLatest(usePrevState);
        checkButtonState();
    }
}

void LogLoadWidget::slotLoadCustomFile() {
    Q_ASSERT(logMode_ == ArchiveMode);
    QStringList fileNames = QFileDialog::getOpenFileNames(this);
    if (fileNames.isEmpty())
        return;

    TimelineFileList archiveLogList = TimelineFileList(fileNames);
    TimelinePreLoadDialog dialog;
    dialog.setModal(true);
    dialog.init(archiveLogList);
    if (dialog.exec() == QDialog::Accepted) {
        archiveLogList_ = archiveLogList;
        loadArchive();
    }
}

// Initial load
void LogLoadWidget::initLoad(QString serverName,
                             QString host,
                             QString port,
                             QString logFile,
                             const std::vector<std::string>& suites,
                             QString remoteUid,
                             int maxReadSize,
                             const std::string& currentNodePath,
                             bool detached) {
    if (logMode_ != LatestMode)
        return;

    // we need to be in a clean state
    clear();
    Q_ASSERT(logMode_ == LatestMode);

    setDetached(detached);

    // clear() hides it so we need to show it again
    ui_->logModeCombo->show();

    // these must be kept until we call clear()!!!!
    serverName_ = serverName;
    host_       = host;
    port_       = port;
    logFile_    = logFile;
    suites_     = suites;
    remoteUid_  = remoteUid;
    setMaxReadSize(maxReadSize);
    currentNodePath_ = QString::fromStdString(currentNodePath);

    loadLatest(false);
}

void LogLoadWidget::loadLatest(bool usePrevState) {
    Q_ASSERT(logMode_ == LatestMode);

    // if it is a reload we remember the current period
    if (usePrevState) {
        auto data            = viewHandler_->data();
        prevState_.valid     = true;
        prevState_.startDt   = ui_->startTe->dateTime();
        prevState_.endDt     = ui_->endTe->dateTime();
        prevState_.fullStart = (prevState_.startDt == data->startTime());
        prevState_.fullEnd   = (prevState_.endDt == data->endTime());
        clearData(true);
    }
    else {
        // prevState_.valid=false;
        clearData(false);
    }

    if (logFile_.isEmpty())
        return;

    logLoaded_      = false;
    logTransferred_ = false;
    localLog_       = true;

    // at this point the file info label can only show some basic information
    // we do not have the details
    updateInfoLabel(false);

    QFileInfo fInfo(logFile_);

    // try to get it over the network, ascynchronous - will call loadCore() in the end
    if (!fInfo.exists()) {
        localLog_ = false;
        // tmpLogFile_=VFile::createTmpFile(true); //will be deleted automatically
        ui_->messageLabel->showInfo("Fetching file from remote host ...");
        ui_->messageLabel->startLoadLabel(true);

        if (!fileTransfer_) {
            fileTransfer_ = new VFileTransfer(this);

            connect(fileTransfer_, SIGNAL(transferFinished()), this, SLOT(slotFileTransferFinished()));

            connect(fileTransfer_, SIGNAL(transferFailed(QString)), this, SLOT(slotFileTransferFailed(QString)));

            connect(fileTransfer_, SIGNAL(stdOutputAvailable(QString)), this, SLOT(slotFileTransferStdOutput(QString)));
        }

        if (VConfig::instance()->proxychainsUsed()) {
            fileTransfer_->transferLocalViaSocks(logFile_, VFileTransfer::LastBytes, maxReadSize_);
        }
        else {
            fileTransfer_->transfer(logFile_, host_, remoteUid_, VFileTransfer::LastBytes, maxReadSize_);
        }
    }
    // load local file
    else {
        loadCore(logFile_);
    }
}

// Load a single/multiple logfiles in ArchiveMode
void LogLoadWidget::loadArchive() {
    Q_ASSERT(logMode_ == ArchiveMode);

    clearData(false);

    logLoaded_      = false;
    logTransferred_ = false;
    localLog_       = true;

    ViewerUtil::setOverrideCursor(QCursor(Qt::WaitCursor));

    ui_->messageLabel->showInfo("Loading data from log file ...");

    bool loadDone = false;

    QElapsedTimer timer;
    timer.start();

    logModel_->beginLoadFromReader();

    // std::vector<std::string> suites;
    for (int i = 0; i < archiveLogList_.items().count(); i++) {
        if (!archiveLogList_.items()[i].loadable_)
            continue;

        ui_->messageLabel->showInfo("Loading data from log file [" + QString::number(i + 1) + "/" +
                                    QString::number(archiveLogList_.items().count()) + "] ...");

        ui_->messageLabel->startProgress(100);

        try {
            viewHandler_->loadMultiLogFile(archiveLogList_.items()[i].dataPath().toStdString(),
                                           suites_,
                                           i,
                                           (i == archiveLogList_.items().count() - 1),
                                           logModel_->logData());

            loadDone = true;
        }

        catch (const std::runtime_error& e) {
            logModel_->endLoadFromReader();
            // logLoaded_=false;
            ui_->messageLabel->stopProgress();
            std::string errTxt(e.what());
        }

        UiLog().dbg() << "Logfile parsed: " << timer.elapsed() / 1000 << "s";

        ui_->messageLabel->stopProgress();
    }

    logModel_->endLoadFromReader();
    viewHandler_->loadPostProc();

    ui_->messageLabel->hide();

    ViewerUtil::restoreOverrideCursor();

    if (!loadDone) {
        ui_->messageLabel->showError(QString::fromStdString("Could not parse any of the specified log files!"));
        viewHandler_->clear();
        logModel_->clearData();
        setAllVisible(false);
        updateInfoLabel();
        return;
    }

    logLoaded_ = true;
    viewHandler_->data()->markAsLoadDone();
    setAllVisible(true);
    updateInfoLabel();

    initFromData();
}

void LogLoadWidget::slotFileTransferFinished() {
    // we are not in a cleared state
    if (!beingCleared_) {
        tmpLogFile_ = fileTransfer_->result();
        fileTransfer_->clear();
        logTransferred_ = true;
        ui_->messageLabel->stopLoadLabel();
        ui_->messageLabel->hide();
        ui_->messageLabel->update();
        if (tmpLogFile_) {
            loadCore(QString::fromStdString(tmpLogFile_->path()));
        }
    }
}

void LogLoadWidget::slotFileTransferFailed(QString err) {
    if (!beingCleared_) {
        tmpLogFile_.reset();
        fileTransfer_->clear();
        logTransferred_ = false;
        ui_->messageLabel->stopLoadLabel();
        logLoaded_ = false;
        ui_->messageLabel->showError("Could not fetch log file from remote host! <br>" + err);
        viewHandler_->clear();
        logModel_->clearData();
        setAllVisible(false);
        updateInfoLabel();
    }
}

void LogLoadWidget::slotFileTransferStdOutput(QString msg) {
    if (!msg.simplified().isEmpty()) {
        ui_->messageLabel->appendInfo(msg);
    }
}

void LogLoadWidget::slotLogLoadProgress(size_t current, size_t total) {
    int percent = 100 * current / total;
    if (percent >= 0 && percent <= 100)
        ui_->messageLabel->progress("", percent);
}

// notification from messagelabel: user cancelled the transfer
void LogLoadWidget::slotCancelFileTransfer() {
#ifdef UI_LOGLOADWIDGET_DEBUG_
    UI_FUNCTION_LOG
    UiLog().dbg() << "fileTransfer_=" << fileTransfer_;
#endif
    if (fileTransfer_) {
        fileTransfer_->stopTransfer(true);
    }
}

void LogLoadWidget::loadCore(QString logFile) {
    ViewerUtil::setOverrideCursor(QCursor(Qt::WaitCursor));
    VFileInfo fInfo(logFile);
    ui_->messageLabel->showInfo("Loading data from log file ... [size=" + fInfo.formatSize() + "]");

    QElapsedTimer timer;
    timer.start();

    ui_->messageLabel->startProgress(100);

    try {
        logModel_->beginLoadFromReader();
        viewHandler_->load(logFile.toStdString(), maxReadSize_, suites_, logModel_->logData());
        logModel_->endLoadFromReader();
    }
    catch (const std::runtime_error& e) {
        logModel_->endLoadFromReader();

        logLoaded_ = false;
        ui_->messageLabel->stopProgress();

        std::string errTxt(e.what());

        QFileInfo fInfo(logFile);
        if (!fInfo.exists()) {
            errTxt += " The specified log file <b>does not exist</b> on disk!";
        }
        else if (!fInfo.isReadable()) {
            errTxt += " The specified log file is <b>not readable</b>!";
        }
        else if (!fInfo.isFile()) {
            errTxt += " The specified log file is <b>not a file</b>!";
        }

        ui_->messageLabel->showError(QString::fromStdString(errTxt));
        viewHandler_->clear();
        logModel_->clearData();
        setAllVisible(false);
        updateInfoLabel();
        ViewerUtil::restoreOverrideCursor();
        return;
    }

    UiLog().dbg() << "Logfile parsed: " << timer.elapsed() / 1000 << "s";

    ui_->messageLabel->stopProgress();
    ui_->messageLabel->hide();
    logLoaded_ = true;
    setAllVisible(true);
    updateInfoLabel();

    ViewerUtil::restoreOverrideCursor();

    initFromData();
}

void LogLoadWidget::initFromData() {
    auto data           = viewHandler_->data();
    QDateTime startTime = data->startTime();
    QDateTime endTime   = data->endTime();
    ui_->startTe->setMinimumDateTime(startTime);
    ui_->startTe->setMaximumDateTime(endTime);

    // TODO: implement period initialisation based on prev state
    bool usePrevState = false;

    // try the set the previously used interval - for reload only
    if (usePrevState && prevState_.valid) {
        if (prevState_.startDt <= data->startTime() || prevState_.fullStart)
            ui_->startTe->setDateTime(data->startTime());
        else if (prevState_.startDt < data->endTime())
            ui_->startTe->setDateTime(prevState_.startDt);
    }
    else {
        ui_->startTe->setDateTime(data->startTime());
    }
    ui_->endTe->setMinimumDateTime(startTime);
    ui_->endTe->setMaximumDateTime(endTime);

    if (usePrevState && prevState_.valid) {
        if (prevState_.endDt >= data->endTime() || prevState_.fullEnd)
            ui_->endTe->setDateTime(data->endTime());
        else if (prevState_.endDt > data->startTime())
            ui_->endTe->setDateTime(prevState_.endDt);
    }
    else {
        ui_->endTe->setDateTime(data->endTime());
    }

    updateTimeLabel(startTime, endTime);

    checkButtonState();
}

void LogLoadWidget::setDetached(bool d) {
    detached_ = d;
}

void LogLoadWidget::checkButtonState() {
    auto data      = viewHandler_->data();
    bool fromStart = (ui_->startTe->dateTime() == data->startTime());
    bool toEnd     = (ui_->endTe->dateTime() == data->endTime());

    //     ui_->startTb->setEnabled(!fromStart);
    //     ui_->endTb->setEnabled(!toEnd);
    ui_->showFullTb->setEnabled(!fromStart || !toEnd);
}

void LogLoadWidget::setMaxReadSize(int maxReadSizeInMb) {
    if (maxReadSizeInMb <= 0)
        maxReadSize_ = 0;
    else
        maxReadSize_ = static_cast<size_t>(maxReadSizeInMb) * 1024 * 1024;
}

void LogLoadWidget::periodChanged(qint64 start, qint64 end) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    QDateTime startDt = QDateTime::fromMSecsSinceEpoch(start, Qt::UTC);
    QDateTime endDt   = QDateTime::fromMSecsSinceEpoch(end, Qt::UTC);
#else
    QDateTime startDt = QDateTime::fromMSecsSinceEpoch(start).toUTC();
    QDateTime endDt   = QDateTime::fromMSecsSinceEpoch(end).toUTC();
#endif
    ui_->startTe->setDateTime(startDt);
    ui_->endTe->setDateTime(endDt);
    updateTimeLabel(startDt, endDt);
}

void LogLoadWidget::periodWasReset() {
    QDateTime startDt = viewHandler_->data()->startTime();
    QDateTime endDt   = viewHandler_->data()->endTime();
    ui_->startTe->setDateTime(startDt);
    ui_->endTe->setDateTime(endDt);
    updateTimeLabel(startDt, endDt);
    checkButtonState();
}

void LogLoadWidget::updateTimeLabel(QDateTime startDt, QDateTime endDt) {
    QColor col(39, 49, 101);
    QString txt = "start: " + Viewer::formatBoldText(startDt.toString("hh:mm:ss yyyy-MM-dd"), col) +
                  " end: " + Viewer::formatBoldText(endDt.toString("hh:mm:ss yyyy-MM-dd"), col);
    ui_->timeLabel->setText(txt);
}

void LogLoadWidget::resolutionChanged(int) {
    int idx = ui_->resCombo->currentIndex();
    if (idx == 0)
        viewHandler_->setResolution(LogLoadData::SecondResolution);
    else if (idx == 1)
        viewHandler_->setResolution(LogLoadData::MinuteResolution);
    else if (idx == 2)
        viewHandler_->setResolution(LogLoadData::HourResolution);
}

//-------------------------
// File info label
//-------------------------

void LogLoadWidget::slotExpandFileInfo(bool st) {
    Q_ASSERT(expandFileInfoProp_);
    expandFileInfoProp_->setValue(st);
    ui_->logInfoLabel->setCompact(!st);
}

void LogLoadWidget::writeSettings(VComboSettings* vs) {
    //    int cbIdx=ui_->resCombo->currentIndex();
    //    if (cbIdx) {
    //        vs->put("plotResolution",
    //                ui_->resCombo->itemData(cbIdx).toString().toStdString());
    //    }
    //    vs->putQs("splitter",ui_->splitter->saveState());
    viewHandler_->writeSettings(vs);
}

void LogLoadWidget::readSettings(VComboSettings* vs) {
    // sort mode
    //    QString resMode=QString::fromStdString(vs->get<std::string>("plotResolution", std::string()));
    //    ViewerUtil::initComboBoxByData(resMode,ui_->resCombo);

    //    splitterSavedState_ = vs->getQs("splitter").toByteArray();
    viewHandler_->readSettings(vs);
}
