#!/usr/bin/python
# -*- coding: utf-8 -*-

""" pyforms.gui.Controls.ControlEventsGraph.EventsWidget

"""

from PyQt4 import QtGui, QtCore
from pyforms.gui.Controls.ControlEventsGraph.Track import Track
from pyforms.gui.Controls.ControlEventsGraph.Pointer import Pointer
from pyforms.gui.Controls.ControlEventsGraph.Event import Event
from pyforms import conf
import sys

__author__  = ["Ricardo Ribeiro"]
__credits__ = ["Ricardo Ribeiro"]
__license__ = "MIT"
__version__ = "0.0"
__maintainer__ = "Ricardo Ribeiro"
__email__ = "ricardojvr@gmail.com"
__status__ = "Development"


class EventsWidget(QtGui.QWidget):
    """
    Timeline widget definition to be used in the ControlEventTimeline
    """

    _defautcolor = QtGui.QColor(100, 100, 255)

    def __init__(self, scroll):
        self._is_painting   = False
        self._break_draw    = False #This variable indicates if should continuing drawing the widget or should move foward
    
        super(EventsWidget, self).__init__()
        self._scroll = scroll

        # Set the widget background to white ############################
        palette = self.palette();palette.setColor(self.backgroundRole(), QtCore.Qt.white);self.setPalette(palette)
        #################################################################

        self._max_time      = 0
        self._tracks        = [Track(parent=self)]      # List of tracks
        self._pointer       = Pointer(0, self, scroll)  # Timeline ( greenline )
        self.tracks_height  = 30                        # Height in pixels
        self.scale          = conf.CONTROL_EVENTS_GRAPH_DEFAULT_SCALE
        

    ##########################################################################
    #### HELPERS/FUNCTIONS ###################################################
    ##########################################################################

    def clean(self):
        #Clean all events
        for track in self._tracks: track.clear()
        del self._tracks[:]
        self._tracks = []
        self._break_draw = True and self._is_painting
        self.repaint()


    def add_track(self):
        #Add a new track
        self._tracks.append( Track(parent=self) )
        self.setMinimumHeight( self.which_top( len(self._tracks) ) )
        return self._tracks[-1]

    def add_event(self, begin, end, title='', track=0, color="#FFFF00"):
        """Adds an event."""
        
        period = Event(begin, end, 
            title         =   title, 
            parentWidget  =   self,
            color         =   color
        )

        if self._max_time<end: self._max_time=end
        # Create new tracks in case the variable track does not exists
        if len(self._tracks)<=track:
            for i in range( len(self._tracks), track+1 ):  self.add_track()
        #################################################

        end_pixel = end/self._scale
        if end_pixel>self._scroll.maximum(): self._scroll.setMaximum( end_pixel )

        return self._tracks[track].add_period(period)



    def __check_current_time_is_visible(self, current_time):
        """
        This function check if the current_time is visible to the user.
        """

       
        scroll_limit = ( self._scroll.sliderPosition() + self.width() )*self._scale

        if current_time > scroll_limit:
            self._scroll.setMaximum( current_time/self._scale )
            self._scroll.setSliderPosition( current_time/self._scale- self.width() )
        if current_time < (self._scroll.sliderPosition()*self._scale):
            self._scroll.setSliderPosition(current_time/self._scale)
      

    def which_track(self, y): 
        #Return the track index which collide with the Y coordenate
        return (y - 20) // self.tracks_height

    def which_top(self, track): 
        #Return the Y coordenate where the track index start
        return track * self.tracks_height + 20

    ##########################################################################
    #### DRAW FUNCTIONS ######################################################
    ##########################################################################


    def paintEvent(self, e):
        self._is_painting = True
        super(EventsWidget, self).paintEvent(e)

        painter = QtGui.QPainter()
        painter.begin(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setFont(QtGui.QFont('Decorative', 8))

        slider_pos = self._scroll.sliderPosition()
        start   = slider_pos*self._scale
        end     = start + self.width()*self._scale
        
        for i, track in enumerate(self._tracks):
            if self._break_draw: break
            track.draw_periods(painter, start, end, track_index=i, left_shift=-self._scroll.sliderPosition(), scale=self._scale)

        # Draw only from pixel start to end
        painter.setPen(QtCore.Qt.DashLine)
        painter.setOpacity(0.3)

        #print('Draw', start, end, self._scale, self._scroll.sliderPosition(), self.width())
      
    
        # Draw vertical lines
        for x in range(start - (start % (100*self._scale)), end, 100*self._scale):
            x2draw = (x-slider_pos*self._scale)//self._scale
            painter.drawLine(x2draw, 20, x2draw, self.height())
            string = str(x)
            boundtext = painter.boundingRect(QtCore.QRectF(), string)
            painter.drawText(x2draw-boundtext.width()/2,15,  string)
        
        for index, track in enumerate(self._tracks):
            top = self.which_top(index)
            painter.drawLine(0, top, self.width(), top)
            painter.drawText(10,top+15, track.title)
        painter.setOpacity(1.0)
            

        self._pointer.draw(painter, left_shift=-slider_pos, scale=self._scale) #Draw the time pointer
        painter.end()

        self._break_draw = False
        self._is_painting = False



    ##########################################################################
    #### PROPERTIES ##########################################################
    ##########################################################################

    @property
    def scale(self): return self._scale
    @scale.setter
    def scale(self, value): 
        self._scale = value
        self._scroll.setMaximum( self._max_time/self._scale )
        
        
    
    @property
    def scroll(self): return self._scroll

    @property
    def position(self): return self._pointer._position
    @position.setter
    def position(self, position):
        self._pointer._position = position
        self._break_draw = True and self._is_painting
        
        if (position/self._scale)>=sys.maxsize:  self.scale += 1
        
        #######################################################################
        # Check if the current time position is inside the scroll
        # if is not in, update the scroll position
        self.__check_current_time_is_visible(position)
        #######################################################################
        self.repaint()

    @property
    def color(self): return self._defautcolor

    @color.setter
    def color(self, value): self._defautcolor = value

    @property
    def tracks_height(self): return self._tracks_height
    @tracks_height.setter
    def tracks_height(self, value):
        self._tracks_height = value
        new_height = len(self.tracks)*value + 20
        if new_height>self.height(): self.setMinimumHeight(new_height)
        self._break_draw = True and self._is_painting
        self.repaint()
    

    @property
    def tracks(self): return self._tracks




















    ##########################################################################
    #### IMPORT AND EXPORT DATA ##############################################
    ##########################################################################

    def import_csv(self, csvfileobject):
        """
        Extracts info from a file object and stores it in memory in
        order to display it on the timeline.

        Refer to the `export` method to learn about input file format
        and structure.
        """
        # Clear previously stored info
        self._tracks = []
        self._selected = None

        for row in csvfileobject:
            if row[0] == "T":
                track = self.add_track()
                track.properties = row
            elif row[0] == "P":
                event = self.add_event(0,1,'-')
                event.properties = row
                
            

    def export_csv(self, csvfileobject):
        """
        Processes all timeline data in an arranged format to be written
        in a CSV file.


        Current file structure:
        =======================

        --- CSV FILE BEGIN ---
        Track info line
        Event info line
        Event info line
        ...
        Track info line
        Event info line
        Event info line
        ...
        Track info line
        Event info line
        Event info line
        ...
        --- CSV FILE END ---


        Track info line format:
        =======================

        | T | Total # of events in this track |  |  | Color | Label |


        Event info line format:
        =======================

        | P | Lock status | Begin frame | End frame | Comment | Color |  |
        """
        for index, track in enumerate(self._tracks):
            csvfileobject.writerow(track.properties)
            for delta in track.periods: 
                csvfileobject.writerow(delta.properties)