# -*- coding: utf-8 -*-

from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ListProperty, BooleanProperty
from kivy.animation import Animation
from theming import ThemableBehavior

Builder.load_string('''
<MDSpinner>:
	canvas.before:
		PushMatrix
		Rotate:
			angle: self._rotation_angle
			origin: self.center
	canvas:
		Color:
			rgba: self.color
			a: self._alpha
		Line:
			circle: self.center_x, self.center_y, self.width / 2, \
			self._angle_start, self._angle_end
			cap: 'square'
			width: dp(2)
	canvas.after:
		PopMatrix

''')


class MDSpinner(ThemableBehavior, Widget):
	""":class:`MDSpinner` is an implementation of the circular progress
	indicator in Google's Material Design.

	It can be used either as an indeterminate indicator that loops while
	the user waits for something to happen, or as a determinate indicator.

	Set :attr:`determinate` to **True** to activate determinate mode, and
	:attr:`determinate_time` to set the duration of the animation.
	"""

	determinate = BooleanProperty(False)
	""":attr:`determinate` is a :class:`~kivy.properties.BooleanProperty` and
	defaults to False
	"""

	determinate_time = NumericProperty(2)
	""":attr:`determinate_time` is a :class:`~kivy.properties.NumericProperty`
	and defaults to 2
	"""

	active = BooleanProperty(True)
	"""Use :attr:`active` to start or stop the spinner.

	:attr:`active` is a :class:`~kivy.properties.BooleanProperty` and
	defaults to True
	"""

	color = ListProperty([])
	""":attr:`color` is a :class:`~kivy.properties.ListProperty` and
	defaults to 'self.theme_cls.primary_color'
	"""

	_alpha = NumericProperty(0)
	_rotation_angle = NumericProperty(360)
	_angle_start = NumericProperty(0)
	_angle_end = NumericProperty(8)

	def __init__(self, **kwargs):
		super(MDSpinner, self).__init__(**kwargs)
		self.color = self.theme_cls.primary_color
		self._alpha_anim_in = Animation(_alpha=1, duration=.8, t='out_quad')
		self._alpha_anim_out = Animation(_alpha=0, duration=.3, t='out_quad')
		self._alpha_anim_out.bind(on_complete=self._reset)

		if self.determinate:
			self._start_determinate()
		else:
			self._start_loop()

	def _start_determinate(self, *args):
		self._alpha_anim_in.start(self)

		_rot_anim = Animation(_rotation_angle=0,
		                      duration=self.determinate_time * .7,
		                      t='out_quad')
		_rot_anim.start(self)

		_angle_start_anim = Animation(_angle_end=360,
		                              duration=self.determinate_time,
		                              t='in_out_quad')
		_angle_start_anim.bind(on_complete=lambda *x: \
			self._alpha_anim_out.start(self))

		_angle_start_anim.start(self)

	def _start_loop(self, *args):
		if self._alpha == 0:
			_rot_anim = Animation(_rotation_angle=0,
			                      duration=2,
			                      t='linear')
			_rot_anim.start(self)

		self._alpha = 1
		self._alpha_anim_in.start(self)
		_angle_start_anim = Animation(_angle_end=self._angle_end + 270,
		                              duration=.6,
		                              t='in_out_cubic')
		_angle_start_anim.bind(on_complete=self._anim_back)
		_angle_start_anim.start(self)

	def _anim_back(self, *args):
		_angle_back_anim = Animation(_angle_start=self._angle_end - 8,
		                             duration=.6,
		                             t='in_out_cubic')
		_angle_back_anim.bind(on_complete=self._start_loop)

		_angle_back_anim.start(self)

	def on__rotation_angle(self, *args):
		if self._rotation_angle == 0:
			self._rotation_angle = 360
			if not self.determinate:
				_rot_anim = Animation(_rotation_angle=0,
				                      duration=2)
				_rot_anim.start(self)

	def _reset(self, *args):
		Animation.cancel_all(self, '_angle_start', '_rotation_angle',
		                     '_angle_end', '_alpha')
		self._angle_start = 0
		self._angle_end = 8
		self._rotation_angle = 360
		self._alpha = 0
		self.active = False

	def on_active(self, *args):
		if not self.active:
			self._reset()
		else:
			if self.determinate:
				self._start_determinate()
			else:
				self._start_loop()
