#!/usr/bin/env python

import itertools as it, operator as op, functools as ft
from collections import namedtuple
import os, sys, re

Group = namedtuple('group', 'name type contents')
Value = namedtuple('value', 'name type contents')
sort_func = lambda elm: (elm.__class__.__name__, elm)



# Begin -- grammar generated by Yapps
import sys, re
from yapps import runtime

class eet_cfgScanner(runtime.Scanner):
	patterns = [
		("';'", re.compile(';')),
		("'value'", re.compile('value')),
		("r'\\}'", re.compile('\\}')),
		("r'\\{'", re.compile('\\{')),
		("'group'", re.compile('group')),
		('[ \\t\\r\\n]+', re.compile('[ \\t\\r\\n]+')),
		('END', re.compile('$')),
		('N', re.compile('[+\\-]?[\\d.]+')),
		('S', re.compile('"([^"\\\\]*(\\\\.[^"\\\\]*)*)"')),
		('VT', re.compile('\\w+:')),
		('GT', re.compile('struct|list')),
	]
	def __init__(self, str,*args,**kw):
		runtime.Scanner.__init__(self,None,{'[ \\t\\r\\n]+':None,},str,*args,**kw)

class eet_cfg(runtime.Parser):
	Context = runtime.Context
	def config(self, _parent=None):
		_context = self.Context(_parent, self._scanner, 'config', [])
		block = self.block(_context)
		END = self._scan('END', context=_context)
		return block

	def block(self, _parent=None):
		_context = self.Context(_parent, self._scanner, 'block', [])
		_token = self._peek("'group'", "'value'", context=_context)
		if _token == "'group'":
			block_group = self.block_group(_context)
			return block_group
		else: # == "'value'"
			block_value = self.block_value(_context)
			return block_value

	def block_group(self, _parent=None):
		_context = self.Context(_parent, self._scanner, 'block_group', [])
		self._scan("'group'", context=_context)
		S = self._scan('S', context=_context)
		GT = self._scan('GT', context=_context)
		self._scan("r'\\{'", context=_context)
		contents = list()
		while self._peek("r'\\}'", "'group'", "'value'", context=_context) != "r'\\}'":
			block = self.block(_context)
			contents.append(block)
		self._scan("r'\\}'", context=_context)
		return Group(S, GT, contents)

	def value(self, _parent=None):
		_context = self.Context(_parent, self._scanner, 'value', [])
		_token = self._peek('S', 'N', context=_context)
		if _token == 'S':
			S = self._scan('S', context=_context)
			return S
		else: # == 'N'
			N = self._scan('N', context=_context)
			return N

	def block_value(self, _parent=None):
		_context = self.Context(_parent, self._scanner, 'block_value', [])
		self._scan("'value'", context=_context)
		S = self._scan('S', context=_context)
		VT = self._scan('VT', context=_context)
		value = self.value(_context)
		self._scan("';'", context=_context)
		return Value(S, VT, value)


def parse(rule, text):
	P = eet_cfg(eet_cfgScanner(text))
	return runtime.wrap_error_reporter(P, rule)

# End -- grammar generated by Yapps




def dump(elm, indent=0):
	if isinstance(elm, (Group, Value)):
		if isinstance(elm.contents, bytes): contents = elm.contents
		else:
			contents = ''.join(
				dump(val, indent=indent+1)
				for val in sorted(elm.contents, key=sort_func) )
		if isinstance(elm, Group):
			contents = '{{\n{}{}}}'.format(contents, ' '*indent*4)
		else:
			if elm.name == '"file"'\
					and elm.type == 'string:'\
					and contents.startswith('"/tmp/.lqr_wpset_bg.'):
				contents = '"/tmp/bg.png"'
			contents += ';'
		return ' '*indent*4 + ' '.join([
			elm.__class__.__name__,
			elm.name, elm.type, contents ]) + '\n'
	else:
		raise TypeError(type(elm))


def main(argv=None):
	import argparse
	parser = argparse.ArgumentParser(
		description='Tool to decode E config, replace transient values'
			' (like desktop bg) and sort groups/values there to make it diff-friendly.')
	parser.add_argument( 'config',
		help='Path to eet-encoded/compressed E config.' )
	optz = parser.parse_args(argv if argv is not None else sys.argv[1:])

	from subprocess import Popen, PIPE
	src = Popen(['eet', '-d', optz.config, 'config'], stdout=PIPE)
	sys.stdout.write(dump(parse('config', src.stdout.read())))
	if src.wait(): raise RuntimeError('eet exited with non-zero status')

if __name__ == '__main__': main()
