/***************************** 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 "StandardObject.h"

#include "IconFactory.h"
#include "Request.h"
#include "MvIconLanguage.h"
#include "IconClass.h"
#include "IconInfo.h"
#include "Dependancy.h"

#include "mars.h"

#include "Folder.h"

#include "Tokenizer.h"

//#include "Log.h"


class StandardObjectDependancy : public Dependancy
{
public:
    StandardObjectDependancy(IconObject*, const string&, int);
    ~StandardObjectDependancy();

    int n() { return n_; }
    const string& param() { return param_; }
    const Request& request() { return request_; }
    IconObjectH object() { return object_; }

private:
    virtual Task* action(const Action&);
    virtual void success(const Request&);
    virtual void failure(const Request&);

    IconObjectH object_;
    string param_;
    int n_;
    Request request_;
    bool ok_;
};

StandardObjectDependancy::StandardObjectDependancy(IconObject* o, const string& param, int n) :
    object_(o),
    param_(param),
    n_(n),
    request_(""),
    ok_(false)
{
}

Task* StandardObjectDependancy::action(const Action& a)
{
    return object_->action(a);
}

void StandardObjectDependancy::success(const Request& r)
{
    ok_      = true;
    request_ = r;
}

void StandardObjectDependancy::failure(const Request& r)
{
    ok_      = false;
    request_ = r;
}

StandardObjectDependancy::~StandardObjectDependancy()
{
}


StandardObject::StandardObject(Folder* parent, const IconClass& kind,
                               const string& name, IconInfo* info) :
    IconObject(parent, kind, name, info)
{
}

StandardObject::~StandardObject()
{
}

void StandardObject::doubleClick()
{
    edit();
}

set<string> StandardObject::can()
{
    return IconObject::can();
}

void StandardObject::createFiles()
{
    IconObject::createFiles();
    Path p = path();
    if (!p.exists())
        p.saveText(className());
}

Request StandardObject::request() const
{
    Request r(path());
    r.print();
    return language().expand(r.justOneRequest());
}

void StandardObject::request(const Request& r)
{
    Request req = language().expand(r, EXPAND_NO_DEFAULT | EXPAND_2ND_NAME);
    req.save(path());
}


void StandardObject::dependancies(set<DependancyH>& dep, const Request& r)
{
    dep.clear();

    vector<string> icons = language().interfaces("icon");

    for (vector<string>::iterator j = icons.begin(); j != icons.end(); ++j) {
        int i                   = 0;
        vector<IconObjectH> sub = subObjects(*j, r);

        for (vector<IconObjectH>::iterator k = sub.begin(); k != sub.end(); ++k)
            dep.insert(new StandardObjectDependancy(*k, *j, i++));
    }
}

const set<DependancyH>& StandardObject::dependancies()
{
    if (dependancies_.size())
        return dependancies_;

    dependancies_.clear();

    Request r = request();

    vector<string> icons = language().interfaces("icon");

    for (vector<string>::iterator j = icons.begin(); j != icons.end(); ++j) {
        int i                   = 0;
        vector<IconObjectH> sub = subObjects(*j, r);

        for (vector<IconObjectH>::iterator k = sub.begin(); k != sub.end(); ++k)
            dependancies_.insert(new StandardObjectDependancy(*k, *j, i++));
    }

    return dependancies_;
}


Request StandardObject::fullRequest() const
{
    Request r = request();

    typedef map<int, Request> Map1;
    typedef map<string, Map1> Map2;

    Map2 m;

    for (set<DependancyH>::const_iterator k = dependancies_.begin(); k != dependancies_.end(); ++k) {
        StandardObjectDependancy* b = dynamic_cast<StandardObjectDependancy*>((Dependancy*)*k);
        const string& p             = b->param();
        int n                       = b->n();
        const Request& r            = b->request();

        m[p][n] = r;
    }

    for (Map2::iterator j = m.begin(); j != m.end(); ++j) {
        const string& param = (*j).first;
        const Map1& reqs    = (*j).second;

        ::request* empty = 0;
        MvRequest s(empty);

        for (Map1::const_iterator i = reqs.begin(); i != reqs.end(); ++i)
            s = s + (*i).second;

        r(param.c_str()) = s;
    }

    cout << "---> StandardObject fullrequest" << endl;
    r.print();
    cout << "<--- StandardObject fullrequest" << endl;

    return r;
}

bool StandardObject::rename(const string& newname)
{
    Request r = request();

    cout << "StandardObject::rename" << endl;
    r.print();

    vector<string> icons = language().interfaces("icon");
    map<string, vector<IconObjectH> > sub;

    for (vector<string>::iterator j = icons.begin(); j != icons.end(); ++j)
        sub[*j] = subObjects(*j, r);

    if (!IconObject::rename(newname))
        return false;

    for (vector<string>::iterator j = icons.begin(); j != icons.end(); ++j)
        setSubObjects(*j, sub[*j], r);

    r.print();
    request(r);
    return true;
}

void StandardObject::duplicate()
{
    clone(parent(), info().x() + 20, info().y() + 20, false);
}

IconObject* StandardObject::clone(Folder* folder, bool update)
{
    return clone(folder, IconInfo::undefX(), IconInfo::undefY(), update);
}


IconObject* StandardObject::clone(Folder* folder, int x, int y, bool update)
{
    StandardObject* other = dynamic_cast<StandardObject*>(IconObject::clone(folder, x, y, update));
    if (!other) {
        //-- this branch is for finding out why 'other' may be 0!
        //-- i.e. use these lines to set breakpoint in debugger!!

        string s("MvUI/StandardObject::clone()");
        //Log::info(s) << "internal error: NULL ptr!" << endl;

        return 0;  //-- probably we should not do this...
    }

    vector<string> icons = language().interfaces("icon");

    Request r = other->request();
    r.print();

    Folder* e = this->embeddedFolder(true);
    Folder* f = other->embeddedFolder(true);

    map<string, vector<IconObjectH> > sub;

    for (vector<string>::const_iterator j = icons.begin(); j != icons.end(); ++j) {
        vector<IconObjectH> v = this->subObjects(*j, r);
        vector<IconObjectH> vOther;

        for (vector<IconObjectH>::iterator k = v.begin(); k != v.end(); ++k) {
            if (e->ancestor(*k)) {
                string name = relativeName(*k);
                Tokenizer parse("/");
                vector<string> n;
                parse(name, n);

                cout << '[' << name << ']' << endl;

                IconObject* o = f;
                for (int i = 1; i < static_cast<int>(n.size()) && o; i++) {
                    cout << "SEARCH: " << n[i] << " in " << o->fullName() << endl;
                    o = o->find(n[i]);
                    if (o)
                        cout << "FOUND: " << o->fullName() << endl;
                    else
                        cout << "NOTFOUND" << endl;
                }

                if (o) {
                    cout << "CLONE: " << (*k)->fullName() << endl;
                    vOther.push_back(o);
                    cout << "   IS: " << o->fullName() << endl;
                }
            }
            else {
                vOther.push_back(*k);
            }
        }

        sub[*j] = vOther;
    }


    for (vector<string>::const_iterator j = icons.begin(); j != icons.end(); ++j)
        other->setSubObjects(*j, sub[*j], r);

    r.print();

    if (icons.size() > 0)
        other->request(r);

    return other;
}

static IconMaker<StandardObject> maker1("Data");
static IconMaker<StandardObject> maker2("Window");
static IconMaker<StandardObject> maker3("Visdef");
static IconMaker<StandardObject> maker4("View");
static IconMaker<StandardObject> maker5("Preference");
