'''
Damped scroll effect
====================

.. versionadded:: 1.7.0

This damped scroll effect will use the
:attr:`~kivy.effects.scroll.ScrollEffect.overscroll` to calculate the scroll
value, and slows going back to the upper or lower limit.

'''

__all__ = ('DampedScrollEffect',)


from kivy.effects.scroll import ScrollEffect
from kivy.properties import NumericProperty, BooleanProperty
from kivy.metrics import sp


class DampedScrollEffect(ScrollEffect):
    '''DampedScrollEffect class. See the module documentation for more
    information.
    '''

    edge_damping = NumericProperty(0.25)
    '''Edge damping.

    :attr:`edge_damping` is a :class:`~kivy.properties.NumericProperty` and
    defaults to 0.25
    '''

    spring_constant = NumericProperty(2.0)
    '''Spring constant.

    :attr:`spring_constant` is a :class:`~kivy.properties.NumericProperty` and
    defaults to 2.0
    '''

    min_overscroll = NumericProperty(.5)
    '''An overscroll less than this amount will be normalized to 0.

    .. versionadded:: 1.8.0

    :attr:`min_overscroll` is a :class:`~kivy.properties.NumericProperty` and
    defaults to .5.
    '''

    round_value = BooleanProperty(True)
    '''If True, when the motion stops, :attr:`value` is rounded to the nearest
    integer.

    .. versionadded:: 1.8.0

    :attr:`round_value` is a :class:`~kivy.properties.BooleanProperty` and
    defaults to True.
    '''

    def update_velocity(self, dt):
        if abs(self.velocity) <= self.min_velocity and self.overscroll == 0:
            self.velocity = 0
            # why does this need to be rounded? For now refactored it.
            if self.round_value:
                self.value = round(self.value)
            return

        total_force = self.velocity * self.friction * dt / self.std_dt
        if abs(self.overscroll) > self.min_overscroll:
            total_force += self.velocity * self.edge_damping
            total_force += self.overscroll * self.spring_constant
        else:
            self.overscroll = 0

        stop_overscroll = ''
        if not self.is_manual:
            if self.overscroll > 0 and self.velocity < 0:
                stop_overscroll = 'max'
            elif self.overscroll < 0 and self.velocity > 0:
                stop_overscroll = 'min'

        self.velocity = self.velocity - total_force
        if not self.is_manual:
            self.apply_distance(self.velocity * dt)
            if stop_overscroll == 'min' and self.value > self.min:
                self.value = self.min
                self.velocity = 0
                return
            if stop_overscroll == 'max' and self.value < self.max:
                self.value = self.max
                self.velocity = 0
                return
        self.trigger_velocity_update()

    def on_value(self, *args):
        scroll_min = self.min
        scroll_max = self.max
        if scroll_min > scroll_max:
            scroll_min, scroll_max = scroll_max, scroll_min
        if self.value < scroll_min:
            self.overscroll = self.value - scroll_min
        elif self.value > scroll_max:
            self.overscroll = self.value - scroll_max
        else:
            self.overscroll = 0
        self.scroll = self.value

    def on_overscroll(self, *args):
        self.trigger_velocity_update()

    def apply_distance(self, distance):
        os = abs(self.overscroll)
        if os:
            distance /= 1. + os / sp(200.)
        super(DampedScrollEffect, self).apply_distance(distance)
