package org.jboss.cache.aop.test.propagation.impl;

import org.jboss.cache.aop.test.propagation.Node;
import org.jboss.cache.aop.test.propagation.PropagationManager;
import org.jboss.cache.aop.test.propagation.PropagationRule;
import org.jboss.cache.aop.test.propagation.StateItem;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PropagationManagerImpl implements PropagationManager {
   private Node rootNode_;

   private Map nodeMap_ = new HashMap();

   private transient PropagationRule orRule_;

   public PropagationManagerImpl() {
      orRule_ = PropagationRuleFactory.getPropagationRule();
   }

   public void setRootNode(String rdn) {
      this.rootNode_ = new NodeImpl();
      rootNode_.setNodeFDN(rdn);
      rootNode_.setNodeRDN(rdn);
      rootNode_.setPropagationRule(orRule_);

      StateItem summary = new StateItemImpl(0);
      summary.setState(PropagationRule.STATE_CLEAR);
      rootNode_.setSummaryStateItem(summary);

      registMap(rootNode_);
   }

   public void addNode(String parentFdn, String rdn) {
      Node parent = findNode(parentFdn);
      if (parent != null) {
         Node node = new NodeImpl();
         node.setNodeFDN(parentFdn + "." + rdn);
         node.setNodeRDN(rdn);
         node.setPropagationRule(orRule_);

         node.setParentNode(parent);
         parent.addChildNode(node);

         StateItem summary = new StateItemImpl(0);
         summary.setState(PropagationRule.STATE_CLEAR);
         node.setSummaryStateItem(summary);

         registMap(node);

         PropagationRule rule = node.getPropagationRule();
         rule.summaryUpperPropagate(node);
      }
   }

   public void addStateItem(String parentFdn, long itemId, long defaultState) {
      Node node = findNode(parentFdn);
      if (node != null) {
         StateItem item = new StateItemImpl(itemId);
         item.setState(defaultState);

         node.addStateItem(item);

         PropagationRule rule = node.getPropagationRule();
         rule.summaryUpperPropagate(node);
      }
   }

   public void stateChange(String parentFdn, long itemId, long newState) {
      Node node = findNode(parentFdn);
      if (node != null) {
         PropagationRule rule = node.getPropagationRule();
         rule.changeState(node, itemId, newState);
      }
   }

   public Node findNode(String fdn) {
      return (Node) nodeMap_.get(fdn);
   }

   private void registMap(Node node) {
      this.nodeMap_.put(node.getNodeFDN(), node);
   }

   public void printNodes() {
      printNode(rootNode_, "");
   }

   private void printNode(Node node, String prefix) {
      System.out.println(prefix + node.getNodeRDN() + " (Summary : "
              + node.getSummaryStateItem().getState() + ")");

      String itemPrefix = prefix + " | ";
      List items = node.getStateItems();
      int size = items.size();
      for (int idx = 0; idx < size; idx++) {
         StateItem item = (StateItem) items.get(idx);
         printStateItem(item, itemPrefix);
      }

      String childPrefix = prefix + " + ";
      List children = node.getChildren();
      size = children.size();
      for (int idx = 0; idx < size; idx++) {
         Node child = (Node) children.get(idx);
         printNode(child, childPrefix);
      }
   }

   private void printStateItem(StateItem item, String prefix) {
      System.out.println(prefix + "(" + item.getItemId() + " : "
              + item.getState() + ")");
   }

   private String toNodeString(Node node, String prefix) {
      StringBuffer buf = new StringBuffer();

      buf.append(prefix + node.getNodeRDN() + " (Summary : "
              + node.getSummaryStateItem().getState() + ")");

      String itemPrefix = prefix + " | ";
      List items = node.getStateItems();
      int size = items.size();
      for (int idx = 0; idx < size; idx++) {
         StateItem item = (StateItem) items.get(idx);
         buf.append(toStateItemString(item, itemPrefix));
      }

      String childPrefix = prefix + " + ";
      List children = node.getChildren();
      size = children.size();
      for (int idx = 0; idx < size; idx++) {
         Node child = (Node) children.get(idx);
         buf.append(toNodeString(child, childPrefix));
      }

      return buf.toString();
   }

   private String toStateItemString(StateItem item, String prefix) {
      return (prefix + "(" + item.getItemId() + " : "
              + item.getState() + ")");
   }

   public String toString() {
      return toNodeString(rootNode_, "+");
   }
}
