/***************************************************************************

    source::worx xtree
    Copyright © 2024-2025 c.holzheuer
    christoph.holzheuer@gmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#ifndef ZNODE_FACTORY_H
#define ZNODE_FACTORY_H

#include <pugixml.hpp>
#include <znode.h>

class xtree;

/*

nodes: nackt also ungekaspselt?
 -> children()
 -> attributes()

attributes:  ja was seid ihr denn? als string gelesen, als string geschrieben, aber dazwischen?

-> std::variant<bool...> mit enum type{t_bool = 0 ...};
-> conversion mit boost::lexical_cast<> bzw. std::to_string() und std::stoi(), std::stod()
-> beim parsen konvertieren? contains '.'? is_number?
-> betrifft tag_values und tag_attributes
-> vorher definieren? attribute 'voltage' == double, oder gar mehr: unit V, double, range
-> über xs:double?

model: muss ich wirklich jeden attibute node einzeln angeben?

*/
namespace znode
{
  template<typename str_t,typename payload_t>
  class znode_factory
  {

  public:

    using str_cref     = const str_t&;
    using zshared_node = std::shared_ptr< zbasic_node<str_t,payload_t> >;

    znode_factory() = default;
    virtual ~znode_factory() = default;

    zshared_node load_tree( const std::string& filename )
    {

      pugi::xml_document tree_document;
      // load document
      pugi::xml_parse_result result = tree_document.load_file( filename.c_str() );
      if( !result )
      {
        throw XQException( "znode_factory::load_tree: parse error: ", result.description() );
      }

      //MemberFunc func = &znode_factory::process_node;
      //xtreewalker<znode_factory, MemberFunc> parser(this,func);
      //_current_depth = -1;
      //tree_document.traverse(parser);

      //zbasic_node<str_t>* root_node = new zbasic_node<str_t>*("root!");
      zshared_node root_node = zbasic_node<str_t, payload_t>::make_node("root!");
      //T root_node = T::make_node( "root!" );

      // prepare root == model !?
      pugi::xml_node tmp_node = tree_document.first_child();
      while(tmp_node)
      {
        //qDebug() << " --- znode_factory building: " << tmp_node.name();
        create_node( tmp_node, root_node );
        tmp_node = tmp_node.next_sibling();
      }

      //znode::zmeas_para<QString>* xxx = new znode::zmeas_para<QString>("mookoo!");
      //xxx->apply_command(42);
      // _root_node->apply_command(42);
      //size_t idx = _root_node->add_child( xxx);
      //qDebug() << " jo: " << _root_node->child(idx)->tag_name();

      return root_node;
    }

  protected:

    void create_node(const pugi::xml_node& xml_node, zshared_node parent)
    {

      //T* new_node = new T( node.name(), node.child_value(), parent );
      //parent->add_child( new_node );

      //zbasic_node<str_t>* new_node = new zbasic_node<str_t>( node.name(), node.child_value(), parent );
      zshared_node new_node = zbasic_node<str_t, payload_t>::make_node( xml_node.name(), xml_node.child_value() );
      parent->add_child( new_node );

      if( !xml_node.attributes().empty() )
      {
        for (pugi::xml_attribute attr: xml_node.attributes())
          new_node->set_attribute(  attr.name(), attr.value() );
      }

      if( !xml_node.children().empty() && std::string( xml_node.child_value() ).empty() )
      {
        for (pugi::xml_node child : xml_node.children())
          create_node( child, new_node );
      }
    }

  };

}

#endif // ZNODE_FACTORY_H
