/* ----------------------------------------------------------------------------- 
 * browser.cxx
 *
 *     A web-base parse tree browser using SWILL.   This is an optional
 *     feature that's normally disabled.
 * 
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *
 * Copyright (C) 2002.  The University of Chicago
 * See the file LICENSE for information on usage and redistribution.	
 * ----------------------------------------------------------------------------- */

char cvsroot_browser_cxx[] = "$Header: /cvsroot/swig/SWIG/Source/Modules/browser.cxx,v 1.6 2004/01/22 22:42:14 cheetah Exp $";

#include "swigmod.h"

#ifdef SWIG_SWILL
extern "C" {
#include "swill.h"
}

static FILE *out = 0;
static Node *view_top = 0;
      
class Browser : public Dispatcher {
  void show_checkbox(Node *t, Node *n) {
    int v = 0;
    if (Getmeta(n,"visible")) {
      v = 1;
    }
    if (v) {
      Printf(out,"<a name=\"n%x\"></a>[<a href=\"hide.html?node=0x%x&hn=0x%x#n%x\">-</a>] ",  n, t, n,n);
    } else {
      Printf(out,"<a name=\"n%x\"></a>[<a href=\"show.html?node=0x%x&hn=0x%x#n%x\">+</a>] ",  n, t, n,n);
    }
  }
  void show_attributes(Node *obj) {
    if (!Getmeta(obj,"visible")) return;
    String *os = NewString("");
    String *k;
    Iterator ki;
    ki = First(obj);
    while (ki.key) {
      k = ki.key;
      if ((Cmp(k,"nodeType") == 0) || (Cmp(k,"firstChild") == 0) || (Cmp(k,"lastChild") == 0) ||
	  (Cmp(k,"parentNode") == 0) || (Cmp(k,"nextSibling") == 0) || 
	  (Cmp(k,"previousSibling") == 0) || (*(Char(k)) == '$')) {
	/* Do nothing */
      } else if (Cmp(k,"parms") == 0) {
	String *o = NewString("");
	Printf(o,"%s", ParmList_protostr(Getattr(obj,k)));
	Replaceall(o,"&","&amp;");
	Replaceall(o,"<","&lt;");
	Replaceall(o,">","&gt;");
	Printf(os,"<a href=\"data.html?n=0x%x\">?</a> %-12s - %s\n", Getattr(obj,k), k, o);
	Delete(o);
      } else {
	DOH *o;
	char *trunc = "";
	if (DohIsString(Getattr(obj,k))) {
	  o = Str(Getattr(obj,k));
	  if (Len(o) > 70) {
	    trunc = "...";
	  }
	  Replaceall(o,"&","&amp;");
	  Replaceall(o,"<","&lt;");
	  Printf(os,"<a href=\"data.html?n=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj,k), k, o, trunc);
	  Delete(o);
	} else {
	  Printf(os,"<a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\n", Getattr(obj,k), k, Getattr(obj,k));
	}
      }
      ki = Next(ki);
    }
    Printf(out,"<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os));
    Delete(os);
  }

public:
  virtual int emit_one(Node *n) {
    char *tag = Char(nodeType(n));
    char *file = Char(Getfile(n));
    int   line = Getline(n);
    char *name = GetChar(n,"name");

    show_checkbox(view_top, n);
    Printf(out,"<b><a href=\"index.html?node=0x%x\">%s</a></b>", n, tag);
    if (name) {
      Printf(out," (%s)", name);
    }
    Printf(out,".  %s:%d\n", file, line);
    Printf(out,"<br>");
    Dispatcher::emit_one(n);
    return SWIG_OK;
  }
  virtual int emit_children(Node *n) {
    if (Getmeta(n,"visible")) {
      Printf(out,"<blockquote>\n");
      Dispatcher::emit_children(n);
      Printf(out,"</blockquote>\n");
    }
    return SWIG_OK;
  }
  virtual int defaultHandler(Node *n) {
    show_attributes(n);
    return SWIG_OK;
  }
  virtual int top(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int includeDirective(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int importDirective(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }

  virtual int extendDirective(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int classDeclaration(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }

  virtual int templateDeclaration(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }

  virtual int enumDeclaration(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int typemapDirective(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int namespaceDeclaration(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }
  virtual int usingDeclaration(Node *n) {
    show_attributes(n);
    emit_children(n);
    return SWIG_OK;
  }

};

static int browser_exit = 0;
static Node *tree_top = 0;
static Browser *browse = 0;

/* ----------------------------------------------------------------------
 * exit_handler()      - Force the browser to exit
 * ---------------------------------------------------------------------- */

void exit_handler(FILE *f) {
  browser_exit = 1;
  Printf(f,"Terminated.\n");
}

/* ----------------------------------------------------------------------
 * node_handler()      - Generate information about a specific node
 * ---------------------------------------------------------------------- */

static void display(FILE *f, Node *n) {
  /* Print standard HTML header */
  
  Printf(f,"<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", PACKAGE_VERSION); 
  Printf(f,"<b>SWIG-%s</b><br>\n", PACKAGE_VERSION);
  Printf(f,"[ <a href=\"exit.html\">Exit</a> ]");
  Printf(f," [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top);
  if (n != tree_top) {
    Printf(f," [ <a href=\"index.html?node=0x%x\">Up</a> ]", parentNode(n));
  }
  Printf(f," [ <a href=\"symbol.html\">Symbols</a> ]");
  Printf(f,"<br><hr><p>\n");

  out = f;

  browse->emit_one(n);

  /* Print standard footer */
  Printf(f,"<br><hr></BODY></HTML>\n");

}

void node_handler(FILE *f) {
  Node *n = 0;
  if (!swill_getargs("p(node)", &n)) {
    n = tree_top;
  }
  view_top = n;
  display(f,n);
}


/* ----------------------------------------------------------------------
 * hide_handler()      - Hide a node 
 * ---------------------------------------------------------------------- */

void hide_handler(FILE *f) {
  Node *n = 0;
  if (!swill_getargs("p(hn)", &n)) {
    n = 0;
  }
  if (n) {
    Delmeta(n,"visible");
  }
  node_handler(f);
}

void show_handler(FILE *f) {
  Node *n = 0;
  if (!swill_getargs("p(hn)", &n)) {
    n = 0;
  }
  if (n) {
    Setmeta(n,"visible","1");
  }
  node_handler(f);
}

void raw_data(FILE *out, Node *obj) {
  if (!obj) return;
  if (DohIsMapping(obj)) {
    String *k;
    Iterator ki;
    String *os = NewString("");
    Printf(os,"Hash {\n");
    ki = First(obj);
    while (ki.key) {
      k = ki.key;
      DOH *o;
      const char *trunc = "";
      if (DohIsString(Getattr(obj,k))) {
	o = Str(Getattr(obj,k));
	if (Len(o) > 70) {
	  trunc = "...";
	}
	Replaceall(o,"<","&lt;");
	Printf(os,"    <a href=\"data.html?n=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj,k), k, o, trunc);
	Delete(o);
      } else {
	Printf(os,"    <a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\n", Getattr(obj,k), k, Getattr(obj,k));
      }
      ki = Next(ki);
    }
    Printf(os,"}\n");
    Printf(out,"<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os));
    Delete(os);
  } else if (DohIsString(obj)) {
    String *o = Str(obj);
    Replaceall(o,"<","&lt;");
    Printf(out,"<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(o));
    Delete(o);
  } else if (DohIsSequence(obj)) {
    int i;
    String *os = NewString("");
    Printf(os,"List [\n");
    for (i = 0; i < Len(obj); i++) {
      DOH *o = Getitem(obj,i);
      const char *trunc = "";
      if (DohIsString(o)) {
	String *s = Str(o);
	if (Len(s) > 70) {
	  trunc = "...";
	}
	Replaceall(o,"<","&lt;");
	Printf(os,"    <a href=\"data.html?n=0x%x\">?</a> [%d] - \"%(escape)-0.70s%s\"\n", o,i,s, trunc);
	Delete(s);
      } else {
	Printf(os,"    <a href=\"data.html?n=0x%x\">?</a> [%d] - 0x%x\n", o, i, o);
      }
    }
    Printf(os,"\n]\n");
    Printf(out,"<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os));
    Delete(os);
  }
}

void data_handler(FILE *f) {
  DOH *n = 0;
  if (!swill_getargs("p(n)", &n)) {
    n = 0;
  }
  Printf(f,"<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", PACKAGE_VERSION); 
  Printf(f,"<b>SWIG-%s</b><br>\n", PACKAGE_VERSION);
  Printf(f,"[ <a href=\"exit.html\">Exit</a> ]");
  Printf(f," [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top);
  Printf(f,"<br><hr><p>\n");
  if (n) {
    raw_data(f,n);
  }
  /* Print standard footer */
  Printf(f,"<br><hr></BODY></HTML>\n");
}

void symbol_handler(FILE *f) {
  Symtab *sym;
  char   *name = 0;

  Printf(f,"<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", PACKAGE_VERSION); 
  Printf(f,"<b>SWIG-%s</b><br>\n", PACKAGE_VERSION);
  Printf(f,"[ <a href=\"exit.html\">Exit</a> ]");
  Printf(f," [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top);
  Printf(f," [ <a href=\"symbol.html\">Symbols</a> ]");
  Printf(f,"<br><hr><p>\n");
  
  if (!swill_getargs("p(sym)|s(name)", &sym, &name)) {
    sym = Swig_symbol_getscope("");
    name = 0;
  }
  if (!sym) {
    Printf(f,"No symbol table specified!\n");
    return;
  }
  {
    String *q = Swig_symbol_qualifiedscopename(sym);
    if (!Len(q)) {
      Printf(f,"<b>Symbol table: :: (global)</b><br>\n"); 
    } else {
      Printf(f,"<b>Symbol table: %s</b><br>\n", q);
    }
    Delete(q);
  }
  
  fprintf(f,"<p><form action=\"symbol.html\" method=GET>\n");
  fprintf(f,"Symbol lookup: <input type=text name=name size=40></input><br>\n");
  fprintf(f,"<input type=hidden name=sym value=\"0x%x\">\n", sym);
  fprintf(f,"Submit : <input type=submit></input>\n");
  fprintf(f,"</form>");

  if (name) {
    Node *n = Swig_symbol_clookup(name,sym);
    Printf(f,"Symbol '%s':\n", name);
    Printf(f,"<blockquote>\n");
    if (!n) {
      Printf(f,"Not defined!\n");
    } else {
      raw_data(f,n);
    }
    Printf(f,"</blockquote>\n");
  }

  Printf(f,"<p><b>Nested scopes</b><br>\n");
  Printf(f,"<blockquote><pre>\n");
  {
    Hash   *h;
    h = firstChild(sym);
    while (h) {
      Printf(f,"<a href=\"symbol.html?sym=0x%x\">%s</a>\n", h, Getattr(h,"name"));
      h = nextSibling(h);
    }
  }
  Printf(f,"</pre></blockquote>\n");
  
  Printf(f,"<p><b>Symbol table contents</b></br>\n");
  raw_data(f,Getattr(sym,"symtab"));
  Printf(f,"<br><hr></BODY></HTML>\n");

}
#endif

void
Swig_browser(Node *top, int port) {
#ifdef SWIG_SWILL
  int sport;
  browser_exit = 0;

  /* Initialize the server */
  sport = swill_init(port);
  if (sport < 0) {
    Printf(stderr,"Couldn't open socket on port %d. Sorry.\n", port);
    return;
  }
  browse = new Browser();
  Setmeta(top,"visible","1");
  tree_top = top;

  Printf(stderr,"SWIG: Tree browser listening on port %d\n", sport);

  swill_handle("exit.html", exit_handler,0);
  swill_handle("index.html", node_handler, 0);
  swill_handle("hide.html", hide_handler,0);
  swill_handle("show.html", show_handler,0);
  swill_handle("data.html", data_handler,0);
  swill_handle("symbol.html", symbol_handler, 0);
  swill_netscape("index.html");

  while (!browser_exit) {
    swill_serve();
  }
  Printf(stderr,"Browser terminated.\n");
  swill_close();
  delete browse;
  return;
#else
  (void)top;
  (void)port;
#endif
}





