--- /dev/null	2005-11-20 21:22:37.000000000 -0600
+++ category_devel/category_devel.info	2007-02-13 17:42:49.000000000 -0600
@@ -0,0 +1,5 @@
+; $Id$
+name = Category devel
+description = Debugging and development tools for Category.
+package = Category
+dependencies = category
--- /dev/null	2005-11-20 21:22:37.000000000 -0600
+++ category_devel/category_devel.module	2007-02-14 10:40:43.000000000 -0600
@@ -0,0 +1,129 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Debugging and development tools for Category.
+ */
+
+/**
+ * Implementation of hook_menu().
+ */
+function category_devel_menu($may_cache) {
+  $items = array();
+  if (!$may_cache) {
+    if (arg(0)=='node' && is_numeric(arg(1))) {
+      if (category_is_cat_or_cont(arg(1))) {
+        $items[] = array(
+          'path' => 'node/'.arg(1).'/cat_devel',
+          'title' => t('Category dev'),
+          'access' => user_access('administer categories'),
+          'callback' => 'category_devel_page',
+          'type' => MENU_LOCAL_TASK,
+        );
+        $items[] = array(
+          'path' => 'node/'.arg(1).'/cat_devel_img',
+          'access' => user_access('administer categories'),
+          'callback' => 'category_devel_image',
+          'callback arguments' => array(arg(1)),
+          'type' => MENU_CALLBACK,
+        );
+      }
+    }
+  }
+  else {
+    $items[] = array(
+      'path' => 'admin/settings/category_devel',
+      'title' => t('Category Devel'),
+      'description' => t('Configure Category Devel'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => 'category_devel_admin_settings',
+      'access' => user_access('administer site configuration'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+  }
+  return $items;
+}
+
+function category_devel_admin_settings() {
+  $form = array();
+  $form['category_devel_dot'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path to dot'),
+    '#description' => t('Enter the path to your Graphviz dot binary.'),
+    '#default_value' => variable_get('category_devel_dot','/usr/pkg/bin/dot'),
+  );
+  return system_settings_form($form);
+}
+
+
+function category_devel_page() {
+  $o = '<p>'.t('Ovals are categories, boxes are containers.').'</p>';
+  $o .= '<img src="'.url('node/'.arg(1).'/cat_devel_img').'" />';
+  return $o;
+}
+
+/**
+ * Menu callback to render and display the tree.
+ * Requires webserver-accessible graphviz binary.
+ */
+function category_devel_image($nid) {
+  $dot = category_devel_dot($nid);
+  $filename = tempnam(file_directory_temp(),'cat_dev_');
+  $imagename = tempnam(file_directory_temp(),'cat_dev_');
+  $handle = fopen($filename,'w');
+  fwrite($handle,$dot);
+  fclose($handle);
+  $errors = system(variable_get('category_devel_dot','/usr/pkg/bin/dot').' -Tpng '.$filename.' >'.$imagename);
+  unlink($filename);
+  $img = file_get_contents($imagename);
+  unlink($imagename);
+  header('Content-Type: image/png');
+  echo $img;
+  exit();
+}
+
+/**
+ * Function to generate a dot file representing the paths to the root.
+ */
+function category_devel_dot($nid) {
+  $o = 'digraph g {';
+  $pairs = array();
+  _category_devel_dot($pairs,$nid);
+  $data = $pairs['data'];
+  unset($pairs['data']);
+  foreach ($pairs as $k=>$v) {
+    foreach ($v as $k2=>$v2) {
+      $o .= '"'.$k.'"'.' -> '.'"'.$k2.'"'.';';
+    }
+  }
+  foreach ($data as $k => $v) {
+    $o .= '"'.$k.'" [shape='.$v['type'].' label="'.$k.', '.$v['weight'].'\n'.$v['name'].'"];';
+  }
+  $o .= '"0" [shape=box label="<root>"];}';
+  return $o;
+}
+
+/**
+ * Helper function for category_devel_dot().
+ */
+function _category_devel_dot(&$pairs,$nid) {
+  $node = node_load($nid);
+  $parents = $node->parents;
+  if (empty($parents)) {
+    $parents = array($node->parent);
+  }
+  $type = category_node_get_type($node);
+  $pairs['data'][$node->nid] = array(
+    'name' => $node->title,
+    'type' => ($type=='category_cat') ? "ellipse" : "box",
+    'weight' => $node->weight,
+  );
+  foreach($parents as $p) {
+    $pairs[$p][$node->nid] = TRUE;
+    if ($p != 0) {
+      _category_devel_dot($pairs,$p);
+    }
+  }
+}
+
