fcf.module({
  name: "fcf:NSystem/NPackage/Theme.js",
  dependencies: ["fcf:NSystem/NPackage/tools.js"],
  module: function(libTools){
    let Namespace = fcf.prepareObject(fcf, "NSystem/NPackage");

    class Theme {
      constructor(a_name, a_configutaion) {
        this._name          = a_name;
        this._configuration = a_configutaion;
        this.rebuild();
      }

      rebuild(){
        this._selfConfiguration = fcf.append(true, {}, {
          aliases:  fcf.application.getConfiguration().aliases,
          decor:    fcf.application.getConfiguration().decor,
          views:    fcf.application.getConfiguration().views,
        });
        libTools.mergeConfiguration(this._selfConfiguration, this._configuration, false);

        this._decor         = typeof this._selfConfiguration.decor == "object" ? this._selfConfiguration.decor : {};
        this._aliases       = typeof this._selfConfiguration.aliases == "object" ? this._selfConfiguration.aliases : {};
        this.setAliases(this._aliases);
        this._views         = {
                                parts: {},
                                all:   {},
                                cur:   {},
                              };
        if (typeof this._selfConfiguration.views == "object")
          this.attachViews(this._selfConfiguration.views);
      }

      getName(){
        return this._name;
      }

      getConfiguration() {
        return this._selfConfiguration;
      }

      getDecor(){
        return this._decor;
      }

      getInfo(){
        return this._selfConfiguration;
      }

      getTemplate(a_mode, a_typeOrView) {
        if (typeof a_typeOrView === "object") {
          let view = fcf.buildView(a_typeOrView, a_mode);
          if (view.template){
            return { template: view.template, found: true };
          }
          a_typeOrView = a_typeOrView.type;
        }

        let partArr = a_mode.split(".");
        let currentParts = this._views;
        let result = undefined;

        for(let i = 0; i < partArr.length; ++i) {
          if (a_typeOrView in currentParts.all) {
            result = { template:  currentParts.all[a_typeOrView], found: true }
          }

          if (partArr[i] in currentParts.parts) {
            currentParts = currentParts.parts[partArr[i]];
          } else {
            currentParts = undefined;
            break;
          }
        }

        if (currentParts && a_typeOrView in currentParts.cur) {
          result = { template:  currentParts.cur[a_typeOrView], found: true }
        } else if (currentParts && a_typeOrView in currentParts.all) {
          result = { template:  currentParts.all[a_typeOrView], found: true }
        }

        if (!result){
          let inheritanceMode = fcf.application.getInheritanceModes()[a_mode];
          if (inheritanceMode)
            return this.getTemplate(inheritanceMode, a_typeOrView);
        } else {
          return result;
        }

        return { template: "@controls:text", found: false };
      }

      getAliases() {
        return this._aliases;
      }

      attachViews(a_objectViews) {
        for(let part in a_objectViews)
          for(let view in a_objectViews[part])
            this.attachView(part, view, a_objectViews[part][view]);
      }

      resolveAlias(a_path) {
        if (a_path.charAt(0) != "@")
          return a_path;
        let subpart = a_path.split("+")[1];
        a_path = a_path.split("+")[0];
        let alias = a_path.substr(1);
        let aliases = this.getAliases();
        let result = alias in aliases ? aliases[alias] : a_path;
        if (subpart)
          result += "+" + subpart;
        return result;
      }

      attachView(a_mode, a_view, a_template) {
        let partArr = a_mode.split(".");
        let currentParts = this._views;
        for (let i = 0; i < partArr.length; ++i) {
          if (partArr[i] != "*") {
            if (!(partArr[i] in currentParts.parts))
              currentParts.parts[partArr[i]] = { parts: {}, cur: {}, all: {} };
            currentParts = currentParts.parts[partArr[i]];
          } else {
            currentParts.all[a_view] = a_template;
            return;
          }
        }
        currentParts.cur[a_view] = a_template;
      }


      setAliases(a_aliases) {
        for(let key in a_aliases){
          let alias = key[0] == "@" ? key.substr(1) : key;
          this._aliases[alias] = a_aliases[key];
        }
      }

    };

    Namespace.Theme = Theme;

    return Namespace.Theme;
  }
});
