/++
  read configuration files<BR>
  - read config files<BR>
  meta_config_files.d
+/
module sdp.output.paths_source;
import std.array,
  std.file,
  std.path,
  std.regex,
  std.stdio,
  std.conv : to;
import sdp.meta.rgx;
template PodManifest() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  auto PodManifest(P)(
    P   _pth = "",
  ) {
    struct ManifestFile_ {
      auto pod_manifest_filename() {
        string _manifest_file = "sisupod.manifest";
        return _manifest_file;
      }
      auto pod_manifest_path() {
        string _manifest_path;
        if (isValidPath(_pth) && _pth.isDir
        && ((_pth.chainPath(pod_manifest_filename).array).isFile)) {
          _manifest_path = _pth;
        } else if (_pth.match(rgx.src_pth_contents)
        && (_pth.isFile)) {
          _manifest_path = dirName(_pth);
        // } else { // _manifest_path = "";
        }
        return _manifest_path;
      }
      auto pod_manifest_file_with_path() {
        string _manifest_path_and_file = pod_manifest_path.chainPath(pod_manifest_filename).array;
        return _manifest_path_and_file;
      }
    }
    return ManifestFile_();
  }
}
template PodMatters() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  auto PodMatters(O,E,P,F)(
    O   _opt_actions,
    E   _env,
    P   _pth                   = "",
    F   _fns                   = "",
    char[][] _manifest_fn_list = [[]],
  ) {
    auto _manifest = PodManifest!()(_pth);
    struct ManifestMatters_ {
      auto pwd() {
        return _env["pwd"];
      }
      auto home() {
        return _env["home"];
      }
      auto opt_action() {
        return _opt_actions;
      }
      auto is_pod() {
        auto _is_pod = (_manifest.pod_manifest_path.length > 0) ? true : false;
        return _is_pod;
      }
      auto pod_manifest_list_of_filenames() {
        return _manifest_fn_list;
      }
      auto pod_manifest_list_of_languages() {
        string[] _lngs;
        foreach (filename_; pod_manifest_list_of_filenames) {
          string _k = "en";
          if (auto m = (filename_).match(rgx.language_code_and_filename)) {
            _k = m.captures[1].to!string;
          }
          _lngs ~= _k; // all the languages from the manifest list of filenames with paths
        }
        return _lngs;
      }
      auto pod_manifest_filename() {
        return _manifest.pod_manifest_filename;
      }
      auto pod_manifest_path() {
        return _manifest.pod_manifest_path;
      }
      auto pod_manifest_file_with_path() {
        return _manifest.pod_manifest_file_with_path;
      }
      auto pod_config_dirs() {                              // TODO
        string[] _config_dirs;
        return _config_dirs;
      }
      auto pod_image_dirs() {                               // TODO
        string[] _image_dirs;
        return _image_dirs;
      }
      auto src_path_and_fn() {
        return _fns;
      }
      auto src_fn() {
        auto _fn = (src_path_and_fn).match(rgx.src_pth_sst_or_ssm).captures["filename"];
        return _fn;
      }
      auto src_lng() {
        string _k;
        if (auto m = (src_path_and_fn).match(rgx.language_code_and_filename)) {
          _k = m.captures[1];
        } else {
          _k = "en";
        }
        return _k;
      }
      auto output_path() {
        auto _output_path = pwd;
        if ((_opt_actions.output_dir_set.length > 0)
          && isValidPath(_opt_actions.output_dir_set)
        ) {
          _output_path = asNormalizedPath(_opt_actions.output_dir_set).array;
          if (!exists(_output_path)) {
            try {
              _output_path.mkdirRecurse;
            }
            catch (Exception ex) {
              // Handle error
            }
          }
          assert(_output_path.isDir,
            "not a directory: " ~ _output_path);
          // TODO always test that is a directory and it is writable
        }
        return _output_path;
      }
      auto src_config_dirs() {                              // TODO
        string[] _config_dirs;
        if (is_pod) {
        } else {
        }
        return _config_dirs;
      }
      auto src_image_dirs() {                               // TODO
        string[] _image_dirs;
        if (is_pod) {
        } else {
        }
        return _image_dirs;
      }
    }
    return ManifestMatters_();
  }
}
template ConfigFilePaths() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  auto ConfigFilePaths(M,E)(
    M   _manifest,
    E   _env,
  ) {
    struct ConfFilePaths {
      auto config_filename_document() {
        return "config_document";
      }
      auto possible_config_path_locations_document() {
        /+ FIX clean up conf paths ↓ +/
        /+ config local site (file system only, not in pod) +/
        /+ return paths +/
        string[] _possible_config_path_locations;
        if (_manifest.is_pod) {
          /+ config document in pod +/
          string _sisudoc_conf_pod;
          string _sisudoc_conf_pod_text;
          _sisudoc_conf_pod = asNormalizedPath(chainPath(
            to!string(_env["pwd"]),
            _manifest.pod_manifest_path ~ "/conf"
          )).array;
          _sisudoc_conf_pod_text = asNormalizedPath(chainPath(
            to!string(_env["pwd"]),
            _manifest.pod_manifest_path ~ "/media/text/" ~ _manifest.src_lng ~ "/conf"
          )).array;
          /+ return paths +/
          _possible_config_path_locations = [
            _sisudoc_conf_pod_text,
            _sisudoc_conf_pod,
          ];
        } else {
          /+ config document (& or local site) on filesystem +/
          string _sisudoc_conf_pwd   = asNormalizedPath(chainPath(to!string(_env["pwd"]), "sisudoc/conf")).array; // think about
          string _sisudoc_conf_pwd_a = asNormalizedPath(chainPath(to!string(_env["pwd"]), "conf")).array;
          string _sisudoc_conf_pwd_b = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../conf")).array;
          string _sisudoc_conf_pwd_c = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../../conf")).array;
          string _sisudoc_conf_pwd_d = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../../../conf")).array;
          /+ return paths +/
          _possible_config_path_locations = [
            _sisudoc_conf_pwd,
            _sisudoc_conf_pwd_a,
            _sisudoc_conf_pwd_b,
            _sisudoc_conf_pwd_c,
            _sisudoc_conf_pwd_d,
          ];
        }
        /+ FIX clean up conf paths ↑
        (compare pwd to doc path location, and build config path)
        +/
        return _possible_config_path_locations;
      }
      auto config_filename_site() {
        return "config_local_site";
      }
      auto possible_config_path_locations_local_site() {
        /+ FIX clean up conf paths ↓ +/
        /+ config local site (file system only, not in pod) +/
        string _dot_pwd        = asNormalizedPath(chainPath(to!string(_env["pwd"]), ".sisu")).array;
        string _underscore_pwd = asNormalizedPath(chainPath(to!string(_env["pwd"]), "_sisu")).array;
        string _dot_home       = asNormalizedPath(chainPath(to!string(_env["home"]), ".sisu")).array;
        /+ return paths +/
        string[] _possible_config_path_locations;
        if (_manifest.is_pod) {
          _possible_config_path_locations = [
            _dot_pwd,
            _underscore_pwd,
            _dot_home,
            "/etc/sisu"
          ];
        } else {
          /+ config document (& or local site) on filesystem +/
          string _sisudoc_conf_pwd   = asNormalizedPath(chainPath(to!string(_env["pwd"]), "sisudoc/conf")).array; // think about
          string _sisudoc_conf_pwd_a = asNormalizedPath(chainPath(to!string(_env["pwd"]), "conf")).array;
          string _sisudoc_conf_pwd_b = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../conf")).array;
          string _sisudoc_conf_pwd_c = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../../conf")).array;
          string _sisudoc_conf_pwd_d = asNormalizedPath(chainPath(to!string(_env["pwd"]), "../../../conf")).array;
          _possible_config_path_locations = [
            _sisudoc_conf_pwd,
            _sisudoc_conf_pwd_a,
            _sisudoc_conf_pwd_b,
            _sisudoc_conf_pwd_c,
            _sisudoc_conf_pwd_d,
            _dot_pwd,
            _underscore_pwd,
            _dot_home,
            "/etc/sisu"
          ];
        }
        /+ FIX clean up conf paths ↑
        (compare pwd to doc path location, and build config path)
        +/
        return _possible_config_path_locations;
      }
    }
    return ConfFilePaths();
  }
}
template SiSUpathsSRC() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  auto SiSUpathsSRC(D,Fn)(
    D   _pwd,
    Fn  _fn_src_and_relative_path,
  ) {
    struct SisuSrcPaths {
      auto pwd() {
        return _pwd;
      }
      auto language() {
        // use command line info as well?
        string _k;
        if (auto m = _fn_src_and_relative_path.match(rgx.language_code_and_filename)) {
          _k = m.captures[1];
        } else { /+ unknown until doc_meta read, (could provide & use command line info?) +/
          _k = "xx"; // original default was "en" but is not known
        }
        return _k;
      }
      auto doc_root() {
        return "sisudoc";
      }
      auto media_root() {
        return asNormalizedPath(doc_root.chainPath("media")).array;
      }
      auto conf_root() {
        return asNormalizedPath(doc_root.chainPath("conf")).array;
      }
      auto text_root() {
        return asNormalizedPath(media_root.chainPath("text")).array;
      }
      auto image_root() {
        return asNormalizedPath(media_root.chainPath("image")).array;
      }
      auto doc_src_fn_with_path_for_text_root_and_lng() {
        return asNormalizedPath(text_root.chainPath(language)).array;
      }
      auto doc_src_with_relative_path() {
        return asNormalizedPath(pwd.chainPath(_fn_src_and_relative_path)).array;
      }
      auto doc_src_fn() {
        return asNormalizedPath(_fn_src_and_relative_path.baseName).array;
      }
    }
    return SisuSrcPaths();
  }
}
template SiSUpathsSisupod() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  string _base_dir_pod = "sisupod";
  string _base_dir_doc = "sisudoc";
  string _suffix = ".zip";
  auto SiSUpathsSisupod()() {
    struct _PathsStruct {
      string base_filename(string fn_src) {
        auto pth = fn_src.baseName.stripExtension;
        return pth;
      }
      string sisupod_dir() {
        auto pth = _base_dir_pod;
        return pth;
      }
      string sisudoc_dir() {
        auto pth = _base_dir_doc;
        return pth;
      }
      string sisupod_filename(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename(fn_src) ~ _suffix).array;
        return pth;
      }
      string base_filesystem(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename(fn_src)).array;
        assert(pth == _base_dir_pod ~ "/"  ~ base_filename(fn_src),
          pth ~ " == "  ~ _base_dir_pod ~ "/" ~ base_filename(fn_src) ~ "?");
        return pth;
      }
      string base_pod(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename(fn_src)).array; // change this
        return pth;
      }
    }
    return _PathsStruct();
  }
}

