#! /usr/bin/env python

import kivy
kivy.require('1.8.0')

from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.utils import get_color_from_hex as rgb

from kivy.graphics import Line, RenderContext, Color

import sys
import ast
import time
import threading
from functools import partial

from kivy_garden.graph import Graph, Plot

class LinePlot(Plot):
    '''LinePlot draws using a standard Line object.
    '''

    '''Args:
    line_width (float) - the width of the graph line
    '''
    def __init__(self, **kwargs):
        self._line_width = kwargs.get('line_width', 1)
        self._id = kwargs.get('id')
        self.color = kwargs.get('color', [1, 1, 1, 1])
        super(LinePlot, self).__init__()

        self.segmentLine = {}
        self.freeLines = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]

    def create_drawings(self):
        self._grc = RenderContext(
                use_parent_modelview=True,
                use_parent_projection=True)
        with self._grc:
            self._gcolor = Color(*self.color)
            self._gline = [
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round'),
                Line(points=[], cap='none', width=self._line_width, joint='round')
            ]

        return [self._grc]

    def max_value(self, inputlist):
        return max([sublist[0] for sublist in inputlist])

    def iterate_points(self):
        '''Iterate on all the points adjusted to the graph settings
        '''
        params = self._params
        funcx = log10 if params['xlog'] else lambda x: x
        funcy = log10 if params['ylog'] else lambda x: x
        xmin = funcx(params['xmin'])
        xmax = funcx(params['xmax'])
        ymin = funcy(params['ymin'])
        size = params['size']


        try:
            ratiox = (size[2] - size[0]) / float(funcx(params['xmax']) - xmin)
            ratioy = (size[3] - size[1]) / float(funcy(params['ymax']) - ymin)
        except ZeroDivisionError:
            return

        for idx, segment in enumerate(self.points):
            # For existing lines, check if need to prune (max x < graph's xmin)
            if idx in self.segmentLine:
                max_x = max([sublist[0] for sublist in segment])
                if (max_x + 50) < xmin:
                    gline_idx = self.segmentLine[idx]
                    self._gline[gline_idx].points = []

                    self.freeLines.append(gline_idx)
                    del self.segmentLine[idx]
                    del self.points[idx]
                    continue

            min_x = min([sublist[0] for sublist in segment])
            if min_x > xmax:
                continue

            for x, y in segment:
                yield (
                    idx,
                    (funcx(x) - xmin) * ratiox + size[0],
                    (funcy(y) - ymin) * ratioy + size[1])

    def draw(self, *args):
        super(LinePlot, self).draw(*args)
        # flatten the list
        points = {}

        for idx, x, y in self.iterate_points():
            if idx not in points:
                points[idx] = []
            points[idx] += [x, y]

        for keys in points.keys():
            if keys in self.segmentLine:
                gline_idx = self.segmentLine[keys]
                self._gline[gline_idx].points = points[keys]
            else:
                if (len(self.freeLines) > 0):
                    # print self._id, keys,'reusing free ine', self.freeLines, points[keys]
                    # reuse a free line
                    free_line_idx = self.freeLines.pop()
                    self._gline[free_line_idx].points = points[keys]
                    self.segmentLine[keys] = free_line_idx


# end of file

