/*
  GEN-NODE.hpp  -  generic node element for tree like data representation

  Copyright (C)         Lumiera.org
    2015,               Hermann Vosseler <Ichthyostega@web.de>

  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.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/


/** @file gen-node.hpp
 ** Generic building block for tree shaped (meta)data structures.
 ** A representation built from GenNode elements is intended to support
 ** (limited) introspection of data structures and exchange of mutations
 ** in the form of \link diff-language.hpp diff messages. \endlink
 ** 
 ** Despite of the name, GenNode is \em not meant to be an universal
 ** data representation; rather it is limited to embody a fixed hard
 ** wired set of data types, able to stand-in for attributes
 ** and sub scope contents of the lumiera high-level data model.
 ** 
 ** \par Anatomy of a GenNode
 ** 
 ** GenNode is a polymorphic value with well defined identity and type.
 ** Each element is conceived to be »unique within context« -- as defined
 ** by the immediately visible scope within a tree like structure.
 ** Beyond this identity metadata, each GenNode carries a DataCap, which
 ** is an inline container and attachment point for payload data. Simple
 ** attribute values can be carried alongside, while more complex types
 ** or entities bound to a reference and registration system (e.g. Placement)
 ** will be referred by a suitable reference representation (PlacementID).
 ** The DataCap is what creates the polymorphic nature, where the common
 ** interface is mostly limited to managemental tasks (copying of values,
 ** external representation).
 ** 
 ** To represent object-like structures and for building trees, a special
 ** kind of data type is placed into the DataCap. This type, Record<GenNode>
 ** is recursive and has the ability to hold both a a set of attributes
 ** addressable by-name and an (ordered) collection of elements treated
 ** as children within the scope of the given record.
 ** 
 ** \par Requirements
 ** 
 ** GenNode elements are to be used in the diff detection and implementation.
 ** This implies some requirements for the (opaque) elements used in diff:
 ** - they need to support the notion of equality
 ** - we need to derive a key type for usage in index tables
 **   - this implies the necessity to support std::less comparisons for tree-maps
 **   - and the necessity to support hash code generation for unordered (hash)maps
 ** - moreover, the elements need to be values, able to be copied and handled at will
 ** - it will be beneficial for these values to support move semantics explicitly
 ** - in addition, the tree diffing suggests a mechanism to re-gain the fully
 **   typed context, either based on some kind of embedded type tag, or
 **   alternatively by visitation and matching
 ** - finally, the handling of changes prompts us to support installation
 **   of a specifically typed <i>change handling closure</i>.
 ** 
 ** \par monadic nature?
 ** 
 ** As suggested by the usage for representation of tree shaped data, we acknowledge
 ** that GenNode could be a Monad. We support the basic operation \em construction,
 ** and the operation \em flatMap would be trivial to add. To fit in with this generic
 ** processing pattern, the one element flavours of GenNode are considered the special case,
 ** while the collective flavours form the base case -- every GenNode can be iterated.
 ** The \em construction requirement suggests that GenNode may be created readily, just
 ** by wrapping any given and suitable element, thereby picking up the element's type.
 ** 
 ** But the purpose and goal of the monadic approach is not clear yet (5/2015).
 ** To begin with, for the task of diff detection and application, it is sufficient
 ** to get the children as traversable collection and to offer a depth-first expansion.
 ** 
 ** @see GenNodeBasic_test
 ** @see diff-list-generation-test.cpp
 ** @see DiffDetector
 ** 
 */


#ifndef LIB_DIFF_GEN_NODE_H
#define LIB_DIFF_GEN_NODE_H


#include "lib/error.hpp"
#include "lib/idi/entry-id.hpp"
#include "lib/time/timevalue.hpp"
//#include "lib/format-util.hpp"        ///////////////////////////////TICKET #973 : investigate the impact of this inclusion on code size
#include "lib/diff/record.hpp"
#include "lib/variant.hpp"
#include "lib/util.hpp"

//#include <vector>
#include <utility>
#include <string>
#include <deque>
//#include <map>


namespace lib {
namespace diff{
  
  namespace error = lumiera::error;
  
  using std::string;
  
  struct GenNode;
  struct Ref;
  
  /** Define actual data storage and access types used */
  template<>
  struct RecordSetup<GenNode>
    {
      using Storage = std::vector<GenNode>;
      using ElmIter = typename Storage::const_iterator;
      
      /** using const reference data access
       *  relevant for handling large subtrees */
      using Access  = GenNode const&;
    };
  
  
  
  
  using Rec = Record<GenNode>;
  using RecRef = RecordRef<GenNode>;
  using MakeRec = Rec::Mutator;
  using DataValues = meta::Types<int
                                ,int64_t
                                ,short
                                ,char
                                ,bool
                                ,double
                                ,string
                                ,time::Time
                                ,time::Offset
                                ,time::Duration
                                ,time::TimeSpan
                                ,hash::LuidH
                                ,RecRef
                                ,Rec
                                >;
  
  
  
