var inheritance = []
var files = {}
var types = {}

var inheritance_lookup = {}
var inheritance_lookup_length = 0
const MEMBER_TYPE = 1
const MEMBER_DECL = 2
const MEMBER_PARAMS = 3
const PARAM_TYPE = 1
var DIR = "/tmp/inheritance/"

var lengths = [0, 0]
// merges old_obj into new_obj
// translation_obj maps old indexes onto new ones in new_obj
function reverse_cache(old_obj, new_obj, translation_obj, lenpos) {
  for(var key in old_obj) {
    var newIndex = new_obj[key];
    // have we already seen this in the merged world?
    if (typeof newIndex == "undefined") {
      // if not add key/value pair
      newIndex = lengths[lenpos]++
      new_obj[key] = newIndex;
    }
    // memorize the translation
    translation_obj[old_obj[key]] = newIndex
  }
}

function merge(file) {
  var txt = read_file(file)
  if(!txt) return
  var i = txt.indexOf(" ")
  txt = txt.substr(i+1)
  var subgraph = eval(txt)
  /** add files from subgraph to new graph
      and update old indexes to point to graph */
  var file_old2new = {}
  reverse_cache(subgraph.files, files, file_old2new, 0)
  delete subgraph.files
  var type_old2new = {}
  reverse_cache(subgraph.types, types, type_old2new, 1)
  delete subgraph.types

  function remap_file(decl) {
    return [file_old2new[decl[0]], decl[1]]
  }
  function remap_type(t) {
    return type_old2new[t]
  }
  for each (var obj in subgraph.inheritance) {
    // skip classes that have already been processed
    if (typeof inheritance_lookup[obj.name] != "undefined") continue;

    // rewrite inheritance indexes
    // while removing invalid ones(ie ones to templates)
    if (obj.bases) {
      obj.bases = obj.bases.map(function (i) {
        var old = subgraph.inheritance[i]
        if (typeof old == "undefined") {
          print(obj.name + " class has a messed up base class list")
          return
        }
        return inheritance_lookup[old.name]
      }).filter(function(x) {return x != -1})
    }
    obj.loc = remap_file(obj.loc)
    for each (var m in obj.members) {
      m[MEMBER_TYPE] = remap_type(m[MEMBER_TYPE])
      m[MEMBER_DECL] = remap_file(m[MEMBER_DECL])
      var params = m[MEMBER_PARAMS]
      if (params)
        for (var i in params)
          params[i][PARAM_TYPE] = remap_type(params[i][PARAM_TYPE])
    }

    // this is to keep track of the indexes in the combined array of all classes
    inheritance_lookup[obj.name] = inheritance_lookup_length++
    // save object in form of ["name", loc1, loc2, <bases>, -1]
    inheritance.push(obj.name, obj.loc[0], obj.loc[1])
    if (obj.bases) inheritance.push.apply(inheritance, obj.bases)
    if (obj.members) {
      write_file(DIR + ["member", obj.name, obj.loc[0], obj.loc[1]].join("_") + ".js", uneval(obj.members))
      delete obj.members
    }
  }
}
function lookup2Array(obj) {
  var a = []
  for(var key in obj) {
    a.push(key)
  }
  return a
}

function input_end() {
  var ls = read_file("/tmp/list.txt").split("\n")
  ls.pop()
  for (var i in ls) {
    var file = ls[i] + ".pork"
    print(file + " " + i * 100/ls.length+"%")
    try{
      merge(file)
    } catch(e)
    {
      print(uneval(e))
    }
  }
  write_file(DIR + "inheritance.js", uneval(inheritance))
  inheritance = undefined
  write_file(DIR + "types.js", uneval(lookup2Array(types)))
  write_file(DIR + "files.js", uneval(lookup2Array(files)))
}
