# -*- coding: utf-8 -*-

from __future__ import print_function
import os
import re
import sys
import json
import datetime
import shutil
import subprocess
import time
import signal
import zipfile
from multiprocessing import Process, Queue
from functools import wraps
from threading import Timer
import platform
import gettext
import yaml
from . import base
from .base import log, pjoin, tmp_path
try:
	import jinja2
except:
	pass
from . import tools
import uuid
import traceback

work_class = {
	'noi' : {'noi'},
	'ccpc' : {'ccpc'},
	'uoj' : {'uoj'},
	'loj' : {'loj'},
	'ipuoj' : {'ipuoj'},
	'tupc' : {'tupc'},
	'tuoj-pc' : {'tupc', 'tuoj'},
	'tuoi' : {'tuoi'},
	'tuoj-oi' : {'tuoi', 'tuoj'},
	'tuoj' : {'tuoj'},
	'thuoj' : {'thuoj'},
	'hand' : {'hand'},
	'ccc' : {'ccc-tex', 'ccc-md'},
	'ccc-tex' : {'ccc-tex'},
	'ccc-md' : {'ccc-md'},
	'tsinsen-oj' : {'tsinsen-oj'},
	'tex' : {'noi', 'ccpc', 'tupc', 'tuoi', 'ccc-tex', 'hand'},
	'md' : {'uoj', 'tuoj', 'ccc-md', 'loj', 'ipuoj'},
	'html' : {'tsinsen-oj'},
	'doku' : {'thuoj'},
	'syzoj_like' : {'loj', 'ipuoj'}
}
io_styles = {
	'noi' : 'fio',
	'ccpc' : 'stdio',
	'uoj' : 'stdio',
	'tuoj' : 'stdio',
	'ccc' : 'stdio',
	'tuoi' : 'stdio',
	'tupc' : 'stdio',
	'tsinsen-oj' : 'stdio',
	'loj' : 'stdio',
	'ipuoj' : 'stdio',
	'thuoj' : 'stdio',
	'hand' : 'stdio'
}
base_templates = {
	'noi' : 'tuoi',
	'tuoi' : 'tuoi',
	'tupc' : 'tupc',
	'ccpc' : 'ccpc',
	'ccc' : 'ccc',
	'hand' : 'hand'
}

secondary_dict = {}
env = None
pandoc_version = None

def detect_pandoc_version():
	global pandoc_version
	if pandoc_version is not None:
		return
	cp = subprocess.Popen(['pandoc', '-v'], stdout = subprocess.PIPE)
	line = cp.stdout.read().decode("utf-8", "ignore").splitlines()[0]
	pandoc_version = tuple(map(int, line.split()[-1].split('.')))

def get_pandoc_option():
	detect_pandoc_version()
	if pandoc_version >= (2, ):
		option = '--listings -f markdown-smart -t latex-smart'
	else:
		option = '--no-tex-ligatures --listings -t latex'
	return option

def get_template(fname, lang = None):
	global env
	if base.lang:
		lang = base.lang
	if not lang:
		lang = 'zh-cn'
	if env == None or base.system == 'Darwin' or (lang and env['lang'] != lang):
		env = {
			'env' : jinja2.Environment(
				loader = jinja2.FileSystemLoader(tmp_path),
				extensions = ['jinja2.ext.do', 'jinja2.ext.i18n']
			),
			'lang' : lang
		}
		try:
			tra = gettext.translation('lang', tmp_path, [env['lang']])
			env['env'].install_gettext_translations(tra)
		except FileNotFoundError as e:
			log.warning(u'没有%s这种语言的翻译表可用。' % lang)
	return env['env'].get_template(fname)