  class DataCap
    : public Variant<DataValues>
    {
    public:
      template<typename X>
      DataCap(X&& x)
        : Variant<DataValues>(std::forward<X>(x))
        { }
      
                                       ////////////////////////TICKET #963  Forwarding shadows copy operations -- generic solution??
      DataCap(DataCap const&) =default;
      DataCap(DataCap&&)      =default;
      DataCap(DataCap& o)
        : DataCap((DataCap const&)o)
        { }
      
      DataCap& operator= (DataCap const&)  =default;
      DataCap& operator= (DataCap&&)       =default;
      
      bool matchData (DataCap const&)  const;
      bool matchNum  (int64_t)         const;
      bool matchTxt  (string const&)   const;
      bool matchTime (time::TimeValue) const;
      bool matchBool (bool)            const;
      bool matchDbl  (double)          const;
      bool matchLuid (hash::LuidH)     const;
      bool matchRec  (RecRef const&)   const;
      bool matchRec  (Rec const&)      const;
      
      struct Locator;
      Locator expand()  const;
      
      operator string() const;
      
      template<typename X>
      X& get();
      template<typename X>
      X const& get()  const;
    };
  
  
  /** generic data element node within a tree */
  struct GenNode
    {
      class ID
        : public idi::BareEntryID
        {
          friend struct GenNode;
          
          template<typename X>
          ID (X*, string const& symbolicID)
            : idi::BareEntryID (symbolicID,
                                idi::getTypeHash<X>())
            { }
          
        public:
          ID (GenNode const& node)
            : ID(node.idi)
            { }
          
          // standard copy operations acceptable
          
          operator string()  const
            {
              return "ID(\""+getSym()+"\")";
            }
        };
      
      
      //------GenNode Data fields---
      
      ID      idi;
      DataCap data;
      
      
      template<typename X>
      GenNode(X&& val)
        : idi(&val, buildChildID<X>())
        , data(std::forward<X>(val))
        { }
      
      template<typename X>
      GenNode(string const& symbolicID, X&& val)
        : idi(&val, symbolicID)
        , data(std::forward<X>(val))
        { }
      
      GenNode(string const& symbolicID, const char* text)
        : GenNode(symbolicID, string(text))
        { }
      
      GenNode(const char* text)
        : GenNode(string(text))
        { }
      
                                       ////////////////////////TICKET #963  Forwarding shadows copy operations -- generic solution??
      GenNode(GenNode const&)  =default;
      GenNode(GenNode&&)       =default;
      GenNode(GenNode& o)  : GenNode((GenNode const&)o) { }
      GenNode(Ref const& r);
      GenNode(Ref &  r);
      GenNode(Ref && r);
      
      GenNode& operator= (GenNode const&)  =default;
      GenNode& operator= (GenNode&&)       =default;
      
      
      
      /** @internal diagnostics helper. Include format-helper.cpp on use */
      operator string()  const
        {
          return "GenNode-"+string(idi)+"-"+string(data);
        }
      
      bool
      isNamed()  const
        {
          return not util::startsWith (idi.getSym(), "_CHILD_");
        }
      
      bool
      isTypeID()  const
        {
          return "type" == idi.getSym();
        }
      
      template<typename X>
      bool contains (X const& elm)  const;
      
      
      bool matches (GenNode const& o)  const { return this->matches(o.idi); }  ///< @note \em not comparing payload data. Use equality for that…
      bool matches (ID const& id)      const { return idi == id; }
      bool matches (int     number)    const { return data.matchNum(number);}
      bool matches (int64_t number)    const { return data.matchNum(number);}
      bool matches (short   number)    const { return data.matchNum(number);}
      bool matches (char    number)    const { return data.matchNum(number);}
      bool matches (double  number)    const { return data.matchDbl(number);}
      bool matches (string text)       const { return data.matchTxt(text);}
      bool matches (const char* text)  const { return data.matchTxt(text);}
      bool matches (time::TimeValue t) const { return data.matchTime(t);  }
      bool matches (bool b)            const { return data.matchBool(b);  }
      bool matches (hash::LuidH h)     const { return data.matchLuid(h);  }
      bool matches (RecRef const& ref) const { return data.matchRec(ref); }
      bool matches (Rec const& rec)    const { return data.matchRec(rec); }
      
      class ScopeExplorer;
      
      struct ScopeExplorerIterator;
      using iterator = ScopeExplorerIterator;
      
      iterator begin()      ;
      iterator begin() const;
      iterator end()        ;
      iterator end()   const;
      
      
      friend string
      name (GenNode const& node)
      {
        return node.idi.getSym();
      }
      
