/*
 * Copyright (C) 2011 Vyatta, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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, see .
 */
#ifndef _COMMIT_ALGORITHM_HPP_
#define _COMMIT_ALGORITHM_HPP_
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// forward decl
namespace cnode {
class CfgNode;
}
namespace cstore {
class Cstore;
}
namespace commit {
using namespace cnode;
using namespace cstore;
enum CommitState {
  COMMIT_STATE_UNCHANGED,
  COMMIT_STATE_ADDED,
  COMMIT_STATE_DELETED,
  COMMIT_STATE_CHANGED
};
enum CommitTreeTraversalOrder {
  PRE_ORDER,
  POST_ORDER
};
enum CommitHook {
  PRE_COMMIT,
  POST_COMMIT,
  LAST // not a valid hook
};
class CommitData {
public:
  CommitData();
  virtual ~CommitData() {}
  // setters
  void setCommitState(CommitState s);
  void setCommitPath(const Cpath& p, bool is_val, const std::string& val,
                     const std::string& name);
  void setCommitMultiValues(const std::vector& values,
                            const std::vector& states);
  void setCommitValue(const std::string& val1, const std::string& val2,
                      bool def1, bool def2);
  void setCommitChildDeleteFailed();
  void setCommitCreateFailed();
  void setCommitSubtreeChanged();
  // getters
  CommitState getCommitState() const;
  Cpath getCommitPath() const;
  size_t numCommitMultiValues() const;
  std::string commitMultiValueAt(size_t idx) const;
  CommitState commitMultiStateAt(size_t idx) const;
  std::string commitValueBefore() const;
  std::string commitValueAfter() const;
  bool commitChildDeleteFailed() const;
  bool commitCreateFailed() const;
  bool commitSubtreeChanged() const;
  // for tmpl stuff
  void setTmpl(std::tr1::shared_ptr def);
  std::tr1::shared_ptr getTmpl() const;
  const vtw_def *getDef() const;
  unsigned int getPriority() const;
  void setPriority(unsigned int p);
  const vtw_node *getActions(vtw_act_type act, bool raw = false) const;
  bool isBeginEndNode() const;
private:
  std::tr1::shared_ptr _def;
  Cpath _commit_path;
  CommitState _commit_state;
  std::vector _commit_values;
  std::vector _commit_values_states;
  std::pair _commit_value;
  std::pair _commit_default;
  bool _commit_create_failed;
  bool _commit_child_delete_failed;
  bool _commit_subtree_changed;
};
class PrioNode : public TreeNode {
public:
  PrioNode(CfgNode *n);
  ~PrioNode() {}
  CfgNode *getCfgNode();
  unsigned int getPriority() const;
  CommitState getCommitState() const;
  Cpath getCommitPath() const;
  bool parentCreateFailed() const;
  bool succeeded() const;
  bool hasSubtreeFailure() const;
  bool hasSubtreeSuccess() const;
  void setCfgParent(CfgNode *p);
  void setSucceeded(bool succeeded);
  void setSubtreeFailure();
  void setSubtreeSuccess();
private:
  CfgNode *_node;
  CfgNode *_cfg_parent;
  bool _succeeded;
  bool _subtree_failure;
  bool _subtree_success;
};
template struct PrioNodeCmp {
  inline bool operator()(PrioNode *a, PrioNode *b) {
    return _is_after(a, b, Int2Type());
  }
  /* note: if comparing "for delete", use "<". if not for delete, use ">".
   *       if two nodes have the same priority, the ordering between them
   *       is not defined, i.e., can be either.
   */
  inline bool _is_after(PrioNode *a, PrioNode *b, Int2Type) {
    return (a->getPriority() > b->getPriority());
  }
  inline bool _is_after(PrioNode *a, PrioNode *b, Int2Type) {
    return (a->getPriority() < b->getPriority());
  }
};
typedef std::priority_queue,
                            PrioNodeCmp > PrioQueueT;
typedef std::priority_queue,
                            PrioNodeCmp > DelPrioQueueT;
typedef std::pair >
  CommittedPathT;
typedef std::vector CommittedPathListT;
// exported functions
const char *getCommitHookDir(CommitHook hook);
CfgNode *getCommitTree(CfgNode *cfg1, CfgNode *cfg2, const Cpath& cur_path);
bool isCommitPathEffective(Cstore& cs, const Cpath& pcomps,
                           std::tr1::shared_ptr def,
                           bool in_active, bool in_working);
bool doCommit(Cstore& cs, CfgNode& cfg1, CfgNode& cfg2);
} // namespace commit
#endif /* _COMMIT_ALGORITHM_HPP_ */