def table(path, name, temp, context, options):
	if options == None:
		options = {}
	for suf in ['.py', '.pyinc', '.json', '.yaml', '.yml']:
		try:
			base.copy(path, name + suf, pjoin(tmp_path, 'table' + suf))
			log.info(u'渲染表格`%s`，参数%s' % (base.pjoin(path, name + suf), str(options)))
			break
		except base.NoFileException as e:
			pass
	else:
		raise base.NoFileException(u'找不到表格`%s.*`' % base.pjoin(path, name))
	def merge_ver(table, titled = None):
		if titled is not None:
			options['titled'] = titled
		return table
	def merge(table):
		titled = options.get('titled', True)
		ret = [row for row in table]
		last = ret[-1]
		for i in range(len(table) - 2, -1, -1):
			for j in range(len(last)):
				cur = ret[i][j]
				if type(cur) == tuple:
					cur = cur[0]
				las = last[j]
				if type(las) == tuple:
					las, opt = las
				else:
					opt = {}
				last[j] = las
				if (not titled or i != 0) and las == cur and not opt.get('no_merge') and options.get('merge') != False:
					last[j] = None
				if (opt.get('no_merge') or options.get('merge') == False) and context.get('comp') in work_class['syzoj_like']:
					last[j] = str(las) + f"<!--{ uuid.uuid4() }-->"
			last = ret[i]
		if len(table) > 0:
			for j in range(len(table[0])):
				if type(table[0][j]) == tuple:
					table[0][j] = table[0][j][0]
		if titled and len(table) > 1:
			for j in range(len(table[1])):
				if type(table[1][j]) == tuple:
					table[1][j] = table[1][j][0]
		return ret
	if suf == '.json':
		res = get_template('table.json', context['prob'].lang()).render(context, options = options)
		try:
			table = json.loads(res)
		except Exception as e:
			open(pjoin(tmp_path, 'table.tmp.json'), 'w').write(res)
			log.error(u'json文件错误`tmp/table.tmp.json`')
			raise e
		os.remove(pjoin(tmp_path, 'table.json'))
	elif suf == '.yaml' or suf == '.yml':
		try:
			table = yaml.full_load(open(base.pjoin(tmp_path, 'table' + suf), 'rb').read().decode('utf-8'))
		except Exception as e:
			open(pjoin(tmp_path, 'table.tmp.json'), 'w').write(res)
			log.error(u'json文件错误`tmp/table.tmp.json`')
			raise e
	elif suf == '.py' or suf == '.pyinc':
		no_merge = lambda item : (item, {'no_merge' : True})
		code = 'def render(context, options, merge_ver, no_merge):\n'
		code += '\tglobal val\n'
		code += '\tfor key, val in context.items():\n'
		code += '\t\texec(\'%s = val\' % key, globals())\n'
		for line in open(base.pjoin(tmp_path, 'table' + suf), 'rb'):
			code += '\t' + line.decode('utf-8').rstrip() + '\n'
		namespace = {}
		exec(code, namespace)
		try:
			table = namespace['render'](context, options, merge_ver, no_merge)
		except Exception as e:
			log.error(e)
			lines = traceback.format_exc().splitlines()
			for idx, line in enumerate(lines):
				if '<string>' in line:
					m = re.match(r'^.*line (\d*),.*$', line)
					if m:
						lineno = int(m.group(1)) - 4
						log.info('  File "%s", line %d' % (base.pjoin(path, name + suf), lineno))
						log.info(code.splitlines()[lineno + 3][1:])
						for i in range(idx + 1, len(lines)):
							log.info(lines[i])
						break
			else:
				raise e
			raise e
	table = merge(table)
	table = json.loads(json.dumps(table))
	if context.get('comp') in work_class['syzoj_like'] and len(table) > 0:
		last_line = [None] * len(table[0])
		for i in range(len(table)):
			for j in range(len(table[i])):
				if table[i][j] == None:
					table[i][j] = last_line[j]
				else:
					last_line[j] = table[i][j]
	cnt = [[1] * len(row) for row in table]
	max_len = len(table[-1])
	for i in range(len(table) - 2, -1, -1):
		max_len = max(max_len, len(table[i]))
		for j in range(min(len(table[i]), len(table[i + 1]))):
			if table[i + 1][j] == None:
				cnt[i][j] += cnt[i + 1][j]
	ret = get_template(temp, context['prob'].lang()).render(context, table = table, cnt = cnt, width = max_len, options = options)
	return ret

def to_arg(dic):
	return ','.join(['%s = %s' % (key, val if type(val) != str else json.dumps(val)) for key, val in dic.items()])

def uoj_title(text):	## 很显然，这个是在瞎整，不过UOJ为什么从二级标题开始用？修改标题字体大小应该改CSS而不是题目嘛
	in_quote = 0
	result = []
	for line in text.split(b'\n'):
		if in_quote == 0 and line.startswith(b'#'):
			result.append(b'#' + line)
		else:
			result.append(line)
		in_quote ^= line.count(b'```') & 1
	return b'\n'.join(result)
	
