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

#include "IconClass.h"
#include "IconInfo.h"
//#include "Unknown.h"
#include "Folder.h"

#include "FolderInfo.h"
#include "Request.h"
#include "TemporaryObject.h"
#include "MvLog.h"

#include <cassert>

static std::map<std::string, IconFactory*>* makers = nullptr;

IconFactory::IconFactory(const std::string& name)
{
    if (makers == nullptr)
        makers = new std::map<std::string, IconFactory*>;

    (*makers)[name] = this;
}

IconFactory::~IconFactory() = default;

// For folders name should contain the full path!!!
IconObject* IconFactory::create(Folder* parent, const std::string& name, const IconClass& kind, IconInfo* info)
{
    IconObject* o = nullptr;

    // Try class, then type
    auto j = makers->find(kind.name());
    if (j == makers->end())
        j = makers->find(kind.type());
    if (j == makers->end()) {
        marslog(LOG_WARN, "Unknown icon type=%s [file=%s]", kind.type().c_str(), name.c_str());
        // o = new Unknown(parent,kind,name,info);
        o = nullptr;
    }
    else
        o = (*j).second->make(parent, kind, name, info);

    if (o != nullptr) {
        parent->adopt(o);
        o->createFiles();
    }

    return o;
}

IconObject* IconFactory::createTemporary(IconObject* o, const Request& r, const IconClass* c)
{
    return new TemporaryObject(o, r, c);
}

IconObject* IconFactory::create(Folder* parent, const std::string& name, const IconClass& kind)
{
    return create(parent, name, kind, nullptr);
}

IconObject* IconFactory::create(Folder* parent, const std::string& name, const IconClass& kind, int x, int y)
{
    auto* info = new IconInfo(kind.name(), x, y);
    return create(parent, name, kind, info);
}

IconObject* IconFactory::create(Folder* parent, const std::string& name)
{
    return create(parent, name, IconInfo::undefX(), IconInfo::undefY());
}

IconObject* IconFactory::create(Folder* parent, const std::string& name, int x, int y)
{
    FolderInfo* folderInfo = nullptr;
    IconInfo* info = nullptr;
    std::string dirName, fileName;

    Path path = parent->path();
    dirName = path.str();
    fileName = path.add(name).str();
    folderInfo = parent->folderInfo();
    info = folderInfo->find(name);

    if (info) {
        const IconClass& ic = IconClass::find(info->type());
        return create(parent, name, ic, info);
    }

    // If there is no folderinfo available we see if there is a
    // dotfile to get the type and the positions
    else {
        Path actPath(dirName);
        Path dot = actPath.add(std::string(".") + name);
        Request dotInfo(dot);

        // If there is no dotfile we guess the file type
        if (!dotInfo) {
            dotInfo = Request("USER_INTERFACE");
            const IconClass& ic = IconClass::guess(fileName);
            dotInfo("ICON_CLASS") = ic.name().c_str();

            info = new IconInfo(dotInfo);
            if (x != IconInfo::undefX() && y != IconInfo::undefY())
                info->position(x, y);

            return create(parent, name, ic, info);
        }
        else {
            const char* type = dotInfo("ICON_CLASS");
            const IconClass& ic = IconClass::find(type);

            info = new IconInfo(dotInfo);
            if (x != IconInfo::undefX() && y != IconInfo::undefY())
                info->position(x, y);

            return create(parent, name, ic, info);
        }
    }
}


IconObject* IconFactory::create(const std::string& name, const IconClass& kind)
{
    IconObject* o = IconObject::search(name);
    if (o)
        return o;

    // cout << "IconFactory::create " << name << std::endl;
    std::string dir = mdirname(name.c_str());
    std::string base = mbasename(name.c_str());

    Folder* f = dynamic_cast<Folder*>(create(dir, IconClass::find("FOLDER")));
    return f ? create(f, base, kind) : nullptr;
}

IconObject* IconFactory::create(IconObject* /*o*/, const Request& /*r*/,
                                const IconClass* /*c*/)
{
    assert(0);
    return nullptr;
    // return new Temporary(o,r,c);
}

IconObject* IconFactory::create(Folder* parent, const Request& r, int x, int y)
{
    const char* kind = r.getVerb();
    const char* name = r("_NAME");

    std::string kind1(kind);  // it is needed on alpha
    const IconClass& c = IconClass::find(kind1);

    // The command below was causing memory problems on alpha.
    // Therefore, it was re-coded in a different way
    //	string n = name?mbasename(name):c.defaultName();
    std::string n;
    if (name)
        n = mbasename(name);
    else
        n = c.defaultName();

    n = parent->uniqueName(n);

    IconObject* o = create(parent, n, c, x, y);
    o->setRequest(r);
    //    r.save(o->path());
    return o;
}
