/*
* Author:          Patrick-Christopher Mattulat
* Co-Author:       Claude Sonnet 4.6 (LLM)
* Company:         Lynar Studios
* E-Mail:          webmaster@lynarstudios.com
* Created:         2023-02-11
* Changed:         2026-06-23
*
* */

#include <ls-std/core/evaluator/NullPointerArgumentEvaluator.hpp>
#include <ls-std/io/section-pair/evaluator/SectionPairRowListValueArgumentEvaluator.hpp>
#include <ls-std/io/section-pair/evaluator/SectionPairRowSingleValueArgumentEvaluator.hpp>
#include <ls-std/io/section-pair/model/SectionPairRow.hpp>
#include <ls-std/io/section-pair/model/SectionPairRowListValue.hpp>
#include <ls-std/io/section-pair/model/SectionPairRowSingleValue.hpp>
#include <ls-std/io/section-pair/serialization/SerializableSectionPairRow.hpp>

using ls::standard::core::Class;
using ls::standard::core::NullPointerArgumentEvaluator;
using ls::standard::core::type::byte_field;
using ls::standard::io::SectionPairRow;
using ls::standard::io::SectionPairRowListValue;
using ls::standard::io::SectionPairRowListValueArgumentEvaluator;
using ls::standard::io::SectionPairRowSingleValue;
using ls::standard::io::SectionPairRowSingleValueArgumentEvaluator;
using ls::standard::io::SerializableSectionPairParameter;
using ls::standard::io::SerializableSectionPairRow;
using std::dynamic_pointer_cast;
using std::shared_ptr;
using std::string;

SerializableSectionPairRow::SerializableSectionPairRow(const SerializableSectionPairParameter &_parameter) : Class("SerializableSectionPairRow"), parameter(_parameter)
{
  const string message = this->getClassName() + ": model reference is null!";
  NullPointerArgumentEvaluator{_parameter.getValue(), message}.evaluate();
}

SerializableSectionPairRow::~SerializableSectionPairRow() noexcept = default;

shared_ptr<Class> SerializableSectionPairRow::getValue() const
{
  return this->parameter.getValue();
}

byte_field SerializableSectionPairRow::marshal()
{
  const byte_field data = this->_marshalKey();
  const shared_ptr<SectionPairRow> row = dynamic_pointer_cast<SectionPairRow>(this->parameter.getValue());
  row->getValue()->reserveNewLine(this->parameter.getNewLine());
  return data + row->getValue()->marshal();
}

void SerializableSectionPairRow::unmarshal(const byte_field &_data)
{
  const shared_ptr<SectionPairRow> row = dynamic_pointer_cast<SectionPairRow>(this->parameter.getValue());
  row->getValue()->reserveNewLine(this->parameter.getNewLine());

  if (row->isSingleValue())
  {
    this->_unmarshalSingleValue(_data);
  }

  if (row->isList())
  {
    this->_unmarshalListValue(_data);
  }
}

string SerializableSectionPairRow::_marshalKey() const
{
  string serializedKey{};
  const shared_ptr<SectionPairRow> row = dynamic_pointer_cast<SectionPairRow>(this->parameter.getValue());

  if (row->isSingleValue())
  {
    serializedKey = row->getKey() + "=";
  }

  if (row->isList())
  {
    serializedKey = row->getKey() + ":" + this->parameter.getNewLine();
  }

  return serializedKey;
}

void SerializableSectionPairRow::_unmarshalListValue(const byte_field &_data) const
{
  SectionPairRowListValueArgumentEvaluator{_data}.evaluate();
  const string::size_type separatorPosition = _data.find(':');
  const string newLine = this->parameter.getNewLine();

  if (separatorPosition != string::npos)
  {
    const shared_ptr<SectionPairRow> row = dynamic_pointer_cast<SectionPairRow>(this->parameter.getValue());
    row->setKey(_data.substr(0, separatorPosition));
    const string::size_type newLinePosition = _data.find(newLine) + (newLine.size() - 1);
    dynamic_pointer_cast<SectionPairRowListValue>(row->getValue())->unmarshal(_data.substr(newLinePosition + 1));
  }
}

void SerializableSectionPairRow::_unmarshalSingleValue(const byte_field &_data) const
{
  SectionPairRowSingleValueArgumentEvaluator{_data}.evaluate();

  if (const string::size_type position = _data.find('='); position != string::npos)
  {
    const shared_ptr<SectionPairRow> row = dynamic_pointer_cast<SectionPairRow>(this->parameter.getValue());
    row->setKey(_data.substr(0, position));
    dynamic_pointer_cast<SectionPairRowSingleValue>(row->getValue())->unmarshal(_data.substr(position + 1));
  }
}
