#!/usr/bin/awk -f

BEGIN{
  first = 1
  hier = 0
  debug = 0
  hiersep="."
}

{
  reparse()
}

/^begin netlist/{
  cell = $4
  if(first) {
    topcell=cell
    first = 0
  }
  start[cell] = NR
}

/^end netlist/{
  end[cell] = NR
}
/^__GLOBAL__/{
  global[$2] = 1
}

/^__HIERSEP__/{
  hiersep = $2
}

{
  netlist[NR] = $0
}

END{
  out("tEDAx v1")
  out("begin netlist v1 " topcell)
  expand(topcell, "", "", "")
  out("end netlist")
}


function expand(cell, instname, path, maplist,       i, j, subpos, subcell, subinst, submaplist)
{
  hier++
  for(i = start[cell]+1; i <= end[cell]-1; i++) {
    $0 = netlist[i]
    reparse()
    # __subcircuit__ pcb_voltage_protection x0 
    # __map__ VOUT -> VOUTXX
    # __map__  ... -> ...
    if($1 == "__subcircuit__") {
      subcell=$2
      subinst=$3
      subpos = i
      sub(/__subcircuit__/, "subcircuit", $0)
      out("#" spaces(hier * 2 - 1) $0)
      submaplist = "" 
      for(i++; ;i++) {
        $0 = netlist[i]
        reparse()
        if($1 != "__map__") break
        dbg("expand: $4=" $4)
        $4 = resolve_node($4, path, maplist)
        submaplist = submaplist " " $2 " " $4
        sub(/__map__/, "map", $0)
        out("#" spaces(hier * 2 - 1) $0)
      }
      
      expand(subcell, subinst, path subinst hiersep, submaplist)
 
      i--; continue; # redo processing of current line
    }
    if($1 == "conn") {
      dbg("conn: $2=" $2)
      $2 = resolve_node($2, path, maplist) #net name
      $3 = path $3 #refdes
    }
    if($1 ~/^(device|footprint|value|spiceval|spicedev|comptag|pinname|pinslot|pinidx)$/) {
      $2 = path $2 #refdes
    }
    out(spaces(hier * 2) $0)
    if($0 ~ /^end netlist/) break
  }
  hier--
}

function spaces(n,     s)
{
  n = (n > 0) ? n - 1 : 0 
  s ="                        "
  while(length(s) < n) s = s s
  return substr(s,1,n)
}

function out(s)
{
  if(length(s) > 512) 
    print "flatten_tedax: WARNING: >> " s "\n  line length > 512 chars, this breaks tEDAx" > "/dev/stderr"
  print s
}

function dbg(s)
{
  if(debug) print s > "/dev/stderr"
}

function resolve_node(node, path, maplist,     arr, n, retnode, i) 
{
  dbg("resolve_node: node=" node " maplist=" maplist)
  gsub(/\\ /, SUBSEP "s", maplist)
  gsub(/\\\t/, SUBSEP "t", maplist)
  n = split(maplist, arr)
  for(i = 1; i <= n; i++) {
    gsub(SUBSEP "s", "\\ ", arr[i])
    gsub(SUBSEP "t", "\\\t", arr[i])
  }
  if(node in global) retnode = node
  else for(i = 1; i <= n; i += 2) {
    if(node == arr[i]) {
      retnode = arr[i+1]
      break
    }
  }
  if(retnode =="") retnode = path node
  return retnode
}

# avoid considering escaped white spaces as field separators
function reparse(    i)
{
  gsub(/\\ /, SUBSEP "s")
  gsub(/\\\t/, SUBSEP "t")
  for(i = 1; i <= NF; i++) {
    gsub(SUBSEP "s", "\\ ", $i)
    gsub(SUBSEP "t", "\\\t", $i)
  }
}

