import time
import random

from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, FadeTransition
from kivy.uix.screenmanager import Screen as BaseScreen
from kivy.uix.relativelayout import RelativeLayout
import kivy.uix.screenmanager

from kivy.properties import StringProperty, NumericProperty, BooleanProperty, ObjectProperty, OptionProperty

class NodeBehavior(object):
    '''Screen is an element intended to be used with a :class:`ScreenManager`.
    Check module documentation for more information.
    :Events:
        `on_pre_enter`: ()
            Event fired when the screen is about to be used: the entering
            animation is started.
        `on_enter`: ()
            Event fired when the screen is displayed: the entering animation is
            complete.
        `on_pre_leave`: ()
            Event fired when the screen is about to be removed: the leaving
            animation is started.
        `on_leave`: ()
            Event fired when the screen is removed: the leaving animation is
            finished.
    .. versionchanged:: 1.6.0
        Events `on_pre_enter`, `on_enter`, `on_pre_leave` and `on_leave` were
        added.
    '''

    name = StringProperty('')
    '''
    Name of the screen which must be unique within a :class:`ScreenManager`.
    This is the name used for :attr:`ScreenManager.current`.
    :attr:`name` is a :class:`~kivy.properties.StringProperty` and defaults to
    ''.
    '''

    manager = ObjectProperty(None, allownone=True)
    ''':class:`ScreenManager` object, set when the screen is added to a
    manager.
    :attr:`manager` is an :class:`~kivy.properties.ObjectProperty` and
    defaults to None, read-only.
    '''

    transition_progress = NumericProperty(0.)
    '''Value that represents the completion of the current transition, if any
    is occurring.
    If a transition is in progress, whatever the mode, the value will change
    from 0 to 1. If you want to know if it's an entering or leaving animation,
    check the :attr:`transition_state`.
    :attr:`transition_progress` is a :class:`~kivy.properties.NumericProperty`
    and defaults to 0.
    '''

    transition_state = OptionProperty('out', options=('in', 'out'))
    '''Value that represents the state of the transition:
    - 'in' if the transition is going to show your screen
    - 'out' if the transition is going to hide your screen
    After the transition is complete, the state will retain it's last value (in
    or out).
    :attr:`transition_state` is an :class:`~kivy.properties.OptionProperty` and
    defaults to 'out'.
    '''

    __events__ = ('on_pre_enter', 'on_enter', 'on_pre_leave', 'on_leave')

    interval = NumericProperty(0.0)

    def on_pre_enter(self, *args):
        pass

    def on_enter(self, *args):
        pass

    def on_pre_leave(self, *args):
        pass

    def on_leave(self, *args):
        pass

    def __repr__(self):
        return '<Screen name=%r>' % self.name

class Node(NodeBehavior, RelativeLayout):
    pass

kivy.uix.screenmanager.Screen = NodeBehavior
Screen = Node

class Fader(ScreenManager):
    interval = NumericProperty(5.0)
    view_start = NumericProperty(5.0)
    show_progress = BooleanProperty(True)

    _interval = None
    _progress_interval = None

    def __init__(self, **kwargs):
        super(Fader, self).__init__(**kwargs)
        if 'transition' not in kwargs:
            self.transition = FadeTransition()

        from kivy.graphics import Color, Rectangle
        with self.canvas.after:
            Color(1., 1., 1., 0.2)
            self.progress_rect = Rectangle(pos=self.pos, size=(0, 0))

        self.on_show_progress(None, self.show_progress)
        self.rotate_screens(0)

    def update_rect(self, *args):
        if not self.show_progress:
            return
        progress = ((time.time() - self.view_start)/self.current_interval)

        self.progress_rect.pos = self.pos
        self.progress_rect.size = (self.size[0] * progress, 10)

    def on_show_progress(self, instance, value):
        if self._progress_interval:
            self._progress_interval.cancel()
            self._progress_interval = None

        if value:
            self._progress_interval = Clock.schedule_interval(self.update_rect, 0)

        self.progress_rect.size = (0, 0)

    def on_interval(self, instance, value):
        if self._interval:
            self._interval.cancel()
        self._interval = Clock.schedule_once(
            self.rotate_screens, self.current_interval)

    def add_widget(self, screen):
        """Just wrap everything in Screen"""
        if not isinstance(screen, NodeBehavior):
            print ('Wrapping!', screen)
            s = Node()
            s.add_widget(screen)
            screen = s
        return super(Fader, self).add_widget(screen)

    def generate_ids(self):
        """Generates random IDs for all screens without set name"""
        for i, c in enumerate(self.screens):
            if not c.name:
                c.name = 'screen_%i_%s' % (i, type(c))

    def rotate_screens(self, dt):
        self.generate_ids()
        self.current = self.next()
        self.view_start = time.time()

        self._interval = Clock.schedule_once(
            self.rotate_screens, self.current_interval)

    @property
    def current_interval(self):
        if self.current_screen and self.current_screen.interval:
            return self.current_screen.interval
        return self.interval
