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

import re

from weakref import ref

from IPython.Prompts import BasePrompt
from IPython.ipapi import get as get_ipython
from IPython.ipapi import TryNext

from powerline.ipython import IPythonPowerline, RewriteResult
from powerline.lib.unicode import string


class IPythonInfo(object):
	def __init__(self, cache):
		self._cache = cache

	@property
	def prompt_count(self):
		return self._cache.prompt_count


class PowerlinePrompt(BasePrompt):
	def __init__(self, powerline, powerline_last_in, old_prompt):
		self.powerline = powerline
		self.powerline_last_in = powerline_last_in
		self.powerline_segment_info = IPythonInfo(old_prompt.cache)
		self.cache = old_prompt.cache
		if hasattr(old_prompt, 'sep'):
			self.sep = old_prompt.sep
		self.pad_left = False

	def __str__(self):
		self.set_p_str()
		return string(self.p_str)

	def set_p_str(self):
		self.p_str, self.p_str_nocolor, self.powerline_prompt_width = (
			self.powerline.render(
				is_prompt=self.powerline_is_prompt,
				side='left',
				output_raw=True,
				output_width=True,
				segment_info=self.powerline_segment_info,
				matcher_info=self.powerline_prompt_type,
			)
		)

	@staticmethod
	def set_colors():
		pass


class PowerlinePrompt1(PowerlinePrompt):
	powerline_prompt_type = 'in'
	powerline_is_prompt = True
	rspace = re.compile(r'(\s*)$')

	def __str__(self):
		self.cache.prompt_count += 1
		self.set_p_str()
		self.cache.last_prompt = self.p_str_nocolor.split('\n')[-1]
		return string(self.p_str)

	def set_p_str(self):
		super(PowerlinePrompt1, self).set_p_str()
		self.nrspaces = len(self.rspace.search(self.p_str_nocolor).group())
		self.powerline_last_in['nrspaces'] = self.nrspaces

	def auto_rewrite(self):
		return RewriteResult(self.powerline.render(
			is_prompt=False,
			side='left',
			matcher_info='rewrite',
			segment_info=self.powerline_segment_info) + (' ' * self.nrspaces)
		)


class PowerlinePromptOut(PowerlinePrompt):
	powerline_prompt_type = 'out'
	powerline_is_prompt = False

	def set_p_str(self):
		super(PowerlinePromptOut, self).set_p_str()
		spaces = ' ' * self.powerline_last_in['nrspaces']
		self.p_str += spaces
		self.p_str_nocolor += spaces


class PowerlinePrompt2(PowerlinePromptOut):
	powerline_prompt_type = 'in2'
	powerline_is_prompt = True


class ConfigurableIPythonPowerline(IPythonPowerline):
	def init(self, config_overrides=None, theme_overrides={}, config_paths=None):
		self.config_overrides = config_overrides
		self.theme_overrides = theme_overrides
		self.config_paths = config_paths
		super(ConfigurableIPythonPowerline, self).init(renderer_module='.pre_5')

	def ipython_magic(self, ip, parameter_s=''):
		if parameter_s == 'reload':
			self.reload()
		else:
			raise ValueError('Expected `reload`, but got {0}'.format(parameter_s))

	def do_setup(self, ip, shutdown_hook):
		last_in = {'nrspaces': 0}
		for attr, prompt_class in (
			('prompt1', PowerlinePrompt1),
			('prompt2', PowerlinePrompt2),
			('prompt_out', PowerlinePromptOut)
		):
			old_prompt = getattr(ip.IP.outputcache, attr)
			prompt = prompt_class(self, last_in, old_prompt)
			setattr(ip.IP.outputcache, attr, prompt)
		ip.expose_magic('powerline', self.ipython_magic)
		shutdown_hook.powerline = ref(self)


class ShutdownHook(object):
	powerline = lambda: None

	def __call__(self):
		from IPython.ipapi import TryNext
		powerline = self.powerline()
		if powerline is not None:
			powerline.shutdown()
		raise TryNext()


def setup(**kwargs):
	ip = get_ipython()

	powerline = ConfigurableIPythonPowerline(**kwargs)
	shutdown_hook = ShutdownHook()

	def late_startup_hook():
		powerline.setup(ip, shutdown_hook)
		raise TryNext()

	ip.IP.hooks.late_startup_hook.add(late_startup_hook)
	ip.IP.hooks.shutdown_hook.add(shutdown_hook)
