var GCObjectTree = {};
var nsISupportsTree = {};
var nsIFrameTree = {};

var needLoveB = {};
/** Called by dehydra on every class declaration */

function process_class(c) {
  function addSupports()
  {
    nsISupportsTree[c.name] = {
      decl: c.decl,
      bases: c.bases
    }
  }

  function addGCObject()
  {
    GCObjectTree[c.name] = 1;
  }

  function addFrame()
  {
    nsIFrameTree[c.name] = 1;
  }

  if (c.name == "nsISupports") {
    addSupports()
    return;
  }
  if (c.name == "GCObject" || c.name == "GCFinalizedObject") {
    addGCObject();
    return;
  }
  if (c.name == "nsIFrame") {
    addFrame();
    return;
  }

  var base;
  for each (base in c.bases) {
    if (nsISupportsTree.hasOwnProperty(base)) {
      addSupports();
    }
    if (GCObjectTree.hasOwnProperty(base)) {
      addGCObject();
    }
    if (nsIFrameTree.hasOwnProperty(base)) {
      addFrame();
    }
  }
}

function processConstructors(v) {
  if(v.name != "constructor") return;

  var m = /^(class|struct) ([\w:]+) .*/(v.type);
  if (!m) {
    return;
  }
  var type = m[2];

  // if class isn't inherited from nsISupports exit
  if (!nsISupportsTree.hasOwnProperty(type))
    return;

  // if the class inherits from GCObject exit
  if (GCObjectTree.hasOwnProperty(type))
    return;

  // if the class inherits from nsIFrame exit
  if (nsIFrameTree.hasOwnProperty(type))
    return;

  needLoveB[type] = 1;
}

/** called by dehydra on every "statement" */
function process(vars, state) {
  iter(processConstructors, vars);
}

/**
 * Takes an array of strings and returns a transformed array with only
 * unique elements.
 */
function uniq(a)
{
  var o = {}
  for each (var e in a) {
    o[e] = 1;
  }

  a = [];
  for (var p in o) {
    a.push(p);
  }
  return a;
}

/**
 * Print all the base classes of the specified class (or at least, those
 * that inherit from nsISupports
 */
function all_bases(c)
{
  var bases = [];

  for each (var base in nsISupportsTree[c].bases) {
    bases.push(base);
    if (nsISupportsTree.hasOwnProperty(base)) {
      for each (var b in all_bases(base)) {
        bases.push(b);
      }
    }
  }
  return bases;
}

/** called by dehydra when there is no more input to consume */
function input_end() {
  for (var c in needLoveB) {
    print("*** do-GCObject:\t" + c + "\t" + nsISupportsTree[c].decl +
	  "\t" + uniq(all_bases(c)));
  }
}