template SiSUpathsSisupods() {
  mixin SiSUrgxInit;
  static auto rgx = Rgx();
  string _base_dir_pod = "sisupod";
  string _base_dir_doc = "sisudoc";
  string _suffix = ".zip";
  auto SiSUpathsSisupods()() {
    struct _PodPaths {
      string base_filename_(string fn_src) {
        auto pth = fn_src.baseName.stripExtension;
        return pth;
      }
      string sisupod_dir_() {
        auto pth = _base_dir_pod;
        return pth;
      }
      string sisudoc_dir_() {
        auto pth = _base_dir_doc;
        return pth;
      }
      string sisupod_filename_(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename_(fn_src) ~ _suffix).array;
        return pth;
      }
      string base_filesystem_(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename_(fn_src)).array;
        assert(pth == _base_dir_pod ~ "/"  ~ base_filename_(fn_src),
          pth ~ " == "  ~ _base_dir_pod ~ "/" ~ base_filename_(fn_src) ~ "?");
        return pth;
      }
      string base_pod_(string fn_src) {
        string pth = _base_dir_pod.chainPath(base_filename_(fn_src)).array; // change this
        return pth;
      }
      auto base_filename(string fn_src) {
        auto pth_1_ = base_filename_(fn_src);
        auto pth_2_ = base_filename_(fn_src);
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            return pth_2_;
          }
        }
        return _pods();
      }
      auto sisupod_filename(string fn_src) {
        auto pth_1_ = sisupod_filename_(fn_src);
        auto pth_2_ = sisupod_filename_(fn_src);
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            return pth_2_;
          }
        }
        return _pods();
      }
      auto base(string fn_src) {
        auto pth_1_ = "";
        auto pth_2_ = base_filesystem_(fn_src);
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            return pth_2_;
          }
        }
        return _pods();
      }
      auto pod_root(string fn_src) {
        auto pth_1_ = "";
        auto pth_2_ = asNormalizedPath(base(fn_src).filesystem_open_zpod.chainPath("")).array; // "sisudoc"
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            return pth_2_;
          }
        }
        return _pods();
      }
      auto conf_root(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = "conf";
        auto pth_2_ = asNormalizedPath(pod_root(fn_src).filesystem_open_zpod.chainPath("conf")).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto css(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(conf_root(fn_src).zpod.chainPath("css")).array;
        auto pth_2_ = asNormalizedPath(conf_root(fn_src).filesystem_open_zpod.chainPath("css")).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto media_root(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = "media";
        auto pth_2_ = asNormalizedPath(pod_root(fn_src).filesystem_open_zpod.chainPath("media")).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto text_root(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(media_root(fn_src).zpod.chainPath("text")).array;
        auto pth_2_ = asNormalizedPath(media_root(fn_src).filesystem_open_zpod.chainPath("text")).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto doc(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = text_root(fn_src).zpod;
        auto pth_2_ = text_root(fn_src).filesystem_open_zpod;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto doc_lng(string fn_src, string lng) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(text_root(fn_src).zpod.chainPath(lng)).array;
        auto pth_2_ = asNormalizedPath(text_root(fn_src).filesystem_open_zpod.chainPath(lng)).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto image_root(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(media_root(fn_src).zpod.chainPath("image")).array;
        auto pth_2_ = asNormalizedPath(media_root(fn_src).filesystem_open_zpod.chainPath("image")).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto fn_pod_filelist(string fn_src) {
        auto pod_root_ = pod_root(fn_src);
        auto _manifest = PodManifest!()(fn_src).pod_manifest_filename;
        auto pth_1_ = _manifest;
        auto pth_2_ = asNormalizedPath(pod_root(fn_src).filesystem_open_zpod.chainPath(_manifest)).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto fn_doc(string fn_src, string lng) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(doc_lng(fn_src, lng).zpod.chainPath(fn_src.baseName)).array;
        auto pth_2_ = asNormalizedPath(doc_lng(fn_src, lng).filesystem_open_zpod.chainPath(fn_src.baseName)).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
      auto fn_doc_insert(string fn_src, string fn_insert, string lng) {
        auto pod_root_ = pod_root(fn_src);
        auto pth_1_ = asNormalizedPath(doc_lng(fn_src, lng).zpod.chainPath(fn_insert.baseName)).array;
        auto pth_2_ = asNormalizedPath(doc_lng(fn_src, lng).filesystem_open_zpod.chainPath(fn_insert.baseName)).array;
        struct _pods {
          auto zpod() {
            return pth_1_;
          }
          auto filesystem_open_zpod() {
            assert(pod_root_.filesystem_open_zpod.chainPath(zpod).array == pth_2_);
            return pth_2_;
          }
        }
        return _pods();
      }
    }
    return _PodPaths();
  }
}