// Copyright (c) 2023 Dominic Masters
// 
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

#pragma once
#include "util/XmlParser.hpp"
#include "parse/event/textevent.hpp"
#include "parse/event/characterfadeevent.hpp"
#include "parse/event/pauseevent.hpp"

namespace Dawn {
  enum EventType {
    EVENT_TYPE_TEXT,
    EVENT_TYPE_CHARACTER_FADE,
    EVENT_TYPE_PAUSE
  };

  struct EventsInformation {
    std::map<int32_t, enum EventType> eventTypes;
    std::map<int32_t, struct TextEventInfo> textEvents;
    std::map<int32_t, struct CharacterFadeEventInfo> characterFadeEvents;
    std::map<int32_t, struct PauseEventInfo> pauseEvents;
    std::vector<std::string> includes;
    
    std::vector<struct LanguageString> strings;
    std::string key;
  };

  class EventsParser : public XmlParser<struct EventsInformation> {
    protected:
      std::vector<std::string> getRequiredAttributes() {
        return std::vector<std::string>{
        };
      }

      std::map<std::string, std::string> getOptionalAttributes() {
        return std::map<std::string, std::string>();
      }

      int32_t onParse(
        Xml *node,
        std::map<std::string, std::string> values,
        struct EventsInformation *out,
        std::string *error
      ) {
        int32_t ret = 0;
        int32_t i = 0;
        int32_t languageKeyNumber = 1;

        if(out->key.size() <= 0) {
          *error = "Events requries a language key to be defined.";
          return 1;
        }

        auto itChildren = node->children.begin();
        while(itChildren != node->children.end()) {
          auto c = *itChildren;
          
          if(c->node == "text") {
            struct TextEventInfo textEvent;
            textEvent.key = out->key + "." + std::to_string(languageKeyNumber++);
            ret = (TextEventParser()).parse(c, &textEvent, error);
            out->eventTypes[i] = EVENT_TYPE_TEXT;
            out->textEvents[i++] = textEvent;
            vectorAppend(&out->strings, textEvent.strings);

          } else if(c->node == "character-fade") {
            struct CharacterFadeEventInfo charFadeEvent;
            ret = (CharacterFadeParser()).parse(c, &charFadeEvent, error);
            out->eventTypes[i] = EVENT_TYPE_CHARACTER_FADE;
            out->characterFadeEvents[i++] = charFadeEvent;
            out->includes.push_back(charFadeEvent.include);

          } else if(c->node == "pause") {
            struct PauseEventInfo pauseEvent;
            ret = (PauseEventParser()).parse(c, &pauseEvent, error);
            out->eventTypes[i] = EVENT_TYPE_PAUSE;
            out->pauseEvents[i++] = pauseEvent;
            out->includes.push_back(pauseEvent.include);

          }

          ++itChildren;
        }

        return ret;
      }
  };

  class EventsGen : public CodeGen {
    public:
      static void generate(
        std::vector<std::string> *out,
        struct EventsInformation *info,
        std::string tabs
      ) {
        auto itEvents = info->eventTypes.begin();
        while(itEvents != info->eventTypes.end()) {
          auto e = *itEvents;
          line(out, "->then(", tabs);
          switch(e.second) {
            case EVENT_TYPE_TEXT:
              TextEventGen::generate(out, &info->textEvents[e.first], tabs + "  ");
              break;
            
            case EVENT_TYPE_CHARACTER_FADE:
              CharacterFadeGen::generate(out, &info->characterFadeEvents[e.first], tabs + "  ");
              break;

            case EVENT_TYPE_PAUSE:
              PauseEventGen::generate(out, &info->pauseEvents[e.first], tabs + "  ");
              break;

          }
          line(out, ")", tabs);
          ++itEvents;
        }
      }
  };
}