def loj_bug(text):		## 学弟也学着我瞎整，伤心QAQ
	# TODO: Avoid duplication
	in_quote = 0
	result = []
	for line in text.split(b'\n'):
		if in_quote == 0 and line.startswith(b'<table'):
			result.append(line
				.replace(b'$<', b'$ <')   # LOJ Markdown 渲染的已知 bug
			)
		else:
			result.append(line)
		in_quote ^= line.count(b'```') & 1
	return b'\n'.join(result)

class Base(object):
	def __init__(self, comp, conf = None):
		self.conf = (base.conf if conf == None else conf)
		self.comp = comp
		self.day = None
		self.contest = None
		self.prob = None
		self.path = None
		self.prec = None
		self.secondary_dict = {}
		self.io_style = io_styles[comp]

	def file_name(self, name):
		if self.comp == 'noi':
			return self.prob['name'] + '/' + name
		elif self.comp == 'uoj':
			return name
		else:
			return name

	def secondary(self, s, sp = None):
		if sp != None:
			if type(sp) == str:
				sp = [sp]
			in_set = False
			for i in sp:
				if i in work_class and base.work in work_class[i]:
					in_set = True
					break
			if not in_set:
				return ''
		if self.work == 'tex' or self.work == 'html' or self.work == 'doku':
			id = str(uuid.uuid4())
			self.secondary_dict[id] = s
			return id
		else:
			return ' {{ ' + s + ' }} '

	def resource(self, name):
		if self.comp in work_class['syzoj_like'] and self.prob.get('pid', {}).get(self.comp + '-default'):
			return '/../problem/show_image/%d/' % self.prob.get('pid', {}).get(self.comp + '-default') + name
		return self.prob['name'] + '/' + name
		
	def down_file(self, name):
		ret = ''
		fname = pjoin(self.prob.path, 'down', name)
		length_warned = False
		for idx, line in enumerate(open(fname, 'rb')):
			if len(line) > 60 and not length_warned:
				log.warning(u'文件`%s`的第%d行太长，建议只提供下发而不渲染到题面。' % (fname, idx + 1))
				length_warned = True
			ret += line.decode('utf-8')
		return ret

	def hide_file(self, name):
		ret = ''
		fname = pjoin(self.prob.path, 'hide', name)
		length_warned = False
		for idx, line in enumerate(open(fname, 'rb')):
			if len(line) > 60 and not length_warned:
				log.warning(u'文件`%s`的第%d行太长，建议只提供下发而不渲染到题面。' % (fname, idx + 1))
				length_warned = True
			ret += line.decode('utf-8')
		if self.comp not in work_class['tex']:
			if ret < 20:
				return u'隐藏内容'
			c = len(ret) // 20
			ret =  ret[:c] + u'……隐藏内容……' + ret[-c:]
		return ret
		
	def titlize(self, title, args, lang = None):
		if base.lang:
			lang = base.lang
		if not lang:
			lang = 'zh-cn'
		if title == 'sample':
			if len(args) > 0:
				self.context['vars']['sample_id'] = args[0]
			if len(args) <= 1:
				return ''
		tra = gettext.translation('lang', tmp_path, [env['lang']])
		ret = tra.gettext(title)
		if len(args) > 0:
			try:
				ret = ret % args
			except Exception as e:
				ret = ret + ''.join(map(str, args))
		elif title == 'sample explanation':
			try:
				ret = ret % (self.context['vars'].get('sample_id', ''), )
			except Exception as e:
				pass
		else:
			try:
				ret = ret % ('',)
			except Exception as e:
				pass
		return '## ' + ret

	def ren_prob_md_j(self):
		time.sleep(0.5)
		log.info(u'渲染题目题面 %s %s' % (self.comp, self.prob.route))
		try:
			shutil.copy(self.prob.statement(), pjoin(tmp_path, 'problem.md.jinja'))
			time.sleep(0.1)
		except base.NoFileException as e:
			log.error(u'找不到题面文件，建议使用`python -m tuack.gen problem`生成题目工程。')
			return
		def to_I(x):
			if not issubclass(type(x), dict) and not issubclass(type(x), list): return
			for key in (x if issubclass(type(x), dict) else range(len(x))):
				if type(x[key]) == int:
					x[key] = tools.Int(x[key])
				elif type(x[key]) == float:
					x[key] = tools.Float(x[key])
				else:
					to_I(x[key])
		to_I(self.prob)
		self.context = {
			'prob' : self.prob,
			'args' : self.prob.get('args'),
			'data' : self.prob.get('data'),
			'samples' : self.prob.get('samples'),
			'pre' : self.prob.get('pre'),
			'dargs' : tools.a(self.prob.get('data')),
			'pargs' : tools.a(self.prob.get('pre')),
			'sargs' : tools.a(self.prob.get('samples')),
			'aargs' : tools.a(self.prob, self.prob.get('data'), self.prob.get('pre'), self.prob.get('samples'), [self.prob]),
			'day' : self.day,
			'contest' : self.contest,
			'io_style' : self.io_style,
			'comp' : self.comp,
			'tools' : tools,
			'tl' : tools,
			'base' : base,
			'common' : base,
			'file_name' : self.file_name,
			'down_file' : self.down_file,
			'resource' : self.resource,
			'render' : self.secondary,
			'precautions' : self.prec,
			'json' : json,
			'vars' : {},
			's' : lambda title, *args : self.titlize(title, args, self.prob.lang()),
			'input_file_name': None,
			'output_file_name': None,
			'work_class' : work_class,
			'noi_pas_c': base.noi_pas_c
		}
		if self.prob.get('file io'):
			self.context['input_file_name'] = self.prob.get('input_table', {}).get('zh-cn', self.prob['name'] + '.in')
			self.context['output_file_name'] = self.prob.get('output_table', {}).get('zh-cn', self.prob['name'] + '.out')
		self.context['img'] = lambda src, env = None, **argw : self.context['render'](
			"template('image', resource = resource(%s), %s)" % (json.dumps(src), to_arg(argw)),
			env
		)
		self.context['font'] = lambda txt, env = None, **argw : self.context['render'](
			"template('font', txt = %s, %s)" % (json.dumps(txt), to_arg(argw)),
			env
		)
		self.context['tbl'] = lambda src, env = None, **argw : self.context['render'](
			"table(%s, %s)" % (json.dumps(src), argw),
			env
		)
		if self.comp == 'tsinsen-oj' and 'tsinsen_files' in dir(self.prob):
			self.context['resource'] = lambda name : '/RequireFile.do?fid=%s' % self.prob.tsinsen_files[name]
		open(pjoin(tmp_path, 'problem.md'), 'wb') \
			.write(get_template('problem_base.md.jinja', self.prob.lang())
				.render(self.context)
				.encode('utf-8')
			)
		time.sleep(0.1)

	def check_install(self):
		pass

	def before(self):
		base.mkdir('statements')
		shutil.copytree(pjoin(base.path, 'templates'), tmp_path, dirs_exist_ok = True)
		base.mkdir(pjoin('statements', self.comp))
		if self.conf.folder == 'contest':
			self.contest = self.conf
		elif self.conf.folder == 'day':
			self.day = self.conf
		elif self.conf.folder == 'problem':
			self.prob = self.conf

	def move_resource(self):
		if os.path.exists(pjoin(self.prob.path, 'resources')):
			base.rmtree(self.path, ignore_errors = True)
			time.sleep(0.1)
			shutil.copytree(pjoin(self.prob.path, 'resources'), (self.path if self.prob.route != '' else pjoin(self.path, self.prob['name'])))

	def gen_paths(self):
		self.path = pjoin('statements', self.comp)
		if self.prob.route != '':
			self.path = pjoin(self.path, self.prob.route)
		self.result_path = self.path + ('-' + base.lang if base.lang else '')
		if self.prob.route == '':
			self.result_path = pjoin(self.result_path, self.prob['name'])
		self.result_path += '.' + self.work

	def main(self):
		if self.conf.folder == 'contest':
			for self.day in self.conf.days():
				if not os.path.exists(pjoin('statements', self.comp, self.day.route)):
					os.makedirs(pjoin('statements', self.comp, self.day.route))
		if self.comp == 'tsinsen-oj':
			log.warning(u'如果你使用了resource，你可能需要使用dumper才能获得正确上传清橙的文件。')
		for self.prob in self.conf.probs():
			self.gen_paths()
			self.move_resource()
			self.ren_prob_md_j()
			self.ren_prob_rest()
			self.start_file()

	def final(self):
		base.rmtree(tmp_path, ignore_errors = True)

	def run(self):
		self.check_install()
		self.before()
		self.main()
		self.final()

	def start_file(self):
		if base.start_file:
			base.xopen_file(self.result_path)

