import subprocess
import os
import sys

CMD = None
EXPECTED = None
SEGFAULT = False
FILE = None
BACKUPFILE = None
for arg in sys.argv[1:]:
  if arg.startswith('--cmd='):
    CMD = arg[arg.find('=')+1:]
  elif arg.startswith('--expected='):
    EXPECTED = arg[arg.find('=')+1:]
  elif arg.startswith('--file='):
    FILE = arg[arg.find('=')+1:]
    BACKUPFILE = FILE + '.bak'
  elif arg == '--segfault':
    SEGFAULT = True

if CMD is None:
  print('Abort: No --cmd')
  sys.exit(1)

if SEGFAULT == False and EXPECTED is None:
  print('Abort: No --expected')
  sys.exit(1)

if FILE is None:
  print('Abort: No --file')
  sys.exit(1)

print('CMD='+CMD)
if SEGFAULT:
  print('EXPECTED=SEGFAULT')
else:
  print('EXPECTED='+EXPECTED)
print('FILE='+FILE)

def runtool():
  p = subprocess.Popen(CMD.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  comm = p.communicate()
  if SEGFAULT:
    if p.returncode != 0:
      return True
  elif p.returncode == 0:
    out = comm[0] + '\n' + comm[1]
    if (out.find('error:') < 0) and (out.find(EXPECTED) > 0):
      return True
  return False

def writefile(filename, filedata):
  f = open(filename, 'wt')
  for line in filedata:
    f.write(line)
  f.close()

def replaceandrun(what, filedata, i, line):
  print(what + ' ' + str(i+1) + '/' + str(len(filedata)) + '..')
  bak = filedata[i]
  filedata[i] = line
  writefile(FILE, filedata)
  if runtool() == True:
    print('pass')
    writefile(BACKUPFILE, filedata)
    return True
  print('fail')
  filedata[i] = bak
  return False

def replaceandrun2(what, filedata, i, line1, line2):
  print(what + ' ' + str(i+1) + '/' + str(len(filedata)) + '..')
  bak1 = filedata[i]
  bak2 = filedata[i+1]
  filedata[i] = line1
  filedata[i+1] = line2
  writefile(FILE, filedata)
  if runtool() == True:
    print('pass')
    writefile(BACKUPFILE, filedata)
  else:
    print('fail')
    filedata[i] = bak1
    filedata[i+1] = bak2

def removecomments(filedata):
  for i in range(len(filedata)):
    line = filedata[i]
    if line.find('//') >= 0:
      replaceandrun('remove comment', filedata, i, line[:line.find('//')].rstrip())

def checkpar(line):
  par = 0
  for c in line:
    if c=='(' or c=='[':
      par = par + 1
    elif c==')' or c==']':
      par = par - 1
      if par<0:
        return False
  return par == 0

def combinelines(filedata):
  if len(filedata) < 3:
    return

  lines = []

  for i in range(len(filedata)-1):
    fd1 = filedata[i].rstrip()
    if fd1.endswith(','):
      fd2 = filedata[i+1].lstrip()
      if fd2 != '':
        lines.append(i)

  chunksize = len(lines)
  while chunksize > 10:
    i = 0
    while i < len(lines):
      i1 = i
      i2 = i + chunksize
      i = i2
      if i2 > len(lines):
        i2 = len(lines)

      filedata2 = list(filedata)
      for line in lines[i1:i2]:
        filedata2[line] = filedata2[line].rstrip() + filedata2[line+1].lstrip()
        filedata2[line+1] = ''

      if replaceandrun('combine lines', filedata2, lines[i1]+1, ''):
        filedata = filedata2
        lines[i1:i2] = []
        i = i1

    chunksize = chunksize / 2

  for line in lines:
    fd1 = filedata[line].rstrip()
    fd2 = filedata[line+1].lstrip()
    replaceandrun2('combine lines', filedata, line, fd1+fd2, '')

def removeline(filedata):
  stmt = True
  for i in range(len(filedata)):
    line = filedata[i]
    strippedline = line.strip()

    if len(strippedline) == 0:
      continue

    if stmt and strippedline[-1]==';' and checkpar(line) and line.find('{')<0 and line.find('}')<0:
      replaceandrun('remove line', filedata, i, '')

    elif stmt and strippedline.find('{') > 0 and strippedline.find('}') == len(strippedline) - 1:
      replaceandrun('remove line', filedata, i, '')

    if ';{}'.find(strippedline[-1]) >= 0:
      stmt = True
    else:
      stmt = False


def removeincludes(filedata):
  for i in range(len(filedata)):
    if filedata[i].startswith('#include '):
      replaceandrun('remove #include', filedata, i, '')

def removeemptyblocks(filedata):
  if len(filedata) < 3:
    return

  i = 0
  while i < len(filedata):
    if filedata[i].strip() == '':
      filedata.pop(i)
    else:
      i = i + 1

  for i in range(len(filedata)-1):
    fd1 = filedata[i].rstrip()
    fd2 = filedata[i+1].strip()
    if checkpar(fd1) and fd1.endswith('{') and fd2 == '}':
      replaceandrun2('remove block', filedata, i, '', '')

def removenamespaces(filedata):
  if len(filedata) < 3:
    return filedata

  stmt = True

  for i in range(len(filedata)):
    line = filedata[i]
    strippedline = line.strip()

    if len(strippedline) == 0:
      continue

    stmt1 = stmt
    if ';{}'.find(strippedline[-1]) >= 0:
      stmt = True
    else:
      stmt = False

    if stmt1 == False:
      continue

    if strippedline.find('}') < 0 and strippedline.find('{') == len(strippedline)-1:
      i2 = i + 1
      level = 1
      while i2 < len(filedata) and level > 0:
        #print(str(i2)+':'+str(level)+':'+filedata[i2])
        for c in filedata[i2]:
          if c == '}':
            level = level - 1
            if level <= 0:
              break
          elif c == '{':
            level = level + 1
        i2 = i2 + 1
      if level == 0 and (filedata[i2-1].strip().endswith('}') or filedata[i2-1].strip().endswith('};')):
        #print(str(i)+';'+str(i2))
        filedata2 = list(filedata)
        ii = i
        while ii < i2:
          filedata2[ii] = ''
          ii = ii + 1
        if replaceandrun('remove codeblock', filedata2, i, ''):
          filedata = filedata2
  return filedata

# reduce..
print('Make sure error can be reproduced...')
if runtool() == False:
     print("Cannot reproduce")
     sys.exit(1)

f = open(FILE, 'rt')
filedata = f.readlines()
f.close()

writefile(BACKUPFILE, filedata)

print('remove comments...')
removecomments(filedata)
print('combine lines..')
combinelines(filedata)
print('remove namespaces...')
filedata = removenamespaces(filedata)
print('remove includes...')
removeincludes(filedata)
print('remove line...')
removeline(filedata)
print('remove includes...')
removeincludes(filedata)
print('remove empty blocks...')
removeemptyblocks(filedata)
print('remove namespaces...')
filedata = removenamespaces(filedata)



writefile(FILE, filedata)