#!/usr/bin/env python
# -*- coding: utf-8 -*-

import array
import re
import struct
import os
import sys

from pytable import normal_table

PFILE = "../Arquivos Gerais/pointers.bin"
TFILE = "../Arquivos Gerais/texts.bin"

TAG_IN_LINE = r'(\[.+?\])'
GET_TAG = r'^\[(.+?)\]$'
END = r'^!\D{30}!$'

TAGS = {
'\x05\x00\x00\x73' : 'E',
'\x05\x00\x00\x75' : '2',
'\x05\x00\x00\x76' : '3',
'\x05\x01\x00\x44' : '>',
'\x05\x00\x00\x6A' : 'H',
'\x05\x00\x00\x7E' : 'S',
'\x05\x00\x00\x7F' : '-',
'\x05\x01\x00\x5B' : 'R',
'\x05\x01\x00\x5C' : 'B',
'\x05\x01\x00\x5D' : 'L',
'\x05\x01\x00\x5E' : 'A',
'\x05\x00\x00\x67' : 'F',
'\x06\x00\x00\x78' : 'W',  # Pr�ximo byte � o tempo de espera
}

def Extract():
	# Dados gravados em big-endian!!
	table = normal_table( 'zelda.tbl' )
	table.fill_with( '61=a', '41=A', '30=0' )
	table.add_items( '0A=\r\n' )

	pfile = open( PFILE, 'rb' )
	# Primeiros 16 bytes do arquivo s�o o header
	# 00 .. 03: STAMP - Sempre "\xD1\x2D\x9E\x31"
	# 04 .. 07: Tamanho do arquivo
	# 08 .. 09: N�mero de ponteiros na estrutura
	# 0A .. 0B: Tamanho dos ponteiros (4 bytes)
	# 0C .. 0F: Completar com zeros
	stamp = pfile.read( 4 )
	size = struct.unpack( '>L', pfile.read( 4 ) )[0]
	pentries = struct.unpack( '>H', pfile.read( 2 ) )[0]
	psize = struct.unpack( '>H', pfile.read( 2 ) )[0]
	pfile.seek( 0x10, 0 )
	# Gera o buffer de ponteiros
	pbuffer = []
	for x in range( pentries ):
		pbuffer.append( struct.unpack( '>L', pfile.read( psize ) )[0] )
	pfile.close()

	output = open( '../Texto Original/Zelda ALttP.txt', 'wb' )
	tfile = open( TFILE, 'rb' )
	# Primeiros 8 bytes do arquivo s�o o header
	# 00 .. 03: STAMP - Sempre "DAT1"
	# 04 .. 07: Tamanho do arquivo
	stamp = tfile.read( 4 )
	size = struct.unpack( '>L', tfile.read( 4 ) )[0]
	for x in range( len( pbuffer ) ):
		try:
			tsize = pbuffer[x + 1] - pbuffer[x]
		except:
			tsize = ( size - 8 ) - pbuffer[x]

		tfile.seek( pbuffer[x] + 8, 0 )
		j = 0
		while j < tsize:
			byte = tfile.read( 1 )
			if byte == '\x1a':
				tag = tfile.read( 4 )
				if tag in TAGS:
					output.write( '[%s]' % TAGS[tag] )
				else:
					output.write( '[%08X]' % struct.unpack( '>L', tag ) )
				j += 5
			elif byte in table:
				output.write( table[byte] )
				j += 1
			else:
				output.write( '[%02X]' % struct.unpack( 'B', byte )[0] )
				j += 1
		output.write( '\r\n!------------------------------!\r\n' )

	tfile.close()
	output.close()

def Insert():
	table = normal_table( 'zelda.tbl' )
	table.fill_with( '61=a', '41=A', '30=0' )
	table.set_mode( 'inverted' )

	iTAGS = dict( [[v, k] for k, v in TAGS.items()] )

	input = open( '../Texto Traduzido/Zelda ALttP.txt', 'rb' )

	buffers = []

	buffer = array.array( 'c' )
	for line in input:
		line = line.strip( '\r\n' )
		print line
		if re.match( END, line ):
			buffer.pop()
			buffers.append( buffer )
			buffer = array.array( 'c' )
		else:
			splited = re.split( TAG_IN_LINE, line )  # Divide a linha de maneira que as tags fiquem separadas do texto
			for string in splited:
				tag = re.match( GET_TAG, string )
				if not tag:  # Se string n�o for uma tag
					for char in string:
						buffer.extend( table[char] )
				else:  # Se string for uma tag
					tag = tag.groups()[0]
					if tag in iTAGS:
						buffer.extend( '\x1a' )
						buffer.extend( iTAGS[tag] )
					else:
						if len( tag ) == 2:
							buffer.extend( chr( int( tag, 16 ) ) )
						else:
							buffer.extend( '\x1a' )
							buffer.extend( struct.pack( '>L', ( int( tag, 16 ) ) ) )
			buffer.extend( '\x0a' )

	# Gerando texts.bin
	tfile = open( TFILE, 'wb' )
	tfile.seek( 0x9, 0 )  # O header ser� preenchido no fim

	pointers = []
	for buffer in buffers:
		pointers.append( tfile.tell() - 8 )
		buffer.tofile( tfile )
	# Escreve o header
	tfile.seek( 0, 0 )
	tfile.write( 'DAT1' )
	tfile.write( struct.pack( '>L', os.path.getsize( tfile.name ) ) )
	tfile.close()

	# Gerando pointers.bin
	pfile = open( PFILE, 'wb' )
	pfile.seek( 0x10, 0 )
	for pointer in pointers:
		pfile.write( struct.pack( '>L', pointer ) )
	pfile.write( '\x00' * 20 )
	# Escreve o header
	pfile.seek( 0, 0 )
	pfile.write( '\xD1\x2D\x9E\x31' )
	pfile.write( struct.pack( '>L', os.path.getsize( pfile.name ) ) )
	pfile.write( struct.pack( '>H', len( pointers ) ) )
	pfile.write( struct.pack( '>H', 4 ) )

	pfile.close()

	#os.system( 'apply.bat' )

	pass

if __name__ == "__main__":
	# import psyco
	# psyco.full()

	print 'Zelda ALttP\'s Dumper - Monkeys Traducoes 2010'
	opt = int( raw_input( " [1] Extrair \n [2] Inserir \n [3] Sair \n>> " ) )

	if opt == 1:
		Extract()
	elif opt == 2:
		Insert()
	elif opt == 3:
		sys.exit( 1 )
	sys.exit( 1 )

