/*
********************************************************************************
* Copyright (c) 1988 by Hewlett-Packard Company
* 
* Permission to use, copy, modify, and distribute this software 
* and its documentation for any purpose and without fee is hereby 
* granted, provided that the above copyright notice appear in all 
* copies and that both that copyright notice and this permission 
* notice appear in supporting documentation, and that the name of 
* Hewlett-Packard not be used in advertising or publicity pertaining 
* to distribution of the software without specific, written prior 
* permission.
********************************************************************************
*/
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/PushBG.h>
#include <Xm/PanedW.h>
#include <Xm/RowColumn.h>
#include <Xm/ScrolledW.h>
#include "Graph.h"
#include "Arc.h"
#include <stdio.h>

/*
 * Define the structure for a node in the binary sort tree.
 */

typedef struct _node {
  int            key;
  struct _node  *left;
  struct _node  *right;
} node;

extern node *insert_node();
extern node *make_node();

Widget node_widgets[1000];
Widget arc_widgets[1000];
static int n_nodes = 0;
static n_arcs = 0;
Widget toplevel;

void delete_widget (w, graph, call_data)
     Widget          w;
     Widget          graph;
     caddr_t         call_data;
{
  XmGraphDestroySelectedArcsOrNodes (graph);
}

void re_orient (w, graph, call_data)
     Widget          w;
     Widget          graph;
     caddr_t         call_data;
{
    Arg wargs[2];

    XtSetArg (wargs[0], XmNreorient, True);
    XtSetValues (graph, wargs, 1);
}

void re_layout (w, graph, call_data)
     Widget          w;
     Widget          graph;
     caddr_t         call_data;
{
    Arg wargs[2];

    XtSetArg (wargs[0], XmNreLayout, TRUE);
    XtSetValues (graph, wargs, 1);
}

void quit (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     caddr_t         call_data;
{
  exit(0);
}

void edit_mode (w, graph, call_data)
     Widget          w;
     Widget          graph;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  if(call_data->set)
    XtSetArg (wargs[0], XmNeditable, TRUE);
  else
    XtSetArg (wargs[0], XmNeditable, FALSE);

    XtSetValues (graph, wargs, 1);
}


main(argc, argv)
    int argc;
    char **argv;
  {
    Widget     sw, graph, reorient, relay, delete;
    Widget     panel, qbutton, edit, add, command;
    int        i, n;
    node      *head = NULL;
    int        digit;   
    Arg        wargs[10];

    toplevel = XtInitialize(argv[0], "Sort", NULL, 0, 
                            &argc, argv);
    panel = XmCreatePanedWindow (toplevel, "panel", NULL, 0);
    XtManageChild (panel);

    n = 0;
    XtSetArg(wargs[n], XmNpacking, XmPACK_COLUMN); n++; 
    XtSetArg(wargs[n], XmNnumColumns, 10); n++; 
    command = XmCreateRowColumn (panel, "command", wargs, n);
    XmAddTabGroup(command);
    XtManageChild (command);


    qbutton = XmCreatePushButton (command, "Quit", wargs, 0);
    XtManageChild (qbutton);

    edit = XmCreateToggleButton (command, "Edit", wargs, 0);
    XtManageChild (edit);

    reorient = XmCreatePushButton (command, "ReOrient", wargs, 0);
    XtManageChild (reorient);

    relay = XmCreatePushButton (command, "Relay", wargs, 0);
    XtManageChild (relay);

  delete = XmCreatePushButton (command, "Delete Node/Arc", wargs, 0);
    XtManageChild (delete);
    /*
     * Create the graph widget.
     */
    XtSetArg (wargs[0], XmNautoLayoutMode, XmNEVER); 
    graph = XmCreateScrolledGraph(panel, "tree", wargs, 1);

    XmAddTabGroup(graph);
    XtManageChild(graph);

    XtAddCallback (relay,    XmNactivateCallback,     re_layout, graph);
    XtAddCallback (reorient, XmNactivateCallback,     re_orient, graph);
    XtAddCallback (qbutton,  XmNactivateCallback,     quit, graph);
    XtAddCallback (edit,     XmNvalueChangedCallback, edit_mode, graph);
    XtAddCallback (delete, XmNactivateCallback, delete_widget, graph);
    /*
     * Create a binary sort tree from random data
     */
    if(argc == 2)
      {
	extern double  drand48();
	static long seed = 0;
	double foo;
	seed = 100; /* getpid(); */
	srand48(seed);
	for(i = 0; i< atoi(argv[1]); i++){
	  foo = drand48();
	  head = insert_node((int) (foo * 1000), head);        
	}
      }
    else
      {
	printf("usage: sort <number>, where <number> is the number of random integers to sort and display\n");
	exit(0);
      }
    /*
     * Create the widgets representing the tree.
     */

    show_tree(graph, head, NULL);
    XtRealizeWidget(toplevel);
    XtManageChildren(node_widgets, n_nodes);
    XtManageChildren(arc_widgets, n_arcs);

    XtSetArg (wargs[0], XmNautoLayoutMode, XmALWAYS); 
    XtSetValues(graph, wargs, 1);

    XtMainLoop();
}

node *insert_node(key, head)
     int   key;
     node *head;
{
  node *prev, *ptr  = head;
  /*
   * If the tree doesn't exist, just create and 
   * return a new node.
   */
  if(!head)
    return (make_node(key));
  /*
   * Otherwise, find a leaf node, always following the 
   * left branches if the key is less than the value in each 
   * node, and the right branch otherwise.
   */
  while(ptr != NULL){ 
    prev = ptr; 
    ptr = (key < ptr->key) ? ptr->left : ptr->right;
  } 
  /*
   * Make a new node and attach it to the appropriate branch.
   */
  if (key < prev->key)
    prev->left = make_node(key);
  else 
    prev->right = make_node(key);
  return (head);
}


node *make_node(key)
     int   key;
{
  node  *ptr = (node *) malloc(sizeof(node));

  ptr->key   = key;
  ptr->left  = ptr->right = NULL;

  return (ptr);
}



show_tree(parent, branch, super_node)
     Widget   parent;     
     node    *branch;     
     Widget   super_node; 
{
  Widget   w;
  char    *name[100];
  Arg      wargs[10];
  int      n = 0;
  Widget node_widget;
  /*
   * If we've hit a leaf, return.
   */
  if(!branch) return;
  /*
   * Create a widget for the node, specifying the
   * given super_node constraint.
   */
  sprintf(name, "%d", branch->key);
  XtSetArg(wargs[n], XmNlabelString, 
	   XmStringCreate(name, XmSTRING_DEFAULT_CHARSET)); n++;
  node_widget =  node_widgets[n_nodes] = 
      XtCreateWidget(name, xmPushButtonGadgetClass, 
		     parent, wargs, n);
  n_nodes++;

  if(super_node)
    {
      Widget arc;
      n =0 ;
      XtSetArg (wargs[n], XmNarcDirection, XmDIRECTED); n++;
      XtSetArg (wargs[n], XmNto, node_widget); n++;
      XtSetArg (wargs[n], XmNfrom, super_node); n++;
      arc_widgets[n_arcs] =  XmCreateArc (parent, name, wargs, n);
 fprintf(stderr,"arc: name <%s> w %p, nameToWidget-> %p, toplevel=%p %p\n",
	 name,arc_widgets[n_arcs], XtNameToWidget(parent,name),toplevel,parent);
      n_arcs++;
    }

  /*
   * Recursively create the sub-nodes, giving this node's 
   * widget as the super_node.
   */

  show_tree(parent, branch->left, node_widget);
  show_tree(parent, branch->right, node_widget);

}


