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

 Copyright 2014 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 "RequestPanel.h"
#include <QWidget>

#include "Editor.h"
#include "IconObject.h"
//#include "Log.h"
#include "IconClass.h"
#include "IconFactory.h"
#include "MvIconParameter.h"

#include "MvQRequestPanelLine.h"
#include "MvQRequestPanelWidget.h"

RequestPanel::RequestPanel(const IconClass& kind, MvQRequestPanelWidget* panelWidget, Editor* editor,
                           bool showDisabledItems, const char* /*name*/) :
    QGridLayout(panelWidget),
    class_(kind),
    apply_(false),
    panelWidget_(panelWidget),
    owner_(editor),
    showDisabledItems_(showDisabledItems)
{
    Q_ASSERT(panelWidget_);

    setSizeConstraint(QLayout::SetMinAndMaxSize);
    setColumnMinimumWidth(MvQRequestPanelLine::WidgetColumn, 200);
    setColumnMinimumWidth(MvQRequestPanelLine::WarningColumn, 0);
    setColumnStretch(MvQRequestPanelLine::WidgetColumn, 1);

    int mleft = 0, mright = 0, mtop = 0, mbottom = 0;
    getContentsMargins(&mleft, &mtop, &mright, &mbottom);
    setContentsMargins(4, mtop, mright, mbottom);

    // We need to set spacing explicitly to make MvQRequestPanelWidget work!
    setHorizontalSpacing(8);
    setVerticalSpacing(6);
    // create(parent,  (char*) name);
    scan();

    // Check if there are params depending on others' values (it is idependent of the Rules!!!)
    for (auto& item : items_) {
        if (item->isDependent()) {
            dependentItems_.push_back(item);
        }
    }

    auto* w = new QWidget(panelWidget_);
    addWidget(w, count(), 1);
    setRowStretch(count() - 1, 1);

    // Manage();
}

RequestPanel::~RequestPanel()
{
    for (auto& item : items_)
        delete item;
}

const IconClass& RequestPanel::iconClass()
{
    return class_;
}

void RequestPanel::scan()
{
    class_.language().scan(*this);


    /*Dimension a,b;
    Dimension ma = 0,mb = 0;

    for(vector<RequestPanelItem*>::iterator j = items_.begin(); j != items_.end(); ++j)
    {
        RequestPanelItem* p = (*j);
        p->getSizes(a,b);
        if(a>ma) ma = a;
        if(b>mb) mb = b;
    }

    for(vector<RequestPanelItem*>::iterator j = items_.begin(); j != items_.end(); ++j)
    {
        RequestPanelItem* p = (*j);
        p->setSizes(ma,mb);
    }*/
}
#if 0
Widget  RequestPanel::where() 
{
	return rowcol_;
}
Widget  RequestPanel::main() 
{
	return UIRequestPanel;
}
#endif

void RequestPanel::merge(IconObject* o)
{
    if (o == currentObject())
        return;

    // Merge requests. The input request is not expanded; therefore,
    // it contains only the non-default parameters. As a consequence,
    // only those parameters, plus the ones that are set in the
    // output request, will be merged.
    Request r1 = request();
    Request r = class_.language().expand(r1, EXPAND_DEFAULTS, false);
    r.merge(o->request());


    // special case: when converting a Map View into a Geographical View
    // and we have a sub-area, then we also need to set
    // MAP_AREA_DEFINITION=CORNERS.

    if (!strcmp(r1.getVerb(), "GEOVIEW") && !strcmp(o->request().getVerb(), "MAPVIEW")) {
        if ((const char*)(o->request()("AREA")) != nullptr) {
            r.setValue("MAP_AREA_DEFINITION", "CORNERS");
        }
    }


    // Move back to the default those values that are no longer valid
    Request rr = class_.language().expand(r, EXPAND_DONT_FAIL);

    request(rr);

    // Update UI
    call(&RequestPanelItem::update);
}

void RequestPanel::replace(IconObject* o)
{
    request(o->request());
    call(&RequestPanelItem::update);
}

void RequestPanel::next(const MvIconParameter& p)
{
    MvQRequestPanelLine::build(*this, p);

    // Who add it to the items???
    // items_.push_back(LineFactory::create(owner,param);
}

void RequestPanel::call(Method proc)
{
    for (auto o : items_) {
        (o->*proc)();
    }
}

void RequestPanel::apply()
{
    apply_ = true;
    call(&RequestPanelItem::apply);
    apply_ = false;
}

