from fontTools import ttLib
from fontTools.misc.textTools import safeEval
from fontTools.ttLib.tables.DefaultTable import DefaultTable
import sys
import os
import logging


log = logging.getLogger(__name__)

class TTXParseError(Exception): pass

BUFSIZE = 0x4000


class XMLReader(object):

	def __init__(self, fileOrPath, ttFont, progress=None, quiet=None, contentOnly=False):
		if fileOrPath == '-':
			fileOrPath = sys.stdin
		if not hasattr(fileOrPath, "read"):
			self.file = open(fileOrPath, "rb")
			self._closeStream = True
		else:
			# assume readable file object
			self.file = fileOrPath
			self._closeStream = False
		self.ttFont = ttFont
		self.progress = progress
		if quiet is not None:
			from fontTools.misc.loggingTools import deprecateArgument
			deprecateArgument("quiet", "configure logging instead")
			self.quiet = quiet
		self.root = None
		self.contentStack = []
		self.contentOnly = contentOnly
		self.stackSize = 0

	def read(self, rootless=False):
		if rootless:
			self.stackSize += 1
		if self.progress:
			self.file.seek(0, 2)
			fileSize = self.file.tell()
			self.progress.set(0, fileSize // 100 or 1)
			self.file.seek(0)
		self._parseFile(self.file)
		if self._closeStream:
			self.close()
		if rootless:
			self.stackSize -= 1

	def close(self):
		self.file.close()

	def _parseFile(self, file):
		from xml.parsers.expat import ParserCreate
		parser = ParserCreate()
		parser.StartElementHandler = self._startElementHandler
		parser.EndElementHandler = self._endElementHandler
		parser.CharacterDataHandler = self._characterDataHandler

		pos = 0
		while True:
			chunk = file.read(BUFSIZE)
			if not chunk:
				parser.Parse(chunk, 1)
				break
			pos = pos + len(chunk)
			if self.progress:
				self.progress.set(pos // 100)
			parser.Parse(chunk, 0)

	def _startElementHandler(self, name, attrs):
		if self.stackSize == 1 and self.contentOnly:
			# We already know the table we're parsing, skip
			# parsing the table tag and continue to
			# stack '2' which begins parsing content
			self.contentStack.append([])
			self.stackSize = 2
			return
		stackSize = self.stackSize
		self.stackSize = stackSize + 1
		subFile = attrs.get("src")
		if subFile is not None:
			if hasattr(self.file, 'name'):
				# if file has a name, get its parent directory
				dirname = os.path.dirname(self.file.name)
			else:
				# else fall back to using the current working directory
				dirname = os.getcwd()
			subFile = os.path.join(dirname, subFile)
		if not stackSize:
			if name != "ttFont":
				raise TTXParseError("illegal root tag: %s" % name)
			sfntVersion = attrs.get("sfntVersion")
			if sfntVersion is not None:
				if len(sfntVersion) != 4:
					sfntVersion = safeEval('"' + sfntVersion + '"')
				self.ttFont.sfntVersion = sfntVersion
			self.contentStack.append([])
		elif stackSize == 1:
			if subFile is not None:
				subReader = XMLReader(subFile, self.ttFont, self.progress)
				subReader.read()
				self.contentStack.append([])
				return
			tag = ttLib.xmlToTag(name)
			msg = "Parsing '%s' table..." % tag
			if self.progress:
				self.progress.setLabel(msg)
			log.info(msg)
			if tag == "GlyphOrder":
				tableClass = ttLib.GlyphOrder
			elif "ERROR" in attrs or ('raw' in attrs and safeEval(attrs['raw'])):
				tableClass = DefaultTable
			else:
				tableClass = ttLib.getTableClass(tag)
				if tableClass is None:
					tableClass = DefaultTable
			if tag == 'loca' and tag in self.ttFont:
				# Special-case the 'loca' table as we need the
				#    original if the 'glyf' table isn't recompiled.
				self.currentTable = self.ttFont[tag]
			else:
				self.currentTable = tableClass(tag)
				self.ttFont[tag] = self.currentTable
			self.contentStack.append([])
		elif stackSize == 2 and subFile is not None:
			subReader = XMLReader(subFile, self.ttFont, self.progress, contentOnly=True)
			subReader.read()
			self.contentStack.append([])
			self.root = subReader.root
		elif stackSize == 2:
			self.contentStack.append([])
			self.root = (name, attrs, self.contentStack[-1])
		else:
			l = []
			self.contentStack[-1].append((name, attrs, l))
			self.contentStack.append(l)

	def _characterDataHandler(self, data):
		if self.stackSize > 1:
			self.contentStack[-1].append(data)

	def _endElementHandler(self, name):
		self.stackSize = self.stackSize - 1
		del self.contentStack[-1]
		if not self.contentOnly:
			if self.stackSize == 1:
				self.root = None
			elif self.stackSize == 2:
				name, attrs, content = self.root
				self.currentTable.fromXML(name, attrs, content, self.ttFont)
				self.root = None


class ProgressPrinter(object):

	def __init__(self, title, maxval=100):
		print(title)

	def set(self, val, maxval=None):
		pass

	def increment(self, val=1):
		pass

	def setLabel(self, text):
		print(text)
