if not hasattr(__builtins__, 'frozenset'):
  from sets import ImmutableSet as frozenset

import types

import matplotlib.numerix as nx

from compClust.iplot.views import IPlotView

class Mapper(object):

  """
  Base class for PlotView Mapper Classes.
  """

  def __init__(self, plotView):
    """
    All the various mappers operate on an instance of IPlotView, 
    """
    if not isinstance(plotView, IPlotView):
      raise ValueError("Need instance of IPlotView, received %s instead"%
                       (str(plotView)))
    self.__plotView = plotView

  def __get_dataset(self):
    return self.__plotView.getDataset()
  dataset = property(__get_dataset, doc="Return a reference to the dataset")
    
  def getPlotView(self):
    return(self.__plotView)

def scaleList(values, minValue=None, maxValue=None, minReturn=0, maxReturn=1):

  """
  scaleList(values, minReturn=0, maxReturn=1, minValue=None, maxValue=None)

  Given a list of objects, returns a list of values returns a list of
  values scalled between 0 and 1 where minValue -> 0 and maxValue ->
  1).  If values is non-numeric each unique item is mapped arbitrarly
  into the 0..1 range.  Values must be a list of hashable python
  objects

  """

  # get just the unique elements
  labels =  list(frozenset(values))
  numericLabels = 1
  for label in labels:
    labelType = type(label)
    if labelType not in [types.IntType, types.LongType, types.FloatType]:
      numericLabels = 0
      break

  if numericLabels:
    try:
      labels = nx.array(labels)
      data = nx.array(values)
    except:
      numericLabels = 0

  if numericLabels:
    if minValue is None:
      minValue = nx.mlab.min(labels)
    if maxValue is None:
      maxValue = nx.mlab.max(labels)
  else:
    minValue = 0
    maxValue = len(labels)
    labelMap = {}
    for label, count in zip(labels, range(maxValue)):
      labelMap[label]= count
    data  = map(lambda x: labelMap[x], values)

  # perhaps there is a more elegent way of doing this... But this
  # works to scale the data between minValue and maxVale
  data = nx.array(data)
  data = nx.array(map(lambda x: max(x,0), data - minValue))
  data = data.astype('f')
  data = data / ((maxValue-minValue)+.0001)
  data = nx.array(map(lambda x: min(x, 1), data))
  
  # thie maps the data into the minReturn..maxReturn range.
  data = (data * (maxReturn - minReturn)) + minReturn

  return(data)