const Request& RequestPanel::request(long flags)
{
    auto j = cache_.find(flags);
    if (j != cache_.end())
        return (*j).second;
    return cache_[flags] = class_.language().expand(cache_[EXPAND_2ND_NAME], flags);
}

void RequestPanel::request(const Request& r, long flags)
{
    cache_.clear();
    cache_[EXPAND_2ND_NAME] = class_.language().expand(r, EXPAND_2ND_NAME);
    if (flags != EXPAND_2ND_NAME)
        cache_[flags] = class_.language().expand(r, flags);
}

void RequestPanel::edit(IconObject* o)
{
    for (auto& item : items_)
        item->edit(o);
}

void RequestPanel::close()
{
    call(&RequestPanelItem::cleanup);
    cache_.clear();
}

void RequestPanel::reset(IconObject* o)
{
    request(o->request());
    edit(o);
    call(&RequestPanelItem::reset);
}

void RequestPanel::registerObserver(RequestPanelItem* observer)
{
    items_.push_back(observer);
}

void RequestPanel::changed()
{
    owner_->changed();
}

void RequestPanel::changed(RequestPanelItem& p, bool canUpdate)
{
    Request r = request();
    p.set(r);
    request(r);

    if (!apply_)
        if (canUpdate)
            call(&RequestPanelItem::update);


    owner_->changed();
}

void RequestPanel::set(const char* p, const std::string& v)
{
    Request r = request();
    r(p) = v.c_str();
    request(r);

    for (auto& dependentItem : dependentItems_) {
        dependentItem->changed(p, v);
    }

    if (!apply_)
        call(&RequestPanelItem::update);

    owner_->changed();
}

void RequestPanel::set(const char* p, const std::vector<std::string>& v)
{
    Request r = request();
    r.set(p, v);
    request(r);

    for (auto& dependentItem : dependentItems_) {
        dependentItem->changed(p, v);
    }

    if (!apply_)
        call(&RequestPanelItem::update);

    owner_->changed();
}

void RequestPanel::clear(const char* p)
{
    Request r = request();
    r.unsetParam(p);
    request(r);

    if (!apply_)
        call(&RequestPanelItem::update);

    owner_->changed();
}

void RequestPanel::setToDefault(RequestPanelItem* item)
{
    Request r = request();
    r.unsetParam(item->parameter().name());
    request(r);

    if (!apply_) {
        item->reset();

        for (auto& j : items_) {
            if (j != item)
                j->update();
        }
    }

    owner_->changed();
}

void RequestPanel::itemWasChangedToDefault()
{
    owner_->changed();
}

IconObjectH RequestPanel::currentObject()
{
    return (items_.size() > 0) ? items_.at(0)->currentObject() : nullptr;
}


int RequestPanel::defaultCnt()
{
    int cnt = 0;
    for (auto& item : items_)
        if (item->hasDefaultTb())
            cnt++;
    return cnt;
}

void RequestPanel::updateParentWidget()
{
    // if(QWidget *w=parentWidget())
    // w->update();
    panelWidget_->delayedForceRepaint();
}

void RequestPanel::setFilter(QString txt)
{
    filterText_ = txt;
    runFilter();
}

void RequestPanel::runFilter()
{
    if (!filterText_.isEmpty()) {
        auto txt = filterText_.toLower();
        for (auto item : items_) {
            auto name = QString::fromStdString(item->parameter().beautifiedName());
            item->setVisibleByFilter(name.toLower().contains(txt));
        }
    }
    else {
        for (auto item : items_) {
            item->setVisibleByFilter(true);
        }
    }
    panelWidget_->delayedForceRepaint();
}

int RequestPanel::filterNonMatchCount()
{
    int cnt = 0;
    for (auto item : items_) {
        if ((showDisabledItems_ || !item->isGray()) && !item->isVisibleByFilter()) {
            cnt++;
        }
    }
    return cnt;
}

void RequestPanel::setShowDisabledItems(bool b)
{
    showDisabledItems_ = b;
    for (auto& item : items_) {
        item->adjustDisabled();
    }
    panelWidget_->delayedForceRepaint();
}

void RequestPanel::applyTemporaryRules(bool temporary)
{
    if (temporary) {
        for (auto item : items_) {
            item->setVisibleByTemporary(temporary);
        }
        panelWidget_->delayedForceRepaint();
    }
}
