#!/usr/bin/python
################################################################
#
#              Renumber Propositions 
#
################################################################
#
#  To re-order files using shortened prop_num's the file may
#  be saved before major re-orderings, by calling renum using 
#  the -f switch, re-ordered at will using the full labels, 
#  and then renumbered again without the -f switch.
#
################################################################
import os, re, time, io
import argparse
from document import build_blocklist
import pattern
#

parser = argparse.ArgumentParser()

parser.add_argument("file",
		help = "name of the file with propositions to be renumbered")

parser.add_argument("-f", "--fullproplabels", action = "store_true",
		help = "label propositions with complete enumeration")

parser.add_argument("-o", "--outfile", type=str,
		help = "output to this file instead of overwriting original")

parser.add_argument("-r", "--renumfile", type=str,
		help = "use renum file")

parser.add_argument("-s", "--suffix", type=str,
		help = "use renum file to replace references with given suffix")

parser.add_argument("-z", "--zeroplus", action = "store_true", 
		help = "use renum file to do zero plus replacements")

args = parser.parse_args()


if args.file.endswith(".tex"):
	Arg_1 = args.file[:-4]
else:
	Arg_1 = args.file
filename = Arg_1 + ".tex" 
if not os.path.isfile(filename):
	raise SystemExit(filename + ' not found.')


if args.suffix or args.zeroplus:
		if not args.renumfile:
				raise SystemExit("Must specify the '.rnm' file")
		if args.suffix and args.zeroplus:
				raise SystemExit("Can't use zeroplus and suffix both on one renum file")
else:
		if args.renumfile:
				raise SystemExit("Must specify zeroplus or a suffix.")


##########################################################
#
#  Set up default Enumeration format 
#
##########################################################


if os.path.isfile(Arg_1 + ".ldf"):
	df_file = open(Arg_1 + ".ldf")
	latex_flag = True
	refnum_format = "section.prop"
elif os.path.isfile(Arg_1 + ".tdf"):
	df_file = open(Arg_1 + ".tdf")
	latex_flag = False
	refnum_format = "chap.prop"
else:
	df_file = None
	latex_flag = False
	refnum_format = "chap.prop"

unit_list = refnum_format.split('.')
num_nums = len(unit_list)
init_list = num_nums * ['1']

##########################################################
#
#  Check for Enumeration format definition in .ldf file
#
##########################################################

latex_sectionings = ['chapter', 'section', 'subsection', 
											'subsubsection', 'paragraph','subparagraph']
propnum_format_defined = False

if df_file:
	for r in df_file:
		directivem = pattern.directive.match(r)
		if directivem:
			if directivem.group(1)== "refnum_format:":
				if propnum_format_defined:
					print("refnum_format definition must come before propnum_format definition")
					raise SystemExit()
				arglist = directivem.group(2).split()
				refnum_format = arglist[0] 
				unit_list = refnum_format.split('.')
				for item in unit_list:
					if item == 'prop' or item == 'chap':
						pass
					elif item in latex_sectionings:
						pass
					else:
						print("Warning unfamiliar unit:", item)
				num_nums = len(unit_list) 
				if len(arglist) > 1 and arglist[1].count('.') + 1 == num_nums:
					if arglist[1].count('.') + 1 != num_nums:
						print("Error in directive:", r)
						raise SystemExit(str(num_nums) + " initial counter values expected")
					ref_start = arglist[1]
					init_list = ref_start.split('.')
					for item in init_list:
						if item.isdigit():
							pass
						else:
							print("Error in directive:", r)
							raise SystemExit("Initial value of counter must be numeric: " + item)
				else:
					init_list = num_nums * ['1']

			if directivem.group(1)== "propnum_format:":
				propnum_format = directivem.group(2).rstrip()
				for x in propnum_format.split("."):
					if x not in refnum_format: 
						raise SystemExit(x + " not a reference format unit.")
				propnum_format_defined = True

if	not propnum_format_defined:
	propnum_format = refnum_format
	

adjusted_init_list = []
for k in range(num_nums):
	if k + 1 == num_nums:
		adjusted_init_list.append(init_list[k])
	else:
		adjusted_init_list.append(str(int(init_list[k])- 1))

ref_element = pattern.latex_unit_prefix + "("+ "|".join(unit_list) +\
								")" + pattern.latex_unit_suffix

ref_unit = re.compile(ref_element)

##########################################################
#
# Scan file and build replacement dictionary, 
# change_num, using only ref_format's. 
#  (Or get it from a .rnm file)
#
# If prop_format is shorter than ref_format
# replace prop_format labels by ref_format's.
#
##########################################################

f = open(filename,"r")
linelist = f.readlines()
f.close()

change_num = {}
outlist = []
inlist = []
if args.renumfile: 
	try:
		f = open(args.renumfile,"r")
	except:
		raise SystemExit("Can't open renum file: " + args.renumfile)
	lines = f.readlines()
	f.close()
	for x in lines:
		if x[0] == "#":
			pass
		else:
			y = x.split()
			if len(y) != 2:
				print("Error in ", args.renumfile) 
				print(x)
				raise SystemExit
			else:
				outlist.append(y[1])			
				inlist.append(y[0])
				change_num[y[1]] = y[0]
