'''
gazeEventsDF has labelled data for all trials
When grabbing trialSourceDict, I must filter to grab data only from the selected trial
'''

from __future__ import division
import sys
import bokeh.plotting as bkP
import bokeh.models as bkM
import numpy as np

bkP.output_server()


class DataSelector:

    def __init__(self, user, fileTime):

        self.trialNum = 0
        self.nextBoxID = 0

        self.trialSourceDict = self.init_trial_datasources()

        self.make_trial_figure()
        self.add_glyphs()

        self.fig.tool_events.on_change('geometries', self.boxCallback)
        self.fig.tool_events.on_change('selected', self.tap_callback)

        from bokeh.io import curdoc
        curdoc().add_root(self.fig)

        from bokeh.client import push_session

        self.session = push_session(curdoc())
        self.session.show()  # open the document in a browser

        curdoc().add_periodic_callback(self.on_timer, 5000)
        self.session.loop_until_closed()  # run forever

    def on_timer(self):
        print self.undefinedSource.data

    def add_glyphs(self):
        '''
        Create a dictionary of glyphs for rendering
        :return: a dictionary of glyphs
        '''

        self.initRectGlyph = bkM.Rect(x='x',
                                 y='y',
                                 width='width',
                                 height='height',
                                 fill_alpha=0.6,
                                 fill_color='gray')

        self.undefinedGlyph = bkM.Rect(x='x',
                                  y='y',
                                  width='width',
                                  height='height',
                                  fill_alpha=0.6,
                                  fill_color='gray')

        self.selectedGlyph = bkM.Rect(x='x',
                                 y='y',
                                 width='width',
                                 height='height',
                                 fill_alpha=0.6,
                                 fill_color='cyan')

        self.fig.add_glyph(self.undefinedSource, self.undefinedGlyph,
                           selection_glyph=self.selectedGlyph,
                           nonselection_glyph=self.undefinedGlyph,
                           name='undefined')

    def init_trial_datasources(self):

        '''
        Creates a dictionary of datasources for this trial.
        Keys: undefinedSource, fixSource, sacSource, purSource

        :return: a dictionary of ColumnDataSources for this trial
        '''

        self.undefinedSource = bkM.ColumnDataSource(
            data=dict(x=[], y=[], width=[], height=[], startTime=[], endTime=[], boxID=[], trialNum=[]))

    def make_trial_figure(self): #trialNum, sessionDict, trialSourceDict, glyphDict):
        '''
        Create figure with velocity trace for the current trialNum
        :return: a bokeh figure
        '''

        x = np.deg2rad(range(720))
        y = 1 + np.sin(x)

        self.fig = bkP.figure(width=800, height=350,x_range=[0,13], y_range=(0,2),tools= [])

        self.fig.line(x, y, line_width=4, name='aLine')

        self.fig.xaxis.axis_label = 'time'
        self.fig.yaxis.axis_label = 'position'

        self.fig.plot_width = 800

        self.fig.tools = []

        # TODO: Remove falseRenderer.  It is a hack
        # I dont' want ot use the boxselect tool selection/hit testing.
        # Ideally, I woudl turn selection off.  It turns out that the best way to do this is to set
        # renderers explicitly.  It does not like an empty list, so I give it this single value.
        falseRenderer = self.fig.circle(x=1000, y=1000)

        self.fig.add_tools(bkM.BoxSelectTool(dimensions=["width"], renderers=[falseRenderer]))

        self.fig.add_tools(bkM.PanTool(dimensions=["width"]))
        self.fig.add_tools(bkM.WheelZoomTool(dimensions=["width"]))
        self.fig.add_tools(bkM.TapTool())

    # Every box has a custom numerical ID
    def boxCallback(self,attr,old,new):
        '''
        A callback function for the box select tool
        '''

        # Test to see if the new datasource has geometry
        if (('y1' in new[0].keys()) == False):
            print 'No geometry'
            return

        width = new[0]['x1'] - new[0]['x0']
        height = new[0]['y1'] - new[0]['y0']
        x = new[0]['x0'] + width / 2
        y = new[0]['y0'] + height / 2

        startTime = new[0]['x0']
        endTime = new[0]['x1']

        new_data = dict(self.undefinedSource.data)

        new_data['x'].append(x)
        new_data['y'].append(y)
        new_data['width'].append(width)
        new_data['height'].append(height)
        new_data['startTime'].append(startTime)
        new_data['endTime'].append(endTime)
        new_data['boxID'].append(self.nextBoxID)
        new_data['trialNum'].append(self.trialNum)

        # update entire .data in one go
        self.undefinedSource.data = new_data

        # explicit trigger
        self.undefinedSource.trigger('data', new_data, new_data)


        self.selectedBoxID = self.nextBoxID
        self.nextBoxID += 1

        #k.execute("push_notebook()");


    def tap_callback(self, attr, old, new):
        print 'Inside tap callback'

if __name__ == "__main__":

    theDataSelector = DataSelector('gdj', '2016-4-19-14-4')
