import collections
import glob
import os
import sys

import psb

fs = open('textsub.tjs', 'w', encoding='cp932')

def make_indexes(texts):
	indexes = {}
	for id, text in enumerate(texts):
		indexes[text] = id
	return indexes

def get_texts(scene):
	names = []
	disps = []
	texts = []
	if 'texts' in scene:
		textlist = scene['texts']
		for record in textlist:
			names.append(record[0])
			disps.append(record[1])
			texts.append(record[2])
	return names, disps, texts
	
def get_selects(scene):
	texts = []
	if 'selects' in scene:
		selects = scene['selects']
		for select in selects:
			texts.append(select['text'])
	return texts
	
def get_sprite(elem):
	character = elem['file'].replace('.stand', '')
	dress = elem['options']['dress']
	pose = elem['options']['pose']
	face = elem['options']['face']
	return '{}_{}_{}_{}'.format(character, dress, pose, face)
	
def get_sprites(scene):
	sprites = {}
	curline = 0
	sprites[curline] = []
	if 'lines' in scene:
		lines = scene['lines']
		for line in lines:
			if isinstance(line, int):
				curline = line
				sprites[curline] = []
			elif isinstance(line, list):
				if line[0] == 'objtrans':
					try:
						idx = line.index('redraw') + 1
						if 'imageFile' in line[idx] and line[idx]['imageFile']['file'].endswith('.stand'):
							sprites[curline].append(get_sprite(line[idx]['imageFile']))
					except ValueError:
						pass
				elif line[0] == 'delayrun':
					for elem in line[2]:
						if elem[0] == 'objtrans':
							try:
								idx = elem.index('redraw') + 1
								if 'imageFile' in elem[idx] and elem[idx]['imageFile']['file'].endswith('.stand'):
									sprites[curline].append(get_sprite(elem[idx]['imageFile']))
							except ValueError:
								pass
	return sprites

def extract(scn_file):
	data, is_comp = psb.get_data(scn_file)
	psbobj = psb.get_psb(data)
	objectblock = psbobj.objectblock
	org_texts = psb.get_texts(psbobj)
	org_names = psb.get_names(psbobj)
	org_chunks = psb.get_chunks(psbobj)
	text_index = make_indexes(org_texts)
	expr = psb.get_expr(objectblock, org_names, org_texts, org_chunks)
	
	ofile = os.path.splitext(file)[0] + '.txt'
	fo = open(ofile, 'w', encoding='utf-8')
	
	if 'scenes' not in expr:
		fo.close()
		return
		
	name_set = set()
	aliases = collections.defaultdict(int)
	for scene in expr['scenes']:
		names, disps, texts = get_texts(scene)
		for name, disp, text in zip(names, disps, texts):
			if name:
				name_set.add(name)
			if disp:
				name_set.add(disp)
			aliases[text] += 1
	
	for name in sorted(name_set):
		id = text_index[name]
		fo.write('//<{:04X}>{}\n'.format(id, name))
		fo.write('<{:04X}>{}\n'.format(id, name))
		fo.write('\n')
			
	fo.write('///'+'='*80+'\n\n')
	
	for scene in expr['scenes']:
		curscene = expr['name'] + scene['label']
		fs.write('\t"{}" => %[\n'.format(curscene.replace('"','\\"')))
		names, disps, texts = get_texts(scene)
		sprites = get_sprites(scene)
		for curline, record in enumerate(zip(names, disps, texts)):
			name, disp, text = record
			if curline in sprites:
				for sprite in sprites[curline]:
					fo.write('# {}\n'.format(sprite))
				fo.write('\n')
			if name:
				if disp:
					speaker = '【{}／{}】'.format(name, disp)
				else:
					speaker = '【{}】'.format(name)
			else:
				speaker = ''
			if aliases[text] > 1:
				alias = '{{{}}}'.format(aliases[text])
			else:
				alias = ''
			if speaker or alias:
				fo.write('//{} {}\n'.format(speaker, alias))
			id = text_index[text]
			text = text.replace('\n','\\n')
			fo.write('//<{:04X}>{}\n'.format(id, text))
			fo.write('<{:04X}>{}\n'.format(id, text))
			fo.write('\n')
			#if alias:
			#	fs.write('{}::::{:04X}::::{:04d}::::{}\n'.format(curscene, id, curline, text))
			fs.write('\t\t{} => "{}",\n'.format(curline + 1, text.replace('"','\\"')))
		fo.write('///'+'='*80+'\n\n')
		fs.write('\t],\n')
		
	for scene in expr['scenes']:
		texts = get_selects(scene)
		for text in texts:
			id = text_index[text]
			text = text.replace('\n','\\n')
			fo.write('//<{:04X}>{}\n'.format(id, text))
			fo.write('<{:04X}>{}\n'.format(id, text))
			fo.write('\n')
				
	fo.close()
			
if __name__ == '__main__':
	if len(sys.argv) < 2:
		print('Usage: extract.py <scn_files>')
		exit(1)
	fs.write('%[\n')
	for arg in sys.argv[1:]:
		for file in glob.glob(arg):
			if os.path.splitext(file)[1].lower() == '.scn':
				if not os.access(os.path.splitext(file)[0] + '.txt', os.F_OK):
					print('Extracting from {}...'.format(file))
					extract(file)
	fs.write(']\n')
