/*
   D-Bus Java Implementation
   Copyright (c) 2005-2006 Matthew Johnson

   This program is free software; you can redistribute it and/or modify it
   under the terms of either the GNU Lesser General Public License Version 2 or the
   Academic Free Licence Version 2.1.

   Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;

import cx.ath.matthew.debug.Debug;

import java.util.regex.Pattern;

/**
 * Keeps track of the exported objects for introspection data */
class ObjectTree 
{
   class TreeNode
   {
      String name;
      ExportedObject object;
      String data;
      TreeNode right;
      TreeNode down;
      public TreeNode(String name)
      {
         this.name = name;
      }
      public TreeNode(String name, ExportedObject object, String data)
      {
         this.name = name;
         this.object = object;
         this.data = data;
      }
   }
   private TreeNode root;
   public ObjectTree()
   {
      root = new TreeNode("");
   }
   public static final Pattern slashpattern = Pattern.compile("/");

   private TreeNode recursiveFind(TreeNode current, String path)
   {
      if ("/".equals(path)) return current;
      String[] elements = path.split("/", 2);
      // this is us or a parent node
      if (path.startsWith(current.name)) {
         // this is us
         if (path.equals(current.name)) {
            return current;
         }
         // recurse down
         else {
            if (current.down == null) 
               return null;
            else return recursiveFind(current.down, elements[1]);
         }
      } 
      else if (current.right == null) {
         return null;
      }
      else if (0 > current.right.name.compareTo(elements[0])) {
         return null;
      }
      // recurse right
      else {
         return recursiveFind(current.right, path);
      }
   }
   private TreeNode recursiveAdd(TreeNode current, String path, ExportedObject object, String data)
   {
      String[] elements = slashpattern.split(path, 2);
      // this is us or a parent node
      if (path.startsWith(current.name)) {
         // this is us
         if (1 == elements.length || "".equals(elements[1])) {
            current.object = object;
            current.data = data;
         }
         // recurse down
         else {
            if (current.down == null) {
               String[] el = elements[1].split("/", 2);
               current.down = new TreeNode(el[0]);
            }
            current.down = recursiveAdd(current.down, elements[1], object, data);
         }
      } 
      // need to create a new sub-tree on the end
      else if (current.right == null) {
         current.right = new TreeNode(elements[0]);
         current.right = recursiveAdd(current.right, path, object, data);
      }
      // need to insert here
      else if (0 > current.right.name.compareTo(elements[0])) {
         TreeNode t = new TreeNode(elements[0]);
         t.right = current.right;
         current.right = t;
         current.right = recursiveAdd(current.right, path, object, data);
      }
      // recurse right
      else {
         current.right = recursiveAdd(current.right, path, object, data);
      }
      return current;
   }
   public void add(String path, ExportedObject object, String data)
   {
      if (Debug.debug) Debug.print(Debug.DEBUG, "Adding "+path+" to object tree");
      root = recursiveAdd(root, path, object, data);
   }
   public void remove(String path)
   {
      if (Debug.debug) Debug.print(Debug.DEBUG, "Removing "+path+" from object tree");
      TreeNode t = recursiveFind(root, path);
      t.object = null;
      t.data = null;
   }

   public String Introspect(String path)
   {
      TreeNode t = recursiveFind(root, path);
      if (null == t) return null;
      StringBuilder sb = new StringBuilder();
      sb.append("<node name=\"");
      sb.append(path);
      sb.append("\">\n");
      if (null != t.data) sb.append(t.data);
      t = t.down;
      while (null != t) {
         sb.append("<node name=\"");
         sb.append(t.name);
         sb.append("\"/>\n");
         t = t.right;
      }
      sb.append("</node>");
      return sb.toString();
   }

   private String recursivePrint(TreeNode current)
   {
      String s = "";
      if (null != current) {
         s += current.name;
         if (null != current.object)
            s += "*";
         if (null != current.down) 
            s += "/{"+recursivePrint(current.down)+"}";
         if (null != current.right)
            s += ", "+recursivePrint(current.right);
      }
      return s;
   }
      
   public String toString()
   {
      return recursivePrint(root);
   }
}