class Latex(Base):
	work = 'tex'
	day_templates = {
		'noi' : 'tuoi',
		'tuoi' : 'tuoi',
		'tupc' : 'tupc',
		'ccpc' : 'ccpc',
		'ccc' : 'ccc',
		'hand' : 'hand'
	}

	def resource(self, name):
		return pjoin(self.prob.full_path, 'resources', name).replace('\\', '/')

	def check_install(self):
		base.check_install('pandoc')
		base.check_install('xelatex')
		base.check_install('gettext')

	def ren_prec(self):
		if not os.path.exists(base.pjoin(self.conf.path, 'precautions', 'zh-cn.md')):
			return
		context = {
			'io_style' : self.io_style,
			'comp' : self.comp,
			'tools' : tools,
			'tl' : tools,
			'base' : base,
			'json' : json
		}
		base.copy(base.pjoin(self.conf.path, 'precautions'), 'zh-cn.md', tmp_path)
		open(base.pjoin(tmp_path, 'precautions.md'), 'wb') \
			.write(get_template('zh-cn.md').render(context, conf = self.conf).encode('utf-8'))
		os.system('pandoc %s %s -o %s' % (
			get_pandoc_option(),
			pjoin(tmp_path, 'precautions.md'),
			pjoin(tmp_path, 'precautions.tex')
		))
		self.prec = open(pjoin(tmp_path, 'precautions.tex'), 'rb').read().decode('utf-8')

	def ren_day_prec(self):
		if not os.path.exists(base.pjoin(self.day.path, 'precautions', 'zh-cn.md')):
			return
		context = {
			'io_style' : self.io_style,
			'comp' : self.comp,
			'tools' : tools,
			'tl' : tools,
			'base' : base,
			'json' : json
		}
		base.copy(base.pjoin(self.day.path, 'precautions'), 'zh-cn.md', tmp_path)
		open(base.pjoin(tmp_path, 'precautions.md'), 'wb') \
			.write(get_template('zh-cn.md').render(context, conf = self.day).encode('utf-8'))
		os.system('pandoc %s %s -o %s' % (
			get_pandoc_option(),
			pjoin(tmp_path, 'precautions.md'),
			pjoin(tmp_path, 'precautions.tex')
		))
		self.prec = open(pjoin(tmp_path, 'precautions.tex'), 'rb').read().decode('utf-8')

	def ren_prob_tex(self):
		os.system('pandoc %s %s -o %s' % (
			get_pandoc_option(),
			pjoin(tmp_path, 'problem.md'),
			pjoin(tmp_path, 'problem.tex')
		))
		tex = open(pjoin(tmp_path, 'problem.tex'), 'rb').read().decode('utf-8')
		for key, val in self.secondary_dict.items():	## 如果未来发生了性能问题，这里可以先写到一个文件里然后再解析
			open(pjoin(tmp_path, key + '.tex.jinja'), 'wb').write(
				('{{ ' + val + ' }}').encode('utf-8')
			)
			ret = get_template(key + '.tex.jinja', self.prob.lang()).render(
				self.context,
				template = lambda temp_name, **context : get_template(temp_name + '.tex.jinja', self.prob.lang()).render(context),
				table = lambda name, options = None : table(pjoin(self.prob.path, 'tables'), name, 'table.tex.jinja', self.context, options)
			)
			tex = tex.replace(key, ret)
		self.secondary_dict = {}
		return tex

	def gen_compile(self):
		clangs = {l for prob in self.probs for l in prob.get('compile', {}).keys()}
		ret = {}
		for clang in clangs:
			cur = []
			for prob in self.probs:
				if prob['type'] != 'output':
					if clang in prob['compile']:
						cur.append({
							'option' : prob['compile'][clang] + (' -Wl,--stack=%d' % prob.memory_limit().B if clang in {'cpp', 'c'} and base.out_system == 'Windows' else ''),
							'cnt' : 1,
							'use' : True
						})
					else:
						cur.append({'option' : u'不可用', 'cnt' : 1, 'use' : False})
				else:
					cur.append({'option' : 'N/A', 'cnt' : 1, 'use' : False})
			last = []
			for p in cur:
				if len(last) == 0 or p['option'] != last[-1]['option']:
					last.append(p)
				else:
					last[-1]['cnt'] += 1
			ret[clang] = last
		return ret

	def ren_day_pdf(self):
		log.info(u'渲染比赛日题面 %s %s' % (self.comp, self.day.route if self.day else self.conf.route))
		self.context.pop('prob')
		self.context.pop('file_name')
		self.context.pop('down_file')
		self.context.pop('resource')
		self.context.pop('render')
		self.context['probs'] = self.probs
		self.context['problems'] = self.tex_problems
		self.context['compile'] = self.gen_compile()
		self.context['water_mark'] = base.water_mark
		if base.water_mark:
			shutil.copy(base.water_mark, pjoin(tmp_path, 'water_mark.' + base.water_mark.split('.')[-1]))
		all_problem_statement = get_template('%s.tex.jinja' % base_templates[self.comp]).render(self.context)
		try:
			open(pjoin(tmp_path, 'problems.tex'), 'wb') \
				.write(all_problem_statement.encode('utf-8'))
		except Exception as e:
			log.info(u'渲染出错的文件为`tmp/problems.tmp.tex`')
			open(pjoin(tmp_path, 'problems.tmp.tex'), 'wb') \
				.write(all_problem_statement.encode('utf-8'))
			raise e
		log.info(u'开始使用xelatex渲染题面。')
		back = os.getcwd()
		os.chdir(tmp_path)
		os.system('xelatex -interaction=batchmode problems.tex')
		os.system('xelatex -interaction=batchmode problems.tex')
		if not os.path.exists('problems.pdf'):
			log.warning(u'题面渲染失败，尝试使用关闭静默模式渲染。')
			os.system('xelatex problems.tex')
			os.system('xelatex problems.tex')
		if not os.path.exists('problems.pdf'):
			log.error(u'题面渲染失败，请检查`tmp`目录下各文件。')
		os.chdir(back)
		shutil.copy(pjoin(tmp_path, 'problems.pdf'), self.result_path)

	def ren_day(self):
		if self.day:
			day_name = self.day['name']
			self.probs = list(self.day.probs())
		else:
			day_name = u'测试'
			self.probs = [self.prob]
		if len(self.probs) == 0:
			log.info(u'指定目录`%s`下没有题目可渲染。' % (self.day.path if self.day else self.conf.path))
			return
		self.tex_problems = []
		for self.prob in self.probs:
			self.ren_prob_md_j()
			self.tex_problems.append(self.ren_prob_tex())
		self.ren_day_pdf()
		self.start_file()

	def main(self):
		self.ren_prec()
		self.day_template = self.day_templates[self.comp]
		if self.conf.folder != 'problem':
			for self.day in base.days():
				self.result_path = pjoin('statements', self.comp, self.day.name_lang() + '.pdf')
				self.ren_day_prec()
				self.ren_day()
		else:
			self.result_path = pjoin('statements', self.comp, self.conf.name_lang() + '.pdf')
			self.ren_day()

