# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

import operator

from collections import defaultdict

try:
	from __builtin__ import reduce
except ImportError:
	from functools import reduce

from pygments.token import Token
from prompt_toolkit.styles import DynamicStyle, Attrs

from powerline.renderers.ipython import IPythonRenderer
from powerline.ipython import IPythonInfo
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE


PowerlinePromptToken = Token.Generic.Prompt.Powerline


# Note: since 2.7 there is dict.__missing__ with same purpose. But in 2.6 one 
# must use defaultdict to get __missing__ working.
class PowerlineStyleDict(defaultdict):
	'''Dictionary used for getting pygments style for Powerline groups
	'''
	def __new__(cls, missing_func):
		return defaultdict.__new__(cls)

	def __init__(self, missing_func):
		super(PowerlineStyleDict, self).__init__()
		self.missing_func = missing_func

	def __missing__(self, key):
		return self.missing_func(key)


class PowerlinePromptStyle(DynamicStyle):
	def get_attrs_for_token(self, token):
		if (
			token not in PowerlinePromptToken
			or len(token) != len(PowerlinePromptToken) + 1
			or not token[-1].startswith('Pl')
			or token[-1] == 'Pl'
		):
			return super(PowerlinePromptStyle, self).get_attrs_for_token(token)
		ret = {
			'color': None,
			'bgcolor': None,
			'bold': None,
			'underline': None,
			'italic': None,
			'reverse': False,
			'blink': False,
		}
		for prop in token[-1][3:].split('_'):
			if prop[0] == 'a':
				ret[prop[1:]] = True
			elif prop[0] == 'f':
				ret['color'] = prop[1:]
			elif prop[0] == 'b':
				ret['bgcolor'] = prop[1:]
		return Attrs(**ret)

	def get_token_to_attributes_dict(self):
		dct = super(PowerlinePromptStyle, self).get_token_to_attributes_dict()

		def fallback(key):
			try:
				return dct[key]
			except KeyError:
				return self.get_attrs_for_token(key)

		return PowerlineStyleDict(fallback)

	def invalidation_hash(self):
		return super(PowerlinePromptStyle, self).invalidation_hash() + 1


class IPythonPygmentsRenderer(IPythonRenderer):
	reduce_initial = []

	def get_segment_info(self, segment_info, mode):
		return super(IPythonPygmentsRenderer, self).get_segment_info(
			IPythonInfo(segment_info), mode)

	@staticmethod
	def hl_join(segments):
		return reduce(operator.iadd, segments, [])

	def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
		'''Output highlighted chunk.

		This implementation outputs a list containing a single pair 
		(:py:class:`pygments.token.Token`, 
		:py:class:`powerline.lib.unicode.unicode`).
		'''
		guifg = None
		guibg = None
		attrs = []
		if fg is not None and fg is not False:
			guifg = fg[1]
		if bg is not None and bg is not False:
			guibg = bg[1]
		if attrs:
			attrs = []
			if attrs & ATTR_BOLD:
				attrs.append('bold')
			if attrs & ATTR_ITALIC:
				attrs.append('italic')
			if attrs & ATTR_UNDERLINE:
				attrs.append('underline')
		name = (
			'Pl'
			+ ''.join(('_a' + attr for attr in attrs))
			+ (('_f%6x' % guifg) if guifg is not None else '')
			+ (('_b%6x' % guibg) if guibg is not None else '')
		)
		return [(getattr(Token.Generic.Prompt.Powerline, name), contents)]

	def hlstyle(self, **kwargs):
		return []

	def get_client_id(self, segment_info):
		return id(self)


renderer = IPythonPygmentsRenderer
