#!/usr/bin/env python3
#******************************************************************************
# Copyright (C) 2018 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
# This file is part of the textoutpc project, which is MIT-licensed.
#******************************************************************************

from ..tags import TextoutInlineTag as _TextoutInlineTag
from ..color import get_color

__all__ = ["TextoutTextTag"]

# ---
# Data.
# ---

_big_size = 2.00
_sml_size = 0.75

_fonts = {
	"arial": "Arial",
	"comic": "Comic MS",
	"tahoma": "Tahoma",
	"courier": "Courier",
	"haettenschweiler": "Haettenschweiler",
	"mono": "monospace",
	"monospace": "monospace"
}

# ---
# Tag definition.
# ---

class TextoutTextTag(_TextoutInlineTag):
	""" Main tag for setting text formatting.
		Example uses:
		
		[b]Bold text.[/b]
		[i]Italic text.[/i]
		[u]Underlined text.[/u]
		[strike]Striked text.[/strike]
		[striked]Text strikes again.[/striked]
		[font=arial]Arial text.[/font]
		[arial]Arial text again.[/arial]
		[blue]This will be in blue[/blue]
		[color=blue]This as well[/color]
		[color=rgb(255, 255, 255, 0.4)]BLACKNESS[/color]
		[color=hsl(0, 100%, 0.5)]This will be red.[/color]
	
		Also supports a hack used on Planète Casio for a while, which
		is a CSS injection, e.g.:
	
		[color=brown; size: 16pt]Hello world![/color]
	"""

	aliases = ('[b]', '[i]', '[u]', '[s]', '[strike]',
		'[monospace]', '[mono]', '[font]', '[color]',
		'[size]', '[big]', '[small]',
		'[arial]', '[comic]', '[tahoma]', '[courier]',
		'[haettenschweiler]', '[red]', '[green]', '[blue]',
		'[yellow]', '[maroon]', '[purple]', '[gray]',
		'[grey]', '[brown]')
	notempty = True

	def prepare(self, name, value):
		self._bold = False
		self._italic = False
		self._underline = False
		self._strike = False
		self._font = None
		self._color = None
		self._size = None

		# Récupérer la partie correspondant à l'injection CSS s'il y
		# en a une.

		def get_props(value):
			props = ''
			if value != None:
				index = value.find(';')
				if index >= 0:
					props = value[index + 1:]
					value = value[:index]
			return value, props

		# Définir les propriétés à partir du truc principal.

		name = name[1:-1]
		props = ""
		if name == "b":
			self._bold = True
		elif name == "i":
			self._italic = True
		elif name == "u":
			self._underline = True
		elif name in ("s", "strike", "striked"):
			self._strike = True
		elif name == "color":
			value, props = get_props(value)
			self._color = get_color(value)
		elif name == "font":
			value, props = get_props(value)
			assert value in _fonts
			self._font = _fonts[value]
		elif name in ('size', 'big', 'small'):
			if name != 'size':
				value = name
			if value == 'big':
				self._size = _big_size
			elif value == 'small':
				self._size = _sml_size
			else:
				self._size = round(int(value) / 100.0, 2)
				assert 0 < self._size <= 3.0

			if self._size == 1.0:
				self._size = None
		elif name in _fonts:
			self._font = name
		else:
			self._color = get_color(name)

		# Gestion des injections CSS.

		for prop in props.split(';'):
			prop = prop.strip()
			if not prop:
				continue

			name, *value = prop.split(':')
			if not value:
				continue
			name = name.strip()
			value = ':'.join(value).strip()

			if name == 'size':
				unit = 'pt'
				if   value.endswith('pt'):
					value = value[:-2].rstrip()
				elif value.endswith('em'):
					unit = 'em'
					value = value[:-2].rstrip()

				if not value or \
					any(c != '0' for c in value[:-3]) or \
					any(not c in '0123456789' for c in value[-3:]):
					continue

				value = int(value[-3:])
				if unit == 'pt':
					value /= 12 # XXX: default em size

				if 0 < value <= 3.0:
					self._size = value

	def _get_css(self):
		""" Get the `style` CSS classes and properties for HTML output. """

		classes, props = [], []

		if not self.tweak('obsolete_tags', True):
			if self._bold:
				props.append('font-weight: bold')
			if self._italic:
				props.append('font-style: italic')
			if self._underline or self._strike:
				props.append('text-decoration:{}{}'.format(' underline' \
					if self._underline else '', ' line-through' \
					if self._strike else ''))

		if self._font:
			props.append('font-family: ' + self._font)

		if self._color:
			# `transparent` is at least considered as a special value,
			# or at most as an alias to `rgba(0,0,0,0)`.

			if self._color[3] == 0.0:
				props.append('color: transparent')
			else:
				# always append the #rgb color: it will be read by older
				# browsers if the `rgba()` function isn't supported.

				props.append('color: #%02X%02X%02X' % self._color[0:3])
				if self._color[3] < 1.0:
					props.append('color: rgba({}, {}, {}, {})' \
						.format(*self._color))

		if self._size:
			props.append('font-size: {}em'.format(self._size))

		return classes, props

	def begin_html(self):
		obsoletetags = self.tweak('obsolete_tags', True)

		cls, props = self._get_css()
		if cls or props:
			props = '<span{}{}>'.format(' class="{}"'.format(' '.join(cls)) \
				if cls else '', ' style="{}"'.format('; '.join(props)) \
				if props else '')
		else:
			props = ''

		return '' \
			+ ('', '<b>')[obsoletetags and self._bold] \
			+ ('', '<i>')[obsoletetags and self._italic] \
			+ ('', '<u>')[obsoletetags and self._underline] \
			+ ('', '<strike>')[obsoletetags and self._strike] \
			+ props

	def end_html(self):
		obsoletetags = self.tweak('obsolete_tags', True)

		return '' \
			+ ('', '</span>')[any(self._get_css())] \
			+ ('', '</strike>')[obsoletetags and self._strike] \
			+ ('', '</u>')[obsoletetags and self._underline] \
			+ ('', '</i>')[obsoletetags and self._italic] \
			+ ('', '</b>')[obsoletetags and self._bold]

# End of file.
