/*
 * This project is licensed under the MIT license. For more information see the
 * LICENSE file.
 */
#pragma once

// -----------------------------------------------------------------------------

#include <functional>
#include <regex>
#include <string>

#include "maddy/blockparser.h"

// -----------------------------------------------------------------------------

namespace maddy {

// -----------------------------------------------------------------------------

/**
 * HeadlineParser
 *
 * From Markdown:
 *
 * ```
 * # Headline 1
 * ## Headline 2
 * ### Headline 3
 * #### Headline 4
 * ##### Headline 5
 * ###### Headline 6
 * ```
 *
 * To HTML:
 *
 * ```
 * <h1>Headline 1</h1>
 * <h2>Headline 2</h2>
 * <h3>Headline 3</h3>
 * <h4>Headline 4</h4>
 * <h5>Headline 5</h5>
 * <h6>Headline 6</h6>
 * ```
 *
 * @class
 */
class HeadlineParser : public BlockParser
{
public:
  /**
   * ctor
   *
   * @method
   * @param {std::function<void(std::string&)>} parseLineCallback
   * @param {std::function<std::shared_ptr<BlockParser>(const std::string&
   * line)>} getBlockParserForLineCallback
   */
  HeadlineParser(
    std::function<void(std::string&)> parseLineCallback,
    std::function<std::shared_ptr<BlockParser>(const std::string& line)>
      getBlockParserForLineCallback,
    bool isInlineParserAllowed = true
  )
    : BlockParser(parseLineCallback, getBlockParserForLineCallback)
    , isInlineParserAllowed(isInlineParserAllowed)
  {}

  /**
   * IsStartingLine
   *
   * If the line starts with 1 - 6 `#`, then it is a headline.
   *
   * @method
   * @param {const std::string&} line
   * @return {bool}
   */
  static bool IsStartingLine(const std::string& line)
  {
    static std::regex re("^(?:#){1,6} (.*)");
    return std::regex_match(line, re);
  }

  /**
   * IsFinished
   *
   * The headline is always only one line long, so this method always returns
   * true.
   *
   * @method
   * @return {bool}
   */
  bool IsFinished() const override { return true; }

protected:
  bool isInlineBlockAllowed() const override { return false; }

  bool isLineParserAllowed() const override
  {
    return this->isInlineParserAllowed;
  }

  void parseBlock(std::string& line) override
  {
    static std::vector<std::regex> hlRegex = {
      std::regex("^# (.*)"),
      std::regex("^(?:#){2} (.*)"),
      std::regex("^(?:#){3} (.*)"),
      std::regex("^(?:#){4} (.*)"),
      std::regex("^(?:#){5} (.*)"),
      std::regex("^(?:#){6} (.*)")
    };
    static std::vector<std::string> hlReplacement = {
      "<h1>$1</h1>",
      "<h2>$1</h2>",
      "<h3>$1</h3>",
      "<h4>$1</h4>",
      "<h5>$1</h5>",
      "<h6>$1</h6>"
    };

    for (uint8_t i = 0; i < 6; ++i)
    {
      line = std::regex_replace(line, hlRegex[i], hlReplacement[i]);
    }
  }

private:
  bool isInlineParserAllowed;
}; // class HeadlineParser

// -----------------------------------------------------------------------------

} // namespace maddy
