from compClust.iplot.mappers.Mapper import Mapper

from compClust.mlx import labelings

class BindingsMapper(Mapper):

  def addBindings(self):

    """
    addBindings(self)

    This function if implimented adds novel event bindings to the
    plotView after the plot is generated.  The IPlot graph class has a
    few default bindings which will be left, unless overriden.

    """

    pass
    
class SimpleBindingsMapper(BindingsMapper):

  """
  Provides some convient acces to RowAnnotations
  """

  def addBindings(self):

    self.__plot = self.getPlotView()._getPlot()
    self.__annotationMapper = self.getPlotView().getAnnotationMapper()
    self.__plot.element_bind('all', '<Button-1>', self.displayAnnotations)
    self.__activeElements = {}

  def displayAnnotations(self, event):

    """
    displayAnnotations(self, event)

    Overides the IPlot display information to display both the primary
    and secondary information in the upper right hand corner.

    """

    closest_widget = event.widget.element_closest(event.x, event.y)
    if closest_widget is None:
      return
    index = closest_widget['index']
    x = event.widget.element_closest (event.x, event.y)['x']
    y = event.widget.element_closest (event.x, event.y)['y']
    primaryName   = event.widget.element_closest (event.x, event.y)['name'].split('__')[0]

    primaryLabeling   = self.__annotationMapper.getPrimaryLabeling()
    secondaryLabeling = self.__annotationMapper.getSecondaryLabeling()
    if primaryLabeling is None:
      row = int(primaryName)
    else:
      row = primaryLabeling.getRowsByLabel(primaryName)[0]
    if secondaryLabeling is not None:
      try:
        secondaryName = reduce(lambda x,y: str(x)+str(y), secondaryLabeling.getLabelsByRow(row))
      except:
        pass
    else:
      secondaryName = ''

    status = "%s: (%3.2f, %3.2f) -- %s "%(primaryName.strip(), x, y, secondaryName.strip())

    coords = (self.__plot.xaxis_limits()[0], self.__plot.yaxis_limits()[1])
    self.__plot.marker_configure('selection', coords= coords, background="lightblue", text=status, anchor='w', under=0, hide=0)
    #self.__plot.marker_bind('selection', '<Control-Button-1>', lambda ev, row=row: self.displayLabelings(ev, row))
    #self.__plot.marker_bind('selection', '<Control-Button-1>', lambda ev, row=row: SummaryWindow(self.getPlotView(), row, parent=self.__plot.master))
    self.__plot.marker_bind('selection', '<Control-Button-1>', lambda ev, row=row: SummaryWindow(self.getPlotView(), row))    
    self.__plot.marker_bind('selection', '<Button-1>', self.hideSelection)

  def hideSelection(self, event):

    """
    hideDisplay(self, event)
    """

    # this hack makes the labels go away before a plot referesh
    self.__plot.marker_configure('selection',  coord=(-100000,-1000000))
    self.__plot.marker_configure('selection', under=1, hide=1)

  def displayLabelings(self, event, row):

    """
    displayLabelings(self, event)

    This little guy pops up a dialog with all the labelings attached
    to the dataset and what that point has been labeled as
    """

    ds = self.getPlotView().getDataset()
    primaryLabeling = self.__annotationMapper.getPrimaryLabeling()
    if primaryLabeling is None:
      name = str(row)
    else:
      name = primaryLabeling.getLabelsByRow(row)[0]

    # set up a new scrolled window for the display
    win = Tkinter.Toplevel()
    sf = Pmw.ScrolledFrame(win,
                           labelpos = 'n', label_text = 'Labels for %s'%(name),
                           usehullsize = 1,
                           hull_width = 700,
                           hull_height = 500,
                           horizflex= 'expand',
                           vertflex = 'expand'
                           )
    sf.pack(fill='both', expand=1)
    frame = sf.interior()
    gridRow = 0
    for labeling in ds.getLabelings():
      tkLabel = Tkinter.Label(frame, text=str(labeling), anchor='e')
      tkLabel.grid(row = gridRow, col = 0)
      labels = labeling.getLabelsByRow(row)
      gridCol = 1
      for label in labels:
        # this block is a little dirty, but attaches the button state to each button and makes sure that
        # the callback is notified of the current button state.
        v = Tkinter.IntVar()
        button = Tkinter.Checkbutton(frame,
                                     text=str(label),
                                     anchor='e',
                                     variable = v)
        button.var = v
        button.configure(command=lambda labeling=labeling, label=label, state=button.var:
                         self.activateMembers(labeling, label, state))

        button.grid(row=gridRow, column= gridCol)
        gridCol +=1
      gridRow +=1

  def activateMembers(self, labeling, label, state):

    """
    activateMembers(self, labeling, label, button)

    using the BLT selection feature, toggle the selection of all
    elements which are marked by the label in labeling.
    """

    plot = self.getPlotView()._getPlot()
    rows = labeling.getRowsByLabel(label)
    primaryLabeling   = self.__annotationMapper.getPrimaryLabeling()
    if primaryLabeling is None:
      elements = rows
    else:
      elements = map(lambda x:primaryLabeling.getLabelsByRow(x)[0], rows)

    if state.get() == 1:
      for element in elements:
        plot.element_activate(element)
        if self.__activeElements.has_key(element):
          self.__activeElements[element] += 1
        else:
          self.__activeElements[element] = 1

    else:
      for element in elements:
        if self.__activeElements.get(element) <= 1:
          plot.element_deactivate(element)
          del(self.__activeElements[element])
        else:
          self.__activeElements[element] -=  1         
        