class Markdown(Base):
	work = 'md'
	def ren_prob_rest(self):
		table_suf = 'html' if self.comp not in work_class['syzoj_like'] else 'md'
		result_md = get_template('problem.md', self.prob.lang()).render(
			self.context,
			template = lambda temp_name, **context : get_template(temp_name + '.html.jinja', self.prob.lang()).render(context),
			table = lambda name, options = None : table(pjoin(self.prob.path, 'tables'), name, 'table.'+ table_suf +'.jinja', self.context, options)
		).encode('utf-8')
		if self.comp == 'uoj':
			result_md = uoj_title(result_md)
		elif self.comp in work_class['syzoj_like']:
			result_md = loj_bug(result_md)
		open(self.result_path, 'wb').write(result_md)

class Html(Base):
	work = 'html'
	def check_install(self):
		base.check_install('pandoc')

	def ren_prob_rest(self):
		if self.comp == 'tsinsen-oj':
			with open(pjoin(tmp_path, 'problem.2.md'), 'wb') as f:
				for line in open(pjoin(tmp_path, 'problem.md'), 'rb'):
					if re.match(b'^##[^#]', line):
						line = (u'## 【%s】\n' % line[2:].strip().decode('utf-8')).encode('utf-8')
					f.write(line)
		else:
			base.copy(tmp_path, 'problem.md', pjoin(tmp_path, 'problem.2.md'))
		txt = open(pjoin(tmp_path, 'problem.2.md'), 'rb').read().decode('utf-8')
		for key, val in self.secondary_dict.items():
			txt = txt.replace(key, '{{ ' + val + ' }}')
		open(pjoin(tmp_path, 'problem.3.md'), 'wb').write(
			txt.encode('utf-8')
		)
		open(base.pjoin(tmp_path, 'problem.4.md'), 'wb') \
			.write(get_template('problem.3.md', self.prob.lang())
				.render(
					self.context,
					template = lambda temp_name, **context : get_template(temp_name + '.html.jinja', self.prob.lang()).render(context),
					table = lambda name, options = None : table(pjoin(self.prob.path, 'tables'), name, 'table.html.jinja', self.context, options)
				).encode('utf-8')
			)
		os.system('pandoc %s -o %s' % (
			pjoin(tmp_path, 'problem.4.md'),
			self.result_path
		))

