/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/


#include <QtGlobal>
#include <QDebug>
#include <QCompleter>
#include <QShortcut>
#include <QMenu>
#include <QPainter>
#include <QShowEvent>

#include "AbstractSearchLine.h"
#include "MvQMethods.h"
#include "MvQTheme.h"

AbstractSearchLine::AbstractSearchLine(QWidget* parent) :
    QWidget(parent),
    confirmSearch_(false),
    useToolTip_(true)
{
    setupUi(this);

    confirmSearchLabel_->hide();
    confirmSearchLabel_->setShowTypeTitle(false);

#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    searchLine_->setPlaceholderText(tr("Find"));
    label_->hide();
#endif

#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
    searchLine_->setClearButtonEnabled(true);
#endif

    connect(searchLine_, SIGNAL(textChanged(QString)),
            this, SLOT(slotFind(QString)));

    connect(searchLine_, SIGNAL(returnPressed()),
            this, SLOT(slotFindNext()));

    connect(actionNext_, SIGNAL(triggered()),
            this, SLOT(slotFindNext()));

    connect(actionPrev_, SIGNAL(triggered()),
            this, SLOT(slotFindPrev()));

    connect(closeTb_, SIGNAL(clicked()),
            this, SLOT(slotClose()));

    nextTb_->setDefaultAction(actionNext_);
    prevTb_->setDefaultAction(actionPrev_);

    setColours();

    // for the 'find next' functionality, although Qt (at the time of writing) uses
    // both F3 and CTRL-G for most platforms, this is not true for Linux. Therefore,
    // we have to add CTRL-G ourselves.

    QKeySequence ctrlg(tr("Ctrl+G"));
    auto* shortcut = new QShortcut(ctrlg, parent);  // should be destroyed by parent
    connect(shortcut, SIGNAL(activated()), this, SLOT(slotFindNext()));

    status_ = true;

    setFocusProxy(searchLine_);

    // set the menu on the Options toolbutton
    caseSensitive_ = false;
    wholeWords_    = false;
    highlightAll_  = false;
    auto* menu     = new QMenu(this);
    menu->addAction(actionCaseSensitive_);
    menu->addAction(actionWholeWords_);
    menu->addAction(actionHighlightAll_);
    optionsTb_->setMenu(menu);

    matchModeCb_->setMatchMode(StringMatchMode::ContainsMatch);  // set the default match mode
    //matchModeChanged(1);  // dummy call to initialise the 'whole words' option state

    setConfirmSearch(false);
}

AbstractSearchLine::~AbstractSearchLine() = default;

void AbstractSearchLine::setColours()
{
    QString group = "searchline";
    notFoundSh_   = MvQTheme::styleSheet(group, "not_found");
    oriSh_        = MvQTheme::styleSheet(group, "normal");
}

void AbstractSearchLine::clear()
{
    //clearRequested();
    searchLine_->clear();
}

bool AbstractSearchLine::isEmpty()
{
    return searchLine_->text().isEmpty();
}

void AbstractSearchLine::selectAll()
{
    searchLine_->selectAll();
}

void AbstractSearchLine::toDefaultState()
{
    searchLine_->setStyleSheet(oriSh_);
}

void AbstractSearchLine::updateButtons(bool found)
{
    status_ = found;

    if (searchLine_->text().isEmpty() || found) {
        if (searchLine_->styleSheet() != oriSh_) {
            searchLine_->setStyleSheet(oriSh_);
        }
    }
    else {
        if (searchLine_->styleSheet() != notFoundSh_) {
            searchLine_->setStyleSheet(notFoundSh_);
        }
    }
}

void AbstractSearchLine::slotClose()
{
    hide();
}

void AbstractSearchLine::on_actionCaseSensitive__toggled(bool b)
{
    caseSensitive_ = b;
}

void AbstractSearchLine::on_actionWholeWords__toggled(bool b)
{
    wholeWords_ = b;
}

void AbstractSearchLine::on_actionHighlightAll__toggled(bool b)
{
    highlightAll_ = b;
}

void AbstractSearchLine::setConfirmSearch(bool confirmSearch)
{
    confirmSearch_ = confirmSearch;
    //confirmSearchLabel_->setVisible(confirmSearch_);

    if (confirmSearch_) {
        //confirmSearchLabel_->showWarning("Large file mode");
        if (searchLine_->text().isEmpty()) {
            status_ = false;
            toDefaultState();
        }

#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
        searchLine_->setPlaceholderText(tr("Find   (you need to hit enter to start search)"));
#endif
    }
    else {
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
        searchLine_->setPlaceholderText(tr("Find"));
#endif
    }

    if (useToolTip_)
        searchLine_->setToolTip(confirmSearchText());
}

QString AbstractSearchLine::confirmSearchText() const
{
    return (confirmSearch_) ? "Search works in <b>large file mode</b>. After typing in the search term <b>press enter</b> or use the arrows to start search!" : "Search works in <b> continuous mode</b>. As you type in a new character the search starts immediately.";
}

void AbstractSearchLine::setCompleter(QSet<QString> coVals)
{
    Q_ASSERT(searchLine_);
    searchLine_->setCompleter(new QCompleter(coVals.values(), searchLine_));
}

void AbstractSearchLine::hideEvent(QHideEvent* event)
{
    QWidget::hideEvent(event);
    Q_EMIT visibilityChanged();
}

void AbstractSearchLine::showEvent(QShowEvent* event)
{
    QWidget::showEvent(event);
    Q_EMIT visibilityChanged();
}

void AbstractSearchLine::paintEvent(QPaintEvent*)
{
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void AbstractSearchLine::writeSettings(QSettings& settings)
{
    settings.beginGroup("searchLine");
    settings.setValue("matchMode", matchModeCb_->currentText());
    settings.setValue("caseSensitive", caseSensitive());
    settings.setValue("wholeWords", wholeWords());
    settings.setValue("highlightAll", highlightAll());
    settings.endGroup();
}

void AbstractSearchLine::readSettings(QSettings& settings)
{
    settings.beginGroup("searchLine");

    MvQ::initComboBox(settings, "matchMode", matchModeCb_);
    MvQ::initCheckableAction(settings, "caseSensitive", actionCaseSensitive_);
    MvQ::initCheckableAction(settings, "wholeWords", actionWholeWords_);
    MvQ::initCheckableAction(settings, "highlightAll", actionHighlightAll_);

    settings.endGroup();
}