      friend bool
      operator== (GenNode const& n1, GenNode const& n2)
      {
        return n1.idi == n2.idi
            && n1.data.matchData(n2.data);
      }
      
      friend bool
      operator!= (GenNode const& n1, GenNode const& n2)
      {
        return not (n1 == n2);
      }
      
    
    protected:
      /** @internal for dedicated builder subclasses */
      GenNode (ID&& id, DataCap&& d)
        : idi(std::move(id))
        , data(std::move(d))
        { }
      
      template<typename X>
      static GenNode::ID
      fabricateRefID (string const& symbolicID)
        {
          X* typeID(0);
          return ID(typeID, symbolicID);
        }
      
    private:
      template<typename X>
      static string
      buildChildID()
        {
          return "_CHILD_" + idi::generateSymbolicID<X>();
        }
    };
  
  
  
  /* === iteration / recursive expansion === */
  
  
  /**
   * @internal Helper to refer to any element position,
   * irrespective if on top level or within a nested scope
   * @remarks typically used within lib::IterStateWrapper
   * @see DataCap#expand()
   */
  struct DataCap::Locator
    {
      const GenNode* node_;
      Rec::iterator scope_;
      
      Locator()
        : node_(nullptr)
        { }
      
      Locator(GenNode const& n)
        : node_(&n)
        { }
      
      Locator(Rec const& r)
        : node_(nullptr)
        , scope_(r.begin())
        { }
      
      const GenNode *
      get()  const
        {
          return node_? node_
                      : scope_? scope_.operator->()
                              : nullptr;
        }
      
      /* === Iteration control API for IterStateWrapper == */
      
      friend bool
      checkPoint (Locator const& loc)
      {
        return loc.get();
      }
      
      friend GenNode const&
      yield (Locator const& loc)
      {
        return *loc.get();
      }
      
      friend void
      iterNext (Locator & loc)
      {
        if (loc.node_)
          loc.node_ = nullptr;
        else
          ++loc.scope_;
      }
    };
  
  
  /**
   * Building block for monad-like depth-first expansion of a GenNode.
   * When used within lib::IterStateWrapper, the result is an Iterator
   * to visit the contents of a GenNodet tree recursively depth-fist.
   */
  class GenNode::ScopeExplorer
    {
      using ScopeIter = IterStateWrapper<const GenNode, DataCap::Locator>;
      
      std::deque<ScopeIter> scopes_;
      
    public:
      ScopeExplorer() { }
      ScopeExplorer(GenNode const& n)
        {
          scopes_.emplace_back(n);
        }
      
      size_t
      depth()  const
        {
          return scopes_.size();
        }
      
      /* === Iteration control API for IterStateWrapper == */
      
      friend bool
      checkPoint (ScopeExplorer const& explorer)
      {
        return not  explorer.scopes_.empty()
            && bool(explorer.scopes_.back());
      }
      
      friend GenNode const&
      yield (ScopeExplorer const& explorer)
      {
        return * (explorer.scopes_.back());
      }
      
      friend void
      iterNext (ScopeExplorer & explorer)
      {
        ScopeIter& current = explorer.scopes_.back();
        explorer.scopes_.emplace_back (current->data.expand());
        ++current;
        while (!explorer.scopes_.empty() && !explorer.scopes_.back())
          explorer.scopes_.pop_back();
      }
      
      friend bool
      operator== (ScopeExplorer const& s1, ScopeExplorer const& s2)
      {
        return not s1.scopes_.empty()
            && not s2.scopes_.empty()
            && s1.scopes_.size() == s2.scopes_.size()
            && yield(s1) == yield(s2);
      }
    };
  
  
  /** @internal Core operation to expand nested scopes recursively */
  inline DataCap::Locator
  DataCap::expand()  const
    {
      Rec* val = unConst(this)->maybeGet<Rec>();
      if (!val)
        return Locator();
      else
        return Locator(*val);
    }
  
  
  struct GenNode::ScopeExplorerIterator
    : IterStateWrapper<const GenNode, ScopeExplorer>
    {
      using IterStateWrapper<const GenNode, ScopeExplorer>::IterStateWrapper;
      
      size_t level()  const { return unConst(this)->stateCore().depth(); }
    };
  
  
  inline GenNode::iterator GenNode::begin()        { return iterator(*this); }
  inline GenNode::iterator GenNode::begin() const  { return iterator(*this); }
  inline GenNode::iterator GenNode::end()          { return iterator(); }
  inline GenNode::iterator GenNode::end()   const  { return iterator(); }
  
