#!/usr/bin/python
import sys, os.path, os, tempfile, socket
from os import getenv, popen, system
from fcntl import fcntl, F_SETFD, F_GETFL

def count_cpus():
  #first try linux, then osx
  try:
    return len([line for line in
                open("/proc/cpuinfo").read().split("\n")
                    if line[0:9] == "processor"])
  except:
     return int(popen("sysctl hw.availcpu").read().split(" ")[2])
    
MOZBUILD = os.path.expanduser("~/work/ff-build/")
MOZSRC = os.path.expanduser("~/work/mozilla/")
SQUASH = os.path.expanduser("~/work/oink-stack/oink/squash")
RUN_SQUASH = os.path.expanduser("~/work/squash-run/run_squash")
cpu_count = count_cpus()

def run_squash(curr_params, param_queue, new_params):
  param_queue.append(new_params)
  if curr_params != None:
    return (curr_params, param_queue, None)
  curr_params = param_queue.pop(0)
  child_stdin, child_stdout, child_stderr = os.popen3( "%s %s" % (RUN_SQUASH, curr_params), "r", 40960)
  child_stdin.close()
  fd = child_stdout.fileno()
  fcntl(fd, F_SETFD, fcntl(fd, F_GETFL) | os.O_NONBLOCK)
  fd = child_stderr.fileno()
  fcntl(fd, F_SETFD, fcntl(fd, F_GETFL) | os.O_NONBLOCK)
  return (curr_params, param_queue, (child_stdout, child_stderr))

def read_output(input_pair):
  if input_pair == None:
    return (None, None)
  stdout, stderr = input_pair
  output = ""
  if stdout != None:
    output = stdout.read(4096)
    if output == "":
      stdout = None
  if stderr != None:
    erroutput = stderr.read(4096)
    if erroutput == "":
      stderr = None
    output = output + erroutput
  
  if stdout == None and stderr == None:
    input_pair = None
  else:
    input_pair = (stdout, stderr)
  return (input_pair, output)

def run_server():
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  port = 9000
  while True:
    try:
      s.bind(("localhost", port))
      s.listen(50)
      print "Listening on %d" % port
      break
    except:
      port = port + 1
  children = {}
  curr_params = None
  curr_io = None
  param_queue = []
  try:
    while True:
      print "Wating for conn"
      conn, addr = s.accept()
      sin = conn.makefile()
      conn.close()
      args = sin.readline().strip().split(" ")
      print(args)
      if args[0] == "prepare":
        if os.fork() == 0:
          renameclass, member, renamed_member = args[1:]
          sin.write(getCmdLine(renameclass, member, renamed_member))
      elif args[0] == "run":
        new_params = " ".join(args[1:])
        curr_params, param_queue, curr_io = run_squash(curr_params, param_queue, new_params)
        if curr_params == new_params:
          sin.write(curr_params)
        else:
          sin.write("queued")
      elif args[0] == "status":
        new_params = " ".join(args[1:])
        if curr_params != new_params:
          print "nostatus"
          sin.write("nostatus")
        else:
          curr_io, ret = read_output(curr_io)
          if curr_io == None:
            curr_params = None
            if param_queue != []:
              new_params = param_queue.pop(0)
              curr_params, param_queue, curr_io = run_squash(curr_params, param_queue, new_params)
          sin.write(ret)
      sin.close()
  except (OSError, IOError, KeyboardInterrupt, socket.error), e:
    print ("Error %s" % e)
    s.close()
    sys.exit()

def get_config(renameclass, member, renamed_member, rest):
  return "-o-lang GNU_Cplusplus -sq-no-squash -sq-implementation '%s' -sq-rename-member '%s' '%s' %s" % (renameclass, member, renamed_member, rest)

def generateInputFiles(member):
  cmd = "find %s -name \\*.cpp | egrep -v /xpcom/\\|%s | xargs egrep -w -l %s 2> /dev/null" % (MOZSRC, "\\|".join(["nsTextFrameThebes.cpp"]),member)
  srcfiles = popen(cmd).read().rstrip().split("\n")
  ifiles = [MOZBUILD + file[len(MOZSRC):len(file) - len("cpp")] + "i" for file in srcfiles]
  idirs = {}
  for file in ifiles:
    (dir, name) = os.path.split(file);
    if not idirs.has_key(dir):
      idirs[dir] = [name]
    else:
      idirs[dir].append(name)
  for directory, files in idirs.iteritems():
    system("make -j %i -C %s %s > /dev/null 2> /dev/null" % (cpu_count, directory, " ".join(files)))
  f, filename = tempfile.mkstemp("","input_files")
  os.write(f,"\n".join([file for file in ifiles if os.path.exists(file)]))
  os.close(f)
  return filename

def getInputFile(cmdline):
  return cmdline.split(' ')[2]

def getCmdLine(renameclass, member, renamed_member, rest = ""):
  return "%i %s %s %s" % (cpu_count,
        SQUASH, generateInputFiles(member),
        get_config(renameclass, member, renamed_member, rest),
        )


if __name__ == "__main__":
  if sys.argv == [sys.argv[0], "tcp-server"]:
    run_server()
  elif len(sys.argv) == 4:
    _, renameclass, member, renamed_member = sys.argv
    print("%s %s" % (RUN_SQUASH, getCmdLine(renameclass, member, renamed_member)))
    #"nsIFrame" "GetPresContext" "PresContext"
  else:
    raise "Usage: %s Class oldMemberName newMemberName" % sys.argv[0]