else:
	newlinelist = []
			
	new_ref = ".".join(adjusted_init_list) 
	new_refstrings = new_ref.split(".")
	new_ref = ".".join(new_refstrings)
	reflist = []
	for r in linelist:
		ref_unitm = ref_unit.match(r)
		propnumm = pattern.propnum.match(r)
		chaptheadm = pattern.chapthead.match(r)
		if propnumm:
				old_propnum = propnumm.group('refnum')
				old_propnum_len = old_propnum.count('.') + 1
				if old_propnum_len !=  num_nums:
					old_refstrings = new_refstrings[:num_nums - old_propnum_len] + old_propnum.split(".")
					old_ref = ".".join(old_refstrings)
				else:
					old_ref = old_propnum
				if old_ref in reflist:
					print(old_ref + ' is a duplicate reference!')
					raise SystemExit
				else:
					reflist.append(old_ref)
				if new_ref != old_ref: 
					outlist.append(old_ref)
					inlist.append(new_ref)
					change_num[old_ref] = new_ref
				new_refstrings = new_ref.split(".")
				if old_propnum_len != num_nums:
					r = re.sub(old_propnum,old_ref,r, count=1)
				this_refnum = new_refstrings[-1]
				next_refnum = str(int(this_refnum) + 1)
				new_refstrings[-1] = next_refnum	
				new_ref = ".".join(new_refstrings)
		elif ref_unitm and ref_unitm.group(1) in unit_list:
				new_refstrings = new_ref.split(".")
				new_refnums = [int(x) for x in new_refstrings]
				level = ref_unitm.group(1)
				level_found = False
				for k in range(num_nums):
					if unit_list[k] == level:
						new_refnums[k] = new_refnums[k] + 1
						level_found = True
					elif level_found and k + 1 == num_nums:
						new_refnums[k] = init_list[k] 
					elif level_found:
						new_refnums[k] = str(int(init_list[k]) - 1)
				new_refstrings = [str(x) for x in new_refnums]
				new_ref = ".".join(new_refstrings)
#
				if chaptheadm and not latex_flag:   #Plain TeX \chap title renumbering
						pass
						old_num = chaptheadm.group(1)
						new_refstrings = new_ref.split(".")
						new_num = new_refstrings[0]
						if old_num != new_num:
								r = re.sub(old_num,new_num,r, count = 1)

		newlinelist.append(r)

	linelist = newlinelist

	if args.fullproplabels:
		pass
	elif propnum_format.count('.') + 1 < old_propnum_len: 
		pass
	elif not outlist:
		print("No new numbering")
		raise SystemExit

##########################################################
#
# Create .rnm file for use renumbering files which reference this file.
#
##########################################################

	if outlist:
		t = time.localtime()
		f = open(Arg_1 + "-" + str(t[1]) + "-" + str(t[0]) + ".rnm","w")
		f.write("# Renumbering of " + Arg_1 + ".tex\n")
		f.write("# " + time.asctime(time.localtime())+ "\n")
		f.write("#  New  Old\n")
		for j in range(len(inlist)):
			f.write("%s  %s\n" % (inlist[j],outlist[j]))
		f.close()

##########################################################
#
# Do global replace of ref_formats's in all non-math text 
#
##########################################################

def changefun(x):
	y = x.group(0)
	return change_num.get(y,y)

numrepstr = "\.".join(num_nums * ["\d+"]) 
if args.suffix:
		s = args.suffix
		refpat = re.compile(numrepstr + "(?=" + s + "(?!\w))")
elif args.zeroplus:
		refpat = re.compile("(?<=(?<!\w)0)" + numrepstr)
else:
		refpat = re.compile(numrepstr + "(?!\w)")
#
blocklist = build_blocklist(linelist)

strings = []
for i, block in enumerate(blocklist):
	if i & 1:
		for pointedstring in block:
			strings.append(pointedstring[0])
	else:
		for pointedstring in block:
			strings.append(re.sub(refpat,changefun,pointedstring[0]))

newfilestring = ''.join(strings)

##########################################################
#
# Output renumbered file.
# Shorten props fully labelled ref_format's
# unless -f (args.fullproplabels) is raised.
#
##########################################################

def shorten(long_format, short_format, long_ref):
	assert long_format.count('.') == long_ref.count('.')
	long_refnums = long_ref.split('.')
	long_refunits= long_format.split('.')
	short_refunits= short_format.split('.')
	short_refnums = []
	for k in range(len(long_refunits)):
		if long_refunits[k] in short_refunits:
			short_refnums.append(long_refnums[k])
	return ".".join(short_refnums)

if args.outfile:
	g = open(args.outfile,"w")
else:
	g = open(filename,"w")

f = io.StringIO(newfilestring).readlines()

if not args.fullproplabels and refnum_format.count('.') > propnum_format.count('.'): 
	for r in f:
		propnumm = pattern.propnum.match(r)
		if propnumm:
			long_num = propnumm.group('refnum')
			short_num = shorten(refnum_format,propnum_format, long_num)
			r = re.sub(long_num,short_num,r, count=1)
		g.write(r)
else:
	for r in f:
		g.write(r)
g.close()



		