  template<typename X>
  inline bool
  GenNode::contains (X const& elm)  const
  {
    for (auto & n : *this)
      if (n.matches(elm))
        return true;
    return false;
  }
  
  
  
  
  /* === References : special treatment on element access === */
  
  template<typename X>
  inline X&
  DataCap::get()
    {
      return Variant<DataValues>::get<X>();
    }
  
  template<typename X>
  inline X const&
  DataCap::get()  const
    {
      return Variant<DataValues>::get<X>();
    }
  
  /** especially when accessing for a Record,
   * a payload of type \c RecordRef<Record<GenNode>> (aka RecRef)
   * will be automatically dereferenced. Effectively this allows
   * a GenNode with a RecRef payload to "stand in" for a node holding
   * a full Record inline. And it allows the construction of a special
   * \link #Ref Ref-GenNode \endlink, which even shares the \em identity
   * (the ID) of the referenced record-GenNode.
   * @note effectively this opens an indirect loophole to const correctness,
   *       since it is possible explicitly to retrieve the RecRef from a
   *       const GenNode and then to access the referred-to Record
   *       without const. In case this turns out to be problematic,
   *       we'd have to alter the semantics of RecRef
   */
  template<>
  inline Rec&
  DataCap::get()
    {
      Rec* rec = maybeGet<Rec>();
      if (rec) return *rec;
      
      return Variant<DataValues>::get<RecRef>();
    }
  
  template<>
  inline Rec const&
  DataCap::get()  const
    {
      Rec* rec = unConst(this)->maybeGet<Rec>();
      if (rec) return *rec;
      
      return Variant<DataValues>::get<RecRef>();
    }

  
  
  /**
   * Constructor for a specially crafted 'ref GenNode'.
   * The identity record of the generated object will be prepared
   * such as to be identical to a regular GenNode with Record payload.
   * @note slicing in usage is intentional
   */
  struct Ref
    : GenNode
    {
      /** create an empty ID stand-in.
       * @note the purpose is to create a symbolic reference by name
       */
      explicit
      Ref(string const& symbolicID)
        : GenNode(fabricateRefID<Rec> (symbolicID)//note: seeds the type hash with Rec, not RecRef
                 , DataCap(RecRef()))            // note: places NIL into the reference part
        { }
      
      /** build reference to a Record, using the original ID
       * @throw error::Logic when oNode does not hold a Record<GenNode>
       */
      Ref(GenNode& oNode)
        : GenNode(ID(oNode)
                 , DataCap(RecRef(oNode.data.get<Rec>())))
        { }
      
      static const Ref END;     ///< symbolic ID ref "_END_"
      static const Ref THIS;    ///< symbolic ID ref "_THIS_"
      static const Ref CHILD;   ///< symbolic ID ref "_CHILD_"
      static const Ref ATTRIBS; ///< symbolic ID ref "_ATTRIBS_"
    };
  
  
  // slice down on copy construction...
  inline GenNode::GenNode(Ref const& r)  : idi(r.idi), data(r.data)   { }
  inline GenNode::GenNode(Ref &  r)      : idi(r.idi), data(r.data)   { }
  inline GenNode::GenNode(Ref && r)      : idi(std::move(r.idi)),
                                           data(std::move(r.data))    { }

  
  /* === Specialisation to add fluent GenNode builder API to Record<GenNode> === */
  
  template<>
  inline GenNode
  MakeRec::genNode()
  {
    return GenNode(std::move(record_));
  }
  
  template<>
  inline GenNode
  MakeRec::genNode(string const& symbolicID)
  {
    return GenNode(symbolicID, std::move(record_));
  }
  
  
  /* === Specialisation for handling of attributes in Record<GenNode> === */
  
  template<>
  inline bool
  Rec::isAttribute (GenNode const& attrib)
  {
    return attrib.isNamed();
  }
  
  template<>
  inline bool
  Rec::isTypeID (GenNode const& attrib)
  {
    return attrib.isTypeID();
  }
  
  template<>
  inline string
  Rec::extractTypeID (GenNode const& v)
  {
    return isTypeID(v)? v.data.get<string>()
                      : Rec::TYPE_NIL;
  }
  
  template<>
  inline string
  Rec::extractKey (GenNode const& v)
  {
    return isAttribute(v)? v.idi.getSym()
                         : "";
  }
  
  template<>
  inline GenNode const&
  Rec::extractVal (GenNode const& v)
  {
    return v;
  }
  
  template<>
  inline string
  Rec::renderAttribute (GenNode const& a)
  {
    return a.idi.getSym() +" = "+ string(a.data);
  }
  
  template<>
  template<typename X>
  inline GenNode
  Rec::buildAttribute (string const& key, X&& payload)
  {
    return GenNode(key, payload);
  }
  
  
  
}} // namespace lib::diff
#endif /*LIB_DIFF_GEN_NODE_H*/