class DoKuWiki(Base):
	work = 'doku'
	def check_install(self):
		base.check_install('pandoc')

	def ren_prob_rest(self):
		os.system('pandoc %s -o %s -w dokuwiki' % (
			pjoin(tmp_path, 'problem.md'),
			pjoin(tmp_path, 'problem.doku')
		))
		txt = open(pjoin(tmp_path, 'problem.doku'), 'rb').read().decode('utf-8')
		for key, val in self.secondary_dict.items():
			txt = txt.replace(key, '{{ ' + val + ' }}')
		open(pjoin(tmp_path, 'problem.2.doku'), 'wb').write(
			txt.encode('utf-8')
		)
		open(self.result_path, 'wb') \
			.write(get_template('problem.2.doku', self.prob.lang())
				.render(
					self.context,
					template = lambda temp_name, **context : '<HTML>' + get_template(temp_name + '.html.jinja', self.prob.lang()).render(context) + '</HTML>',
					table = lambda name, options = None : '<HTML>' + table(pjoin(self.prob.path, 'tables'), name, 'table.html.jinja', self.context, options).strip() + '</HTML>'
				).encode('utf-8')
			)

class_list = {
	'ccpc' : Latex,
	'uoj' : Markdown,
	'tupc' : Latex,
	'tuoi' : Latex,
	'noi' : Latex,
	'tuoj' : Markdown,
	'ccc-tex' : Latex,
	'ccc-md' : Markdown,
	'tsinsen-oj' : Html,
	'loj' : Markdown,
	'ipuoj' : Markdown,
	'thuoj' : DoKuWiki,
	'hand' : Latex
}

comp_list = {
	'ccpc' : 'ccpc',
	'uoj' : 'uoj',
	'tupc' : 'tupc',
	'tuoi' : 'tuoi',
	'noi' : 'noi',
	'tuoj' : 'tuoj',
	'ccc-tex' : 'ccc',
	'ccc-md' : 'ccc',
	'tsinsen-oj' : 'tsinsen-oj',
	'loj' : 'loj',
	'ipuoj' : 'ipuoj',
	'thuoj' : 'thuoj',
	'hand' : 'hand'
}

if __name__ == '__main__':
	try:
		if base.init():
			base.check_install('jinja2')
			for base.work in base.works:
				for base.lang in base.langs:
					base.run_exc(class_list[base.work](comp_list[base.work]).run)
		else:
			log.info(u'这个工具用于渲染题面。')
			log.info(u'支持的工作：%s' % ','.join(sorted(class_list.keys())))
	except base.NoFileException as e:
		log.error(e)
		log.info(u'尝试使用`python -m tuack.gen -h`获取如何生成一个工程。')
