#include "indoor_formatter.h"

#include "formatter_helpers.h"
#include "poi_def.h"

#include <maps/libs/common/include/exception.h>

using namespace std::string_literals;

namespace maps::wiki::poi {
namespace {
const auto TEMPLATE_KEY = "indoor_company_template"s;

const char INDOOR_COMPANY_XML_TEMPLATE[] = R"(
{{%AUTOESCAPE context="XML"}}
<company>
  <company-id>{{POI_ID}}</company-id>
  <disp_class>{{DISP_CLASS}}</disp_class>

  {{#ONE_POI_NAME}}
  <name lang="{{POI_NAME_LANG}}">{{POI_NAME_VALUE}}</name>
  {{/ONE_POI_NAME}}

  {{#ONE_POI_SHORT_NAME}}
  <shortname lang="{{POI_NAME_LANG}}">{{POI_NAME_VALUE}}</shortname>
  {{/ONE_POI_SHORT_NAME}}

  {{#ONE_POI_SYNONYM_NAME}}
  <synonym lang="{{POI_NAME_LANG}}">{{POI_NAME_VALUE}}</synonym>
  {{/ONE_POI_SYNONYM_NAME}}

  <coordinates>
    <lon>{{POI_LON}}</lon>
    <lat>{{POI_LAT}}</lat>
  </coordinates>

  {{#POI_RUBRIC_ID_SECTION}}
  <rubric-id>{{POI_RUBRIC_ID}}</rubric-id>
  {{/POI_RUBRIC_ID_SECTION}}

  {{#POI_SECONDARY_RUBRIC_IDS_SECTION}}
  <secondary-rubric-id>{{POI_SECONDARY_RUBRIC_ID}}</secondary-rubric-id>
  {{/POI_SECONDARY_RUBRIC_IDS_SECTION}}

  <actualization-date>{{POI_ACT_DATE}}</actualization-date>

  {{#POI_MODIFIED_BY_SECTION}}
  <modified-by>{{POI_MODIFIED_BY}}</modified-by>
  {{/POI_MODIFIED_BY_SECTION}}

  {{#POI_PERMALINK_SECTION}}
  <permalink>{{POI_PERMALINK}}</permalink>
  {{/POI_PERMALINK_SECTION}}

  <indoor-level-universal>{{POI_INDOOR_LEVEL_UNIVERSAL}}</indoor-level-universal>
</company>
)";

} // anonymous namespace


IndoorXmlFormatter::IndoorXmlFormatter(std::ostream& out)
    : emitter_(out)
{
    emitter_.Emit("<?xml version='1.0' encoding='UTF-8'?>\n");
    emitter_.Emit("<companies"
                  " xmlns:xi='http://www.w3.org/2001/XInclude'"
                  " version='2.1'>\n");
    ct::StringToTemplateCache(TEMPLATE_KEY, INDOOR_COMPANY_XML_TEMPLATE,
                              ct::STRIP_BLANK_LINES);
}

void
IndoorXmlFormatter::append(const PoiDef& def)
{
    ct::TemplateDictionary dict(TEMPLATE_KEY);
    REQUIRE(def.id, "unspecified POI_ID");
    dict.SetValue("POI_ID", std::to_string(def.id.get()));
    dict.SetValue("DISP_CLASS", std::to_string(def.dispClass));
    REQUIRE(def.actualizationDate, "unspecified POI_ACT_DATE");
    dict.SetValue(
        "POI_ACT_DATE",
        std::to_string(chrono::sinceEpoch<std::chrono::milliseconds>(def.actualizationDate.get()))
    );
    dumpRubrics(def, dict);
    REQUIRE(def.lat, "unspecified POI_LAT");
    dict.SetValue("POI_LAT", std::to_string(def.lat.get()));
    REQUIRE(def.lon, "unspecified POI_LON");
    dict.SetValue("POI_LON", std::to_string(def.lon.get()));
    for (const auto& name : def.names) {
        auto* nameTemplate = dict.AddSectionDictionary("ONE_POI_NAME");
        nameTemplate->SetValue("POI_NAME_LANG", name.lang);
        nameTemplate->SetValue("POI_NAME_VALUE", name.value);
    }
    for (const auto& name : def.shortNames) {
        auto* nameTemplate
            = dict.AddSectionDictionary("ONE_POI_SHORT_NAME");
        nameTemplate->SetValue("POI_NAME_LANG", name.lang);
        nameTemplate->SetValue("POI_NAME_VALUE", name.value);
    }
    for (const auto& name : def.synonymNames) {
        auto* nameTemplate
            = dict.AddSectionDictionary("ONE_POI_SYNONYM_NAME");
        nameTemplate->SetValue("POI_NAME_LANG", name.lang);
        nameTemplate->SetValue("POI_NAME_VALUE", name.value);
    }
    if (!def.permalink.empty()) {
        dict.SetValueAndShowSection("POI_PERMALINK", def.permalink,
                                    "POI_PERMALINK_SECTION");
    }
    if (def.modifiedBy) {
        dict.SetValueAndShowSection("POI_MODIFIED_BY", std::to_string(*def.modifiedBy),
                                    "POI_MODIFIED_BY_SECTION");
    }
    REQUIRE(!def.indoorLevelUniversal.empty(),
        "Formatter is for indoor poi only.");
    dict.SetValue("POI_INDOOR_LEVEL_UNIVERSAL", def.indoorLevelUniversal);
    ct::ExpandTemplate(TEMPLATE_KEY, ct::STRIP_BLANK_LINES, &dict,
                       &emitter_);
}

IndoorXmlFormatter::~IndoorXmlFormatter()
{
    emitter_.Emit("</companies>");
}

} // namespace maps::wiki::poi:

