#!/usr/bin/env python3

import fileinput
import io, os, re, datetime
import hashlib
import variables
import time

from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed

qsp_sources_path = "locations"
tw_sources_path = os.path.join("sugarcube","src")

verbose = False
#verbose = True
skipMode = 0
#skipMode = -1

verbose_i = 20


error_counter = 1
regex_parts = {}

regex_parts['operator_assign'] = r'=|\+=|-='

regex_parts['parameter'] = r"\$ARGS\[\d+\]"
regex_parts['var'] = r"\$?[a-z]+\w*"
regex_parts['functioncall'] = r"\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\)"

regex_parts['integer'] = r"\d+"
regex_parts['string'] = r"""'\w'|"""+ r'''"\w"'''

regex_parts['value_literal'] = "|".join([regex_parts['integer'],regex_parts['string']])

regex_parts['value'] = "|".join([regex_parts['parameter'],regex_parts['var'],regex_parts['functioncall'],regex_parts['value_literal'] ])

regex_parts['statement'] = '?'

regex_parts['assignment'] = f"\s*({regex_parts['var']})\s*({regex_parts['operator_assign']})\s*({regex_parts['value']})\s*"

def pv(desc,line):
	if(verbose):
			print(desc.ljust(verbose_i, ' ')+line)

def convert_calculation(right):
	pv("START CALCULATION:",right)
	brackets_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
	#brackets_regex = r"""(?<![a-zA-Z0-9])(?:min|rand|max|mid)\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
	calculations = []
	#print(right)
	while b_match := re.search(brackets_regex,right):
		complete_match = b_match.group(0)
		calculation_raw = b_match.group(1)
		operator = b_match.group(2)
		if operator == 'mod':
			calculation_raw = calculation_raw.replace('mod','%')
		calculation = convert_literal(calculation_raw)
		index = f"$CALC_HELPER_{len(calculations)}"
		right = right.replace(complete_match,index)
		calculations.append(calculation)
	right = convert_literal(right)

	#function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""


	#while function_name_match := re.search(function_name_regex,right):
	#	complete_match = function_name_match.group(0)
	#	index = f"$LIT_HELPER_{len(calculations)}"
	#	right = right.replace(complete_match,index)
	#	calculations.append(complete_match)

	while len(calculations) > 0:
		calculation = calculations.pop()
		index = f"$CALC_HELPER_{len(calculations)}"
		right = right.replace(index,f"({calculation})")
	pv("IS CALCULATION:",right)
	return right

def convert_command(command_raw):



	command = command_raw.strip()

	#if (command.startswith('<') or  and command.endswith('>'):
	#	return command

	split_by_and = command.split(' & ')
	if len(split_by_and) > 1:
		return ' '.join([convert_command(s) for s in split_by_and])

	assign_operators = ['=','-=','+=']
	for assign_operator in assign_operators:
		split_by_assign = command.split(assign_operator,1)
		if len(split_by_assign) > 1:
			left = split_by_assign[0]
			if left.startswith('set '):
				left = left[4:]

			right = split_by_assign[1]

			right = convert_calculation(right)

			pv("IS ASSIGNMENT:",right)
			return f'<<set {convert_literal(left)} {assign_operator} {right}>>'

	if match := re.match(r"^(?:set\s*)?(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command):
		return f'<<set {convert_literal(match.group(1))} {match.group(2)} {convert_literal(match.group(3))}>>'

	if match := re.match(r"""^(x?gt|gs)([\s'"].+)$""",command):
		arguments = match.group(2)
		pv('GS OR GT:',command)
		i = 0
		replaces = []
		while brackets_match := re.search(r"""\(([^\(^\)]*?,[^\(^\)]*?)\)""",arguments):
			original = brackets_match.group(1)
			pv("REPLACE:",original)
			indentifier = f'$BRACKET_HELER_{i}'
			arguments = arguments.replace(original,indentifier)
			replaces.append(original)
			i += 1

		arguments = " ".join([convert_literal(l) for l in arguments.split(',')])

		while len(replaces) > 0:
			original = replaces.pop()
			indentifier = f'$BRACKET_HELER_{len(replaces)}'
			arguments = arguments.replace(indentifier,original)

		return f'<<{match.group(1)} {arguments}>>'

	if match := re.match(r"""^msg\s*(.+)$""",command,re.I):
		return f"<<msg {match.group(1)}>>"

	if match := re.match(r"""^dynamic \$(.*)$""",command,re.I):
		arguments = match.group(1).replace(',',' ')
		return f"<<{arguments}>>"



	pv("NO COMMAND MATCH:",command)

	return ''


def convert_condition(condition_raw):
	condition = condition_raw.strip()

	if(re.match(r"dyneval\(",condition)):
		return condition

	#condition = convert_calculation(condition)
	#print(condition)
	subconditions = []

	bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+)\s*\)"""
	bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*and|or|xor\s*)[^\)^\(]+)\s*\)"""

	while match := re.search(bracket_search_regex,condition):
		fullmatch = match.group(0)
		subcondition = match.group(1)
		subcondition_converted = convert_condition(subcondition)
		subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
		condition = condition.replace(fullmatch,subcondition_ident)
		subconditions.append(subcondition_converted)
		#print(condition)

	if len(subconditions) > 0:
		condition = convert_condition(condition)
		while len(subconditions) > 0:
			subcondition = subconditions.pop()
			subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
			condition = condition.replace(subcondition_ident,f"({subcondition})")
			#print(condition)
		return condition


	split_by_or = condition.split(' or ')
	if len(split_by_or) > 1:
		return ' or '.join([convert_condition(s) for s in split_by_or])

	split_by_xor = condition.split(' xor ')
	if len(split_by_xor) > 1:
		return ' xor '.join([convert_condition(s) for s in split_by_xor])

	split_by_and = condition.split(' and ')
	if len(split_by_and) > 1:
		return ' and '.join([convert_condition(s) for s in split_by_and])

	#match = re.match(r"(\$ARGS\[\d+\]|\$?\w+)\s*([=><]+)\s*('?\w+'?)",condition)
	#match = re.match(r"(\S+)\s*([=><]+)\s*(\S+)",condition)

	if(len(condition) >= 2 and condition[0] == '(' and condition[-1] == ')'):
		condition = condition[1:-1]
	#print(condition)
	match = re.match(r"([^<^>^=^!]+)\s*([=><!]+)\s*([^<^>^=^!]+)",condition)

	if match:
		left = convert_literal(convert_calculation(match.group(1)))
		right = convert_literal(match.group(3))
		operator = match.group(2)

		if operator == '=':
			operator = '=='
		elif operator == '!':
			operator = '!='
		elif operator == '=>':
			operator = '>='
		elif operator == '=<':
			operator = '<='


		return ' '.join([left,operator,right])

	return f'ERROR: FAILED TO CONVERT CONDITION: {condition}'

def convert_literal(literal_raw):
	literal = literal_raw.strip()
	pv("START LITERAL:",literal)
	if not literal:
		return ''

	subliterals = []
	bracket_search_regex = r"""\[\s*([^\]^\[]+)\s*\]"""
	while match := re.search(bracket_search_regex,literal):
		fullmatch = match.group(0)
		subcondition = match.group(1)
		subcondition_converted = convert_literal(subcondition)
		subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
		literal = literal.replace(fullmatch,subcondition_ident)
		subliterals.append(subcondition_converted)
		#print(condition)

	if len(subliterals) > 0:
		literal = convert_literal(literal)
		while len(subliterals) > 0:
			subcondition = subliterals.pop()
			subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
			literal = literal.replace(subcondition_ident,f"[{subcondition}]")
			#print(condition)
		return literal

	#brackets_regex = r"""\(\s*([^\)^\(]+)\s*\)"""
	#function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""
	#calculations = []
	#while b_match := re.search(brackets_regex,literal):
	#	complete_match = b_match.group(0)
	#	calculation_raw = b_match.group(1)
	#	calculation_parts = calculation_raw.split(',')
	#	calculation = ','.join([convert_literal(s) for s in calculation_parts])
	#	index = f"$LIT_HELPER_{len(calculations)}"
	#	literal = literal.replace(complete_match,index)
	#	calculations.append(calculation)

	#while function_name_match := re.search(function_name_regex,literal):
	#	complete_match = function_name_match.group(0)
	#	index = f"$LIT_HELPER_{len(calculations)}"
	#	literal = literal.replace(complete_match,index)
	#	calculations.append(complete_match)

	#if len(calculations) > 0:
	#	literal = convert_literal(literal)
	#	while len(calculations) > 0:
	#		calculation = calculations.pop()
	#		index = f"$LIT_HELPER_{len(calculations)}"
	#		literal = literal.replace(index,f"({calculation})")
	#	pv("LITERAL AFTER BRACKETS:",literal)

	if(re.match(r"dyneval\(",literal)):
		return literal

	if literal == "''" or literal == '""':
		return literal


	if(literal.isnumeric() or (literal.startswith('-') and literal[1:].isnumeric())):
		pv("IS NUMERIC",literal)
		return literal

	if(literal.startswith('(') and len(literal) > 1):
		return '('+literal[1:]
	if(literal.endswith(')') and len(literal) > 1):
		return literal[:-1]+')'

	#array_braces = False
	#while match:=re.match(r"\$?([a-z][a-z0-9\-_{}'\+]*)(\['(.*?<<.*?>>'*?)'\])",literal,re.I):
	#	value = match.group(3)
	#	if not value.startswith("<"):
	#		value = value.replace("<<","'+")
	#	else:
	#		value = value.replace("<<","")#
	#
	#	if not value.endswith(">"):
	#		value = value.replace(">>","+'")
	#	else:
	#		value = value.replace(">>","")
	#	literal = literal.replace(match.group(2),r"{{"+value+r"}}")
	#	array_braces = True
	#if array_braces:
	#	literal = literal.replace(r'{{','[').replace(r'}}',']')



	if(len(literal)>= 3 and ((literal[0] == '\'' and literal[-1] == '\'') or (literal[0] == '"' and literal[-1] == '"') )):

		literal = literal.replace('<<','')
		literal = literal.replace('>>','')
		literal = literal.replace("''","'")

		return literal



	if(match := re.match(r"^arrsize\(\s*'(\$?)([a-z]+\w*)'\s*\)$",literal)):
		return f"${match.group(2)}.length"

	if(match := re.match(r"^killvar\s+'(\$?)([a-z]+\w*)'$",literal,re.I)):
		return f"<<set ${match.group(2)} to null>>"

	if(match := re.match(r'^\$ARGS\[(\d+)\]$',literal,re.I)):
		#ARGS
		return f'$location_var[$here][{match.group(1)}]'

	if(match := re.match(r'^\$ARGS(LIT_HELPER_\d+)$',literal,re.I)):
		#ARGS
		return f'$location_var[$here]'+match.group(1)

	if(match := re.match(r"^(\$?)[a-zA-z]+\w*(\[('\w*'|\d+)\])?$",literal)):
		if match.group(1):
			return literal
		return '$'+literal

	if(match := re.match(r"^(\$?)([a-zA-z]+\w*)\[(.+)\]$",literal)):
		#if match.group(1):
		#	return f"${match.group(2)}[{convert_literal(match.group(3))}]"
		return f"${match.group(2)}[{convert_literal(match.group(3))}]"
	#print(literal)


	if(match := re.match(r'^(\w+)\s*\((\s*\w+\s*(?:,\s*\w*\s*)*)\)$',literal)):
		function_name = match.group(1)
		function_parameters = match.group(2)
		return f'{function_name}({convert_literal(function_parameters)})'

	while(match := re.search(r'<<(\$\w+)>>',literal)):
		literal = literal.replace(match.group(0),match.group(1))

	#Arithmetic Operations
	arith_operations = ['*','/','-','+','%',',','mod']
	for arith_operation in arith_operations:
		split_by_arith = literal.split(arith_operation)
		if len(split_by_arith) > 1:
			if arith_operation == 'mod':
				arith_operation = '%'
			return f' {arith_operation} '.join([convert_literal(s) for s in split_by_arith])


	if literal.startswith('wait '):
		return f'<<{literal}>>'

	if(match := re.match(r"""^killvar\s+['"]\$?(.*)['"]$""",literal)):
		return f'<<set ${match.group(1)} = 0>>'

	if literal.startswith('jump '):
		jump_san = literal.replace('"','').replace("'","")
		return f"<<warn 'JUMP COMMAND ENCOUNTERED: {jump_san}'>>"

	if literal.startswith(':'):
		return f"<<warn 'JUMP MARKER ENCOUNTERED: {literal}'>>"

	if literal == "'" or literal == '"':
		return ''

	if re.match(r"""^['"\w\s\?\.!\(\)\$]+$""",literal):
		pv("Plain String",literal)
		return literal

	#return literal
	return f'ERROR: FAILED TO CONVERT LITERAL: """{literal}"""'


function_name_conversions = []


def convert_lineblock(lines,location_identifier=''):
	outputs = []

	nesting = []
	commenting = False
	isfunction = False
	functionlines = []
	functionlines_temp = []
	function_name = ''

	subpassages = {}
	subpassage = ''

	for line_raw in lines:
		#line_raw = lines[line_num]
		line = line_raw.strip()
		original = line

		pv("START:",line)

		if len(line) == 0:
			continue

		whitespace_count = len(nesting)

		# Subpassages
		if len(subpassage) > 0:
			if line.startswith('~$'):
				endSubpassageName = line[2:]
				gtOrGs = 'gt'
				if endSubpassageName.startswith('gs:'):
					gtOrGs = 'gs'
					endSubpassageName = endSubpassageName[3:]
				if endSubpassageName == subpassage:
					outputs.append( whitespace_count * '\t' + f"<<{gtOrGs} '{subpassage}' $location_var[$here][0] $location_var[$here][1] $location_var[$here][2] $location_var[$here][3] $location_var[$here][4]>>\n")
					subpassages[subpassage].append('<!-- END: '+subpassage+' -->')
					subpassage = ''
					continue
			subpassages[subpassage].append(line)
			continue

		if len(subpassage) == 0:
			if line.startswith('~^'):
				startSubpassageName = line[2:]
				subpassage = startSubpassageName
				subpassages[subpassage] = []
				continue



		for preparation in preparations:
			if len(preparation) > 2:
				line = re.sub(preparation[0],preparation[1],line,0,preparation[2])
			else:
				line = re.sub(preparation[0],preparation[1],line)


		line_output = ''



		purges = [
			'CLOSE ALL',
			'close all',
			'*clr & cla',
			'killall',
			'showstat 0','showstat 1',
			'showobjs 0','showobjs 1',
			'showinput 0','showinput 1',
			"gs 'stat'","gs'stat'",
		]

		for purge in purges:
			line = line.replace(purge,'')

		pv("AFTER PURGES:",line)

		#line = line.replace(" mod "," % ")

		#while match := re.match(r"iif\s*\((.+),(.*),(.*)\)",line):
		#	line = line.replace(match.group(0),f"({convert_condition(match.group(1))}) ? {convert_literal(match.group(2))} : {convert_literal(match.group(3))}")




		# FUNCTIONS
		if isfunction:
			if line.endswith('}'):
				isfunction = False
				functionname_sanatized = function_name.replace('$','').replace('[','').replace(']','').replace("'",'')
				functionlines.append(f':: {functionname_sanatized}_macro[widget]\n<<widget "{functionname_sanatized}">>\n')
				functionlines_temp = convert_lineblock(functionlines_temp)
				for fl in functionlines_temp:
					functionlines.append(f'\t{fl}')
				functionlines.append(f'<</widget>>\n')
				function_name_conversions.append([function_name,functionname_sanatized])
			else:
				functionlines_temp.append(line)
			continue

		if match := re.match(r"""(\$[a-z][a-z0-9\-_'"\[\]]+)\s*=\s*{""",line,re.I):
			isfunction = True
			#functionlines.append(f'<<widget "{match.group(1)}">>')
			function_name = match.group(1)
			functionlines_temp = []
			continue

		pv("AFTER FUNCTIONS:",line)

		while fuckyoumatch := re.search(r"""\[["']([^\]]*?)<<(.*?)>>(.*?)["']\]""",line):
			index = f'${fuckyoumatch.group(2)}'
			#left = ''
			if fuckyoumatch.group(1):
				index = f"'{fuckyoumatch.group(1)}'+" + index
			#right = ''
			if fuckyoumatch.group(3):
				index = index + f"+'{fuckyoumatch.group(3)}'"
			#	right = fuckyoumatch.group(3)

			#index = f"'{left}'+${fuckyoumatch.group(2)}+'{right}'"
			#print(index)
			line = line.replace(fuckyoumatch.group(0),f"[{index}]")
			#print("MATCH")

		pv("AFTER ARRAY []:",line)

		while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*(<<.*?)'\s*\)""",line):
			fullmatch = dynevalmatch.group(0)
			varname = dynevalmatch.group(1)
			varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
			varname = "State.getVar('$"+varname.replace('<<',"'+").replace('>>',"+'")+"')"
			line = line.replace(fullmatch,varname)
			#print(line)

		pv("AFTER DYNEVAL:",line)

		while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*\$?(.*?)'\s*\)""",line):
			fullmatch = dynevalmatch.group(0)
			varname = "$"+dynevalmatch.group(1)
			varname = varname.replace('<<',"'+").replace('>>',"+'")
			#varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
			varname = varname.replace("['+","[").replace(r"+']",r"]")

			varname = varname.replace('$$',"$")
			line = line.replace(fullmatch,varname)

		pv("AFTER DYNEVAL2:",line)

		if line.startswith('!{') or line.startswith('!!{') or line == '!!{':
			line_output = '<!-- ' + line
			if line.endswith('}'):
				line_output += ' -->'
			else:
				commenting = True
			pv("IS COMMENT:",line_output)
		elif line.endswith('}') and commenting:
			line_output = line+' -->'
			commenting = False
			pv("IS COMMENT:",line_output)
		elif commenting:
			line_output = line.replace('--','-')
			pv("IS COMMENT:",line_output)
		elif line.lower() == 'end' or line.lower().startswith('end &!'):
			whitespace_count -= 1
			if len(nesting) > 0:
				end_command = nesting.pop()
				if end_command == 'if':
					#file.write('<</if>>\n')
					line_output = '<</if>>'
				elif end_command == 'while':
					#file.write('<</while>>\n')
					line_output = '<</while>>'
				elif end_command == 'act':
					#file.write('<</act>>\n')
					line_output = '<</act>>'
				else:
					print(f'ERROR: UNKNOWN NESTRING: {end_command}')
			else:
				line_output = '<</END>>'
			pv("IS END:",line_output)
		elif line.startswith('!'):
			line_output = '<!-- ' + line + '-->'
			pv("IS COMMENT:",line_output)
		elif line.lower() == 'else':
			#file.write('<<else>>\n')
			line_output = '<<else>>'
			whitespace_count -= 1
			pv("IS ELSE:",line_output)
		elif line.lower() == 'cls':
			line_output = ''
			pv("IS CLS:",line_output)
		elif line.lower() == '*nl':
			#file.write('\n')
			line_output = ''
			pv("IS NL:",line_output)
		elif line[0:3] == '---':
			line_output = ''
			pv("IS EOF:",line_output)
		elif match := re.match(r"^\s*msg\s*'(.*)'\s*$",line,re.I):
			msg = match.group(1).replace("'",'"')
			line_output = f"""<<msg '{msg}'>>"""
			pv("IS MSG:",line_output)


		elif match := re.match(r"""act\s*'(.*?)\s*\(<font color="red"><<will_cost>> Willpower</font>\)':\s*'<br><font color="red">You don''t have enough willpower to use this action.</font>'""",line,re.I):
			label = match.group(1).replace("'",'"')
			line_output = f"<<act `'{label} ('+$will_cost+')'`>><font color=red><br/>You don`t have enough willpower to use this action.</font><</act>>"
		elif match := re.match(r"""^'(?:<center>)?<img\s+(?:<<\$?\w+>>\s+)src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/center>)?'""",line,re.I):
			#Images
			if match.group(2):
				line_output = f'''<<image "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
			else:
				line_output = f'''<<image "{match.group(1)}{match.group(3)}">>'''
			pv("IS IMAGE:",line_output)
		elif match := re.match(r"""^'?(?:<center>)?<video\s+(?:<<\$?\w+>>\s+)*(?:\s*autoplay\s*|\s*loop\s*)*src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/video>)?(?:<\/center>)?'?""",line,re.I):
			#Images
			if match.group(2):
				line_output = f'''<<video "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
			else:
				line_output = f'''<<video "{match.group(1)}{match.group(3)}">>'''
			pv("IS VIDEO:",line_output)
		elif line.startswith('<') and line.endswith('>'):
			line_output = line
			pv("IS HTML:",line_output)
		elif line.startswith("'<") and line.endswith(">'"):
			line_output = line[1:-1]
			pv("IS COMMENTED HTML:",line_output)
		elif match := re.match(r"""^'[\w<>\s=:'"\/\.\(\),\*]+'$""",line):
			#Plain HTML
			line_output = line[1:-1]
			if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",line_output):
				#line_output = #line_output.replace(link_match[0],"moep")
				#print("moep")
				#print(link_match)
				for lmatch in link_match:
					line_output = line_output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
			pv("IS PLAIN HTML:",line_output)
		elif match := re.match(r"^\s*(if|while)\s+([^:]+):(.*)",line,re.I):
			command = match.group(1).lower()
			line_w = f'<<{command} {convert_condition(match.group(2))}>>'
			if match.group(3):
				#if com := convert_command(match.group(3)):
				#	line_w += '\n' + (whitespace_count+1) * '\t' + com
				#else:
				#	line_w += '\n' + (whitespace_count+1) * '\t' + convert_literal(match.group(3))
				converted = convert_lineblock([match.group(3)])
				if len(converted)>0 and converted[0]:
					line_w += '\n' + (whitespace_count+1) * '\t' + converted[0]
				line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
			else:
				nesting.append(command)
			#file.write(line_w)
			line_output = line_w
			pv("IS IF:",line_output)
		elif match := re.match(r"\s*(act)\s*(.+):(.*)",line,re.I):
			# Act-Command
			command = match.group(1).lower()

			line_w = f'<<{command} {convert_literal(match.group(2))}>>'
			if match.group(3):
				line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
				line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
			else:
				nesting.append(command)
			#file.write(line_w)
			line_output = line_w
			pv("IS ACT:",line_output)
		elif match := re.match(r"\s*(elseif)\s+([^:]+):(.*)",line,re.I):
			# ElseIf
			command = match.group(1).lower()
			line_w = f'<<{command} {convert_condition(match.group(2))}>>'
			whitespace_count -= 1
			if match.group(3):
				#line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
				line_w += '\n' + whitespace_count * '\t'+f'<</if>>'
				#nesting.pop()
			#file.write(line_w)
			line_output = line_w
			pv("IS ELSEIF:",line_output)
		#elif match := re.match(r"^dynamic\s+'(.*)'$",line,re.I):
		#	out = match.group(1).replace('<<',"'+").replace('>>',"+'")
		#	line_output = f"<<dynamic {out}>>"
		elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
			left = match.group(1)
			right = match.group(3)
			operator = match.group(2)

			left = left.replace(r"[''",r"['").replace(r"'']",r"']")
			left = left.replace(r"['+",r"[").replace(r"+']",r"]")
			left = left.replace('<<',"'+").replace('>>',"+'")
			left = left.replace('$$',"$")

			right = right.replace(r"[''",r"['").replace(r"'']",r"']")
			right = right.replace(r"['+",r"[").replace(r"+']",r"]")
			right = right.replace('<<',"").replace('>>',"")
			right = right.replace('$$',"$")
			right = convert_literal(right)

			line_output = f'<<set {left} {operator} {right}>>'
			pv("IS DYNAMIC:",line_output)
		#elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
		elif match := re.match(r"^dynamic\s*\$([a-zA-Z]\w+)$",line,re.I):
			line_output = f'<<{match.group(1)}>>'
		elif match := re.match(r"""^([^\$])*<a\s+href\s*=\s*"exec:\s*(?:minut\s*\+=\s*(\d+)\s*&\s*)?gt(.*)?"\s*>(.*?)</a>.*$""",line,re.I):
			while link_match := re.search(r"""<a\s+href\s*=\s*"exec:\s*(?:minut\s*\+=\s*(\d+)\s*&\s*)?gt(.*)?"\s*>(.*?)</a>""",line,re.I):
				full_match = link_match.group(0)
				time = ""
				if link_match.group(1):
					time = f"<<set $minut += {link_match.group(1)}>>"
				goto = link_match.group(2)
				goto = goto.replace(","," ").replace(r"''",r"'")
				label = link_match.group(3)
				link = f"<<link '{label}'>>{time}<<gt {goto}>><</link>>"
				line = line.replace(full_match,link)
			line_output = line
		elif match := convert_command(line):
			line_output = match
			pv("IS COMMAND:",line_output)
		else:
			line_output = convert_literal(line)
			if len(line_output) >= 2 and line_output[0] == '\'' and line_output[-1] == '\'':
				line_output = f'<p>{line_output[1:-1]}</p>'
				pv("IS LITERAL:",line_output)

		whitespace = whitespace_count * '\t'
		output = f'{whitespace}{line_output}\n'
		if output.strip():
			#file.write(cleanUpTheMess(output))
			output = cleanUpTheMess(output)
			if "ERROR:" in output:
				global error_counter
				output = f'{whitespace}<!-- FAILED TO CONVERT\n{whitespace}\t{original}\n{whitespace}-----\n\t{output}\n{whitespace}-->\n{whitespace}<<warn "CONVERSION ERROR {(hashlib.md5(original.encode())).hexdigest()}">>\n'
				error_counter += 1
			outputs.append(output)

	for subpassId in subpassages:
		subpass = subpassages[subpassId]
		subpassageLines = convert_lineblock(subpass)
		outputs.append(f'\n:: {subpassId}\n')
		for subpassageLine in subpassageLines:
			outputs.append(subpassageLine)

	if len(functionlines) > 0:
			#outputs.append(f'::{location_identifier}_widgets[widget]\n')
			for functionline in functionlines:
				functionline = functionline.replace('$ARGS','_args').replace('$location_var[$here][','_args[')
				outputs.append(functionline)

	return outputs



def convert_file(filename,skipIfNotExplicit=0,defaultsubfolder=False):
	skip = skipIfNotExplicit
	qsp_filename = filename+".qsrc"
	qsp_filepath = os.path.join(qsp_sources_path,qsp_filename)

	tw_filename = filename+".tw"
	tw_filepath = os.path.join(tw_sources_path,tw_filename)

	if defaultsubfolder:
		os.makedirs(os.path.join(tw_sources_path,defaultsubfolder),exist_ok =True)
		tw_filepath = os.path.join(tw_sources_path,defaultsubfolder,tw_filename)

	try:
		with open(qsp_filepath) as file:
			lines = [line.rstrip() for line in file]
	except:
		try:
			with open(qsp_filepath, encoding="utf-8") as file:
				lines = [line.rstrip() for line in file]
		except:
			return f"FAILED: {qsp_filename}"


	location_identifier = ''

	ignore_recusions = 0

	if match := re.match(r"^\s*!!\s*(FOLDER\s*:\s*\w+)?\s*(SKIP\s*:\s*-?\d)?\s*(IGNORERECURSIONS\s*:\s*-?\d)?\s*$",lines[0],re.I):
		if match.group(1):
			parts = match.group(1).split(':')
			new_path = os.path.join(tw_sources_path,parts[1].strip())
			os.makedirs(new_path,exist_ok =True)
			tw_filepath = os.path.join(new_path,tw_filename)
		if match.group(2):
			parts = match.group(2).split(':')
			arg = int(parts[1])
			if arg == 1:
				skip = 1
			elif arg == 0:
				skip = 0
			elif arg == -1:
				skip = -1
		if match.group(3):
			parts = match.group(3).split(':')
			arg = int(parts[1])
			if arg == 1:
				ignore_recusions = 1
			elif arg == 0:
				ignore_recusions = 0


	if skip == 1:
		return

	if skip == -1 and os.path.exists(tw_filepath):
		modification_time_delta = os.path.getmtime(qsp_filepath) - os.path.getmtime(tw_filepath)
		if modification_time_delta <= 0:
			return

	identifier_line = 0
	for line_num in range(0,len(lines)-1):
		line_raw = lines[line_num]
		line = line_raw.strip()
		match = re.match(r"#\s*(\S+)", line)
		if match:
			location_identifier = match.group(1)
			identifier_line = line_num
			break

	with open(tw_filepath, 'w') as file:
		#file.write(f'<!-- GENERATED: {datetime.datetime.now()} -->\n')
		file.write(f':: {location_identifier}\n')
		file.write(f"<<set $here = '{location_identifier}'>>\n<<set $ARGS = $location_var[$here]>>\n")

		if ignore_recusions == 1:
			file.write(f'<<set _ts to Math.floor(Date.now() / 10000)>>\n')
			file.write(f'<<setinit $gt_history[_ts][$here] = 0>>\n')





		#for line_num in range(identifier_line+1,len(lines)-1):
		outputs = convert_lineblock(lines[identifier_line+1:],location_identifier)

		for output in outputs:
			file.write(output)

	with open(tw_filepath, 'r') as file:
		data = file.read()

	with open(tw_filepath, 'w') as file:
		regex1 = r"""<<gs 'willpower' ([\s'\w]*)>>\s*<<if \$will_cost <= \$pc\.willpower>>\s*<<act '([\w\s]*?)\s*\(will_cost Willpower\)'>>"""

		while match := re.search(regex1,data,re.I):
			blockStart = match.end()
			regex_close = r"""<<else>>\s*<<act `?'"""+match.group(2)+r""".*?<</act>>\s*<</if>>"""
			if close_match := re.search(regex_close,data,re.I):
				blockEnd = close_match.start()
				block = data[blockStart:blockEnd]
				# Remove the re-calculation of the willpower-cost
				newBlock = block
				newBlock = newBlock.replace("<<gs 'willpower' "+match.group(1)+">>",'')
				newBlock = re.sub(r"""<<gs 'willpower' 'pay' ([\s'\w]*)>>""","",newBlock)
				data = data.replace(block,newBlock)

				data = data.replace(close_match.group(0),"")

				arguments = match.group(1).replace(' ',',')
				data = data.replace(match.group(0),"<<act '"+match.group(2)+"' undefined `{willpower:["+arguments+"]}`>>")
			else:
				#print("FAIL: "+match.group(0))
				break

		data = data.replace('<<act ','<<actCLA ')
		data = data.replace('<</act>>','<</actCLA>>')

		file.write(data)

	with open(tw_filepath, 'r') as file:
		data = file.read()
		regex_split = r"""::\s*SPLIT:(\w+)"""
		while match := re.search(regex_split,data,re.I):
			identifier = match.group(1)
			regex_split_end = r"""<!-- END: SPLIT:"""+identifier+r"""\s*-->"""
			if end_match := re.search(regex_split_end,data,re.I):
				sub_filepath = os.path.join(new_path,identifier+'.tw')
				subdata = data[match.start():end_match.end()]
				subdata = subdata.replace("SPLIT:"+identifier,identifier,1)
				with open(sub_filepath, 'w') as subfile:
					subfile.write(subdata)
				data = data[:match.start()]+data[end_match.end():]
				data = data.replace("SPLIT:"+identifier,identifier,1)


	with open(tw_filepath, 'w') as file:
		file.write(data)

	return tw_filepath

FTCL = [r'ERROR: FAILED TO CONVERT LITERAL:\s*"""',r'"""']
VAR = r"""\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)"""

preparations = [
	[
		r"""\$week\[""",
		r"$week_name["
	],
	[
		r"""pcs_pubecol\[""",
		r"pcs_pubecol_num["
	],
	[
		r"""pcs_pubes\[""",
		r"pcs_pubes_num["
	],
	[
		r"""^PLAY\s*.*""",
		r""
	],
	[
		r"""^\s*pl\s+(.*)$""",
		r"\1"
	]
	#[
	#	r"""(</?(?:table|center|th|tr|td))([^>]*=[^>]*)(>)""",
	#	r'\1\3',
	#	re.I
	#]
]

skill_names = [
	[r"\$pcs_heels","highHeels"],
	[r"\$pcs_stren","strength"],
	[r"\$pcs_agil","agility"],
	[r"\$pcs_intel","intelligence"],
	[r"\$pcs_react","reaction"],
	[r"\$pcs_sprt","spirit"],
	[r"\$pcs_chrsm","charisma"],
	[r"\$pcs_prcptn","perception"],
	[r"\$pcs_humint","people"],
	[r"\$pcs_persuas","persuasion"],
	[r"\$pcs_observ","observation"],
	[r"\$pcs_jab","jabs"],
	[r"\$pcs_punch","punch"],
	[r"\$pcs_kick","kick"],
	[r"\$pcs_def","defense"],
	[r"\$pcs_run","run"],
	[r"\$pcs_vball","volleyball"],
	[r"\$pcs_ftbll","football"],
	[r"\$pcs_wrstlng","wrestling"],
	[r"\$pcs_shoot","shoot"],
	[r"\$pcs_bushcraft","bushcraft"],
	[r"\$pcs_chess","chess"],
	[r"\$pcs_icesktng","iceskating"],
	[r"\$pcs_gaming","gaming"],
	[r"\$pcs_makupskl","makeup"],
	[r"\$pcs_danc","dance"],
	[r"\$pcs_dancero","eroticdance"],
	[r"\$pcs_dancpol","poledance"],
	[r"\$pcs_cheer","cheerleading"],
	[r"\$pcs_mdlng","modelling"],
	[r"\$pcs_vokal","singing"],
	[r"\$pcs_instrmusic","playInstrument"],
	[r"\$pcs_photoskl","photo"],
	[r"\$pcs_artskls","art"],
	[r"\$pcs_compskl","computer"],
	[r"\$pcs_comphckng","hacking"],
	[r"\$pcs_hndiwrk","handyWork"],
	[r"\$pcs_sewng","sewing"],
	[r"\$pcs_servng","serving"],
	[r"\$pcs_medcn","medicine"],

]

replaces = [
	[
		r"ERROR: FAILED TO CONVERT CONDITION: func\(",
		r"func("
	],
	[
		r"ERROR: FAILED TO CONVERT CONDITION: \$?([a-zA-Z])",
		r"$\1"
	],
	[
		FTCL[0]+r"killvar\s*'"+VAR+r"'"+FTCL[1],
		r"<<set $\1 to undefined>>"
	],
	[
		r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"\)\(),\s]+]*)>>)?(\.[^"]+)">""",
		r"<<image `'\2\3\5'`>>"
	],
	[
		r"""'([\w\/]+)<<\s*rand\s*\(\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)\s*>>([^']*)'""",
		r"""'\1'+rand(\2,\3)+'\4'"""
	],
	[
		r"""<<set \$?([a-zA-Z][a-zA-Z0-9-_'"]+]*\[.*)>>""",
		r"""<<setinit $\1>>"""
	],
	[
		# <<set $gopnikbandQW += -1>> -> <<setn $gopnikbandQW += -1>>
		r"""<<set (\$[^>]*?)\s([+-]=)\s*(-?\d+)>>""",
		r"""<<setn \1 \2 \3>>""",
		1
	],
	[
		# asd
		r"""<<set (\$[^>]*?)\s(\+=)\s*(["'][^>]*?)>>""",
		r"""<<sets \1 \2 \3>>""",
		1
	],
	[
		r"""(\+)\s+=""",
		r"""\1="""
	],
	[
		r"(I|you|You|he|He|she|She|it|It|we|We|they|They|can|Can|don|Don)''(m|re|s|ll|ve|t)",
		r"\1'\2"
	],
	#[
	#	r"^(.*"+FTCL[0]+r"(.*)"+FTCL[1]+r".*)$",
	#	r"<!-- \1 -->\n<<warn 'FTCL: \1'>>"
	#],
	[
		r"=\s*\$(mid|MID)\s*\(",
		r"= mid("
	],
	[
		r"(<<set\s*.*?\[)([a-zA-Z].*?)(\]\s*=.*>>)",
		r"\1$\2\3"
	],
	[
		r"(<<act\s*'.*)(\$.*?\])(.*'>>)",
		r"\1'+\2+'\3"
	],
	[
		r"\[([a-zA-Z]\w*)\]",
		r"[$\1]"
	],
	[
		r"([\+\-])\s+=",
		r"\1="
	],
	[
		r"<<setinit\s*(.*)\[\]\s*=\s*(.*)>>",
		r"""<<setinitpush "\1" \2>>"""
	],
	[
		r"\s+min\(",
		r" Math.min("
	],
	[
		r"\s+max\(",
		r" Math.max("
	],
	[
		r"""<<set (.*) to null>>\s*,\s*(.*)(\s*)""",
		r"<<set \1[\2] to null>>\3"
	]
	,
	[
		r"""\$arrsize\(""",
		r"arrsize("
	],
	[
		r"""<<set(?:init)?\s+\$?(?P<name>\w+)\[arrsize\('\$?(?P=name)'\)\]\s*=\s*(.*)\s*>>""",
		r"<<run $\1.push(\2)>>"
	],
	[
		r"""<center><(?:h\d|b)><font color="maroon">(.*)</font></(?:h\d|b)></center>""",
		r"<h2>\1</h2>"
	],


	[
		r"""(<<act '[^']*)'([^']*'>>)""",
		r"\1`\2"
	],
	# NPC-Stuff Start
	[
		r"""\$npc_(\w*?)\[([^\]]*?)\]""",
		r"$npcs.get(\2,'\1')",
		1
	],
	# Fix for Sub-Arrays
	[
		r"""\$npcs\.get\((.*?),('\w*')\)(\[[^\]]*\]+?)\]""",
		r"$npcs.get(\1]\3,\2)",
		1
	],
	[
		r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*=\s*(.*?)>>""",
		r"<<run $npcs.set(\1,\2)>>",
		1
	],
	[
		r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*\+=\s*(.*?)>>""",
		r"<<run $npcs.inc(\1,\2)>>",
		1
	],
	[
		r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*-=\s*(.*?)>>""",
		r"<<run $npcs.dec(\1,\2)>>",
		1
	],
	# NPC-Stuff END
	[
		r"""(\$\w+(?:\['\w+'\])?)\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
		r"""getvar("\1") \2 \3""",
		1
	],
	[
		#Example: $property_construction_status[$i] == 0 -> getvar("$property_construction_status["+$i+"]") == 0
		r"""(\$\w+)(?:\[(\$\w+)\])\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
		r"""getvar("\1["+\2+"]") \3 \4""",
		1
	],
	[
		r"""\*?\s*\$\s*cl[ar]\s*$""",
		r""
	],
	[
		r"""<<gs 'clothing' 'wear'\s*(.*?)\s+(.*?)>>""",
		r"<<run $wardrobe.wear_clothes_legacy('clothes',\1,\2)>>"
	],
	[
		r"""<<gs 'shoes' 'wear'\s+(.*?)\s+(.*?)>>""",
		r"<<run $wardrobe.wear('shoes',\1,\2)>>"
	],
	[
		r"""<<gs\s+'shoes'\s+'wear'\s+'last_worn'\s*>>""",
		r"<<run $wardrobe.wear_last('shoes')>>"
	],
	[
		r"""<<gs\s+'bras'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
		r"<<run $wardrobe.wear('bra',\1,\2)>>"
	],
	[
		r"""<<gs\s+'panties'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
		r"<<run $wardrobe.wear('panties',\1,\2)>>"
	],
	[
		r"""<<gs\s+'coats'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
		r"<<run $wardrobe.wear('coat',\1,\2)>>"
	],
	[
		r"""<<gs\s+'bras'\s+'wear'\s*>>""",
		r"<<run $wardrobe.wear_last('bra')>>"
	],
	[
		r"""<<gs\s+'panties'\s+'wear'\s*>>""",
		r"<<run $wardrobe.wear_last('panties')>>"
	],
	[
		r"""iif\(([^)]*?)\s*==?\s*'',""",
		r"iif(!\1,",
		1
	],
	# Rand in gs Fix
	[
		r"""<<g([st].*?)\srand\((.*?)\)(.*?)>>""",
		r"<<g\1 `rand(\2)`\3>>",
		1
	],
	# Pain
	[
		r"""(<<(?:else)?if\s+|and\s+|x?or\s+)(?:getvar\(")\$pain\[('\w+')\](?:"\))(.*?>>)""",
		r"\1$pc.pain(\2)\3",
		1
	],
	[
		r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*\+=\s*(.*?)>>""",
		r"<<run $pc.painInc(\1,\2)>>",
		1
	],
	[
		r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*-=\s*(.*?)>>""",
		r"<<run $pc.painDec(\1,\2)>>",
		1
	],
	[
		r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*=\s*(.*?)>>""",
		r"<<run $pc.painSet(\1,\2)>>",
		1
	],
	#Cum
	[
		r"""\$cumloc\[(\d+)\]""",
		r"$pc.cumAtLocation(\1)",
		1
	],
	# Inner Thought
	[
		r"""(?:'?\s*\+\s*)?\$OpenInnerThought\s*\+\s*'(.*?)'\s*\+\s*\$CloseInnerThought(?:\s*\+\s*'?)?""",
		r"""<span class="innerThought">\1</span>""",
		1
	],
	# Group Membership
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*1',r"$q.school.func('isGroupMember','cool')",1],
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*2',r"$q.school.func('isGroupMember','jocks')",1],
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*3',r"$q.school.func('isGroupMember','nerds')",1],
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*4',r"$q.school.func('isGroupMember','gopniks')",1],
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*5',r"$q.school.func('isGroupMember','outcasts')",1],
	[r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*6',r"$q.school.func('isGroupMember','teachers')",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*1>>',r"<<run $q.school.func('setGroupMembership','cool')>>",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*2>>',r"<<run $q.school.func('setGroupMembership','jocks')>>",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*3>>',r"<<run $q.school.func('setGroupMembership','nerds')>>",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*4>>',r"<<run $q.school.func('setGroupMembership','gopniks')>>",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*5>>',r"<<run $q.school.func('setGroupMembership','outcasts')>>",1],
	[r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*6>>',r"<<run $q.school.func('setGroupMembership','teachers')>>",1],
]

purge_messes=[
	r"""<<set(init)? \$npc_selfie\[""",
	r'''<<set(init)? \$npcGo\[''', # We need to replace this by another function,
	r'''<<set(init)? \$npcGoSchool\['''
]



def cleanUpTheMess(output):
	for purge_mess in purge_messes:
		if match := re.search(purge_mess,output):
			return ''

	for skill_name in skill_names:
		oldSN = skill_name[0]
		newSN = skill_name[1]
		oldSN_without_prefix = oldSN.split('_')[1]
		output = re.sub(r"<<set(?:init)?\s+"+oldSN+r"\s*=\s*(.*?)\s*>>",r"<<run $pc.skillSetLevel('"+newSN+r"',\1)>>",output)
		output = re.sub(r"<<gs\s+'exp_gain'\s+('"+oldSN_without_prefix+r"')\s+`?(.*?)`?>>",r"<<run $pc.skillExperienceGain('"+newSN+r"',\2)>>",output)
		output = re.sub(oldSN,'$pc.skillLevel("'+newSN+'")',output)

	for replace in replaces:
		if len(replace) > 2:
			if replace[2] == 1:
				while(re.search(replace[0],output)):
					output = re.sub(replace[0],replace[1],output)
		else:
			output = re.sub(replace[0],replace[1],output)

	if warnmatch := re.search(r"""<<warn '(.*)'>>""",output):
		return output.replace(warnmatch.group(1),warnmatch.group(1).replace("'",'"'))

	if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",output):
		for lmatch in link_match:
			output = output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")

	output = re.sub(r"""\$result""","$result",output,0,re.I)

	while image_match := re.match(r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)>>)?\.[^"]+">""",output):
		if len(image_match.group(3)) == 0:
			break
		output = output.replace(image_match.group(3),f'"+${image_match.group(4)}+"')

	while match := re.search(r"""<<set(?:init)?[^=]+=\s*'([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+)('([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+))+'>>""",output):
		output = output.replace(match.group(2),f"`{match.group(3)}")

	# NPCs: add print to all get-calls which are not inside a macro
	if(not output.strip().startswith('<<')):
		output = re.sub(r"(?<!=)(\$npcs\.get\(.*?\))",r"<<=\1>>",output)

	# Arousal
	while match := re.search(r"<<gs 'arousal' '(\w+)' (.*?)(\s.*?)?>>",output):
		if match.group(3):
			arguments = "`["+match.group(3).replace("' '","','").strip()+"]`"
		else:
			arguments = ''
		output = output.replace(match.group(0),"<<arouse '"+match.group(1)+"' "+match.group(2)+" "+arguments+">>")


	for variable_replacement in variables.variable_replacements:
		if len(variable_replacement) > 2:
			if variable_replacement[2] == 1:
				output = re.sub(variable_replacement[0],variable_replacement[1],output)
			else:
				output = output.replace(variable_replacement[0],variable_replacement[1])
		else:
			output = output.replace(variable_replacement[0],variable_replacement[1])
			output = output.replace('getvar("'+variable_replacement[1]+'")',variable_replacement[1])

	# Inventory-Vars
	for inventory_variable in variables.inventory_variables:
		output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*=\s*(.*?)\s*>>",rf"<<run $inventory.set('{inventory_variable[1]}',\1)>>",output)
		output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*-=\s*(.*?)\s*>>",rf"<<run $inventory.dec('{inventory_variable[1]}',\1)>>",output)
		output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run $inventory.inc('{inventory_variable[1]}',\1)>>",output)
		output = re.sub(rf"<<{inventory_variable[0]}>>",rf"""$inventory.get("{inventory_variable[1]}")""",output)
		output = re.sub(rf"""getvar\("\${inventory_variable[0]}"\)""",rf"""$inventory.get("{inventory_variable[1]}")""",output)
		output = re.sub(rf"""\${inventory_variable[0]}([^\w])""",rf"""$inventory.get("{inventory_variable[1]}")\1""",output)

	# Get Set Variables
	for get_set_variable in variables.get_set_variables:
		output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*=\s*(.*?)\s*>>",rf"<<run {get_set_variable[2]}>>",output)
		if(len(get_set_variable) == 5):
			output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run {get_set_variable[3]}>>",output)
			output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*\-=\s*(.*?)\s*>>",rf"<<run {get_set_variable[4]}>>",output)
		#output = re.sub(rf"<<set(?:init)?\s+\${get_set_variable[0]}\s*-=\s*(.*?)\s*>>",rf"<<run $inventory.dec('{inventory_variable[1]}',\1)>>",output)
		#output = re.sub(rf"<<set(?:init)?\s+\${get_set_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run $inventory.inc('{inventory_variable[1]}',\1)>>",output)
		output = re.sub(rf"<<{get_set_variable[0]}>>",get_set_variable[1],output)
		output = re.sub(rf"""getvar\("{get_set_variable[0]}"\)""",get_set_variable[1],output)
		output = re.sub(rf"""{get_set_variable[0]}(?P<stuffToTheRight>[^\w])""",rf"""{get_set_variable[1]}\g<stuffToTheRight>""",output)

	for pgsvr in  variables.post_get_set_variables_replacements:
		output = output.replace(pgsvr[0],pgsvr[1])

	output = output.replace("$location_var[$here][0] == ''","!$location_var[$here][0]")

	return output

def testConvertLine(line):
	test_line = ''
	#test_line = """gs 'npc_relationship', 'socialgroup_setting', 0, 0, -10, 10, -10, -10"""

	if len(test_line) > 0:
		verbose = True
		print(test_line)
		result = convert_lineblock([test_line])
		if len(result) > 0:
			print(result[0])
		else:
			print("EMPTY RESULT")
		exit()

def convertFiles(restrictfiles=[]):
	#output_files = []

	os.makedirs(tw_sources_path, exist_ok=True)

	#for replace in replaces:
	#	print(replace[0])

	#restrictfiles = []
	#restrictfiles = ['gschool_gopnik_chats']
	restrictfilesRegex = [r'.*_attributes.*']
	targetFolder = 'outfits'


	files  = os.listdir(qsp_sources_path)
	file_counter = 0
	last_displayed_percentage_time = time.time()

	filesToDo = []

	for file in files:
		regexMatched = False
		for fileRegex in restrictfilesRegex:
			if re.match(fileRegex,file):
				regexMatched = True
		if (len(restrictfiles) == 0 and len(restrictfilesRegex) == 0) or (os.path.splitext(file)[0] in restrictfiles) or regexMatched:
			if file.endswith(".qsrc"):
				filesToDo.append(os.path.splitext(file)[0])
				#output_files.append(convert_file(os.path.splitext(file)[0],skipMode,'unsorted'))


	with ThreadPoolExecutor(32) as executor:
		# submit all tasks
		futures = [executor.submit(convert_file, p, skipMode, targetFolder) for p in filesToDo]
		# process all results
		for future in as_completed(futures):
			# open the file and load the data
			completedPath = future.result()
			# report progress
			#print(f'.loaded {filepath}')


			file_counter += 1
			if(last_displayed_percentage_time + 5 < time.time()):
				print(str(round(file_counter/len(files)*100, 2))+"%")
				last_displayed_percentage_time = time.time()



	#for output_file in output_files:
	#	for line in fileinput.input(output_file, inplace=True):
	#
	#		for function_name_conversion in function_name_conversions:
	#
	#
	#		if fileinput.filelineno() == 10:
	#			print(('10'+line), end='')
	#	break
if __name__ == "__main__":
	convertFiles()
