########################################
# The contents of this file are subject to the MLX PUBLIC LICENSE version
# 1.0 (the "License"); you may not use this file except in
# compliance with the License.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
# the License for the specific language governing rights and limitations
# under the License.
# 
# The Original Source Code is "compClust", released 2003 September 03.
# 
# The Original Source Code was developed by the California Institute of
# Technology (Caltech).  Portions created by Caltech are Copyright (C)
# 2002-2003 California Institute of Technology. All Rights Reserved.
########################################
#
#       Authors: Lucas Scharenbroich
#                Christopher Hart
# Last Modified: Dec 13 23:41:29 PST 2001
#

import operator
import Numeric

from compClust.mlx.views import SubsetView

##############################################################################
#
# SortedView
#
# Allows a dataset to be sorted in multiple ways
#
##############################################################################

class SortedView(SubsetView):
  """
  Allows for a dataset to be sorted in multiple, flexible ways
  """

  def __init__(self, dataset, name=None):
    all_keys = dataset.getRowKeys() + dataset.getColKeys()
    SubsetView.__init__(self, dataset, all_keys, name=name)
    
  def sort(self, func):
    """calls sortRowsByFunction"""
    self.sortRowsByFunction(func)

  def reset(self):
    """
    Places the dataset back in its original order.
    """
    self.permuteRows(range(self.getNumRows()))

  def sortRowsByFunction(self, func):
    """
    Sort the data row-wise using a numeric fuction.

    The function should take in a Numeric vector and produce a scalar value
    which can be sorted using the python built-in sort() method.  Thus, valid
    return types are strings, integers, or floats.

    If this subroutine becomes a bottleneck, the permuted order of the data
    can be computed externally and the view sorted via the permute() methods.
    """
    
    rows = self.getNumRows()
    
    temp = zip(map(func, self.dataset.getData()), range(rows))
    temp.sort()
    self.permuteRows(map(operator.getitem, temp, [1] * rows))

  def sortColsByFunction(self, func):
    """
    Sort the data column-wise using a numeric fuction.

    The function should take in a Numeric vector and produce a scalar value
    which can be sorted using the python built-in sort() method.  Thus, valid
    return types are strings, integers, or floats.

    If this subroutine becomes a bottleneck, the permuted order of the data
    can be computed externally and the view sorted via the permute() methods.
    """

    cols = self.getNumCols()

    data = Numeric.transpose(self.dataset.getData())
    temp = zip(map(func, data), range(cols))
    temp.sort()
    self.permuteCols(map(operator.getitem, temp, [1] * cols))
    
  def permuteRows(self, plist):
    """
    Set the rows in the view to a particular permutation.

    The plist contains the order in which the data should appear.  It needs to
    have numRows() elements with each element in the range [0:numRows-1].
    Duplicates are not allowed.
    """
    
    self.base_rows = plist

    self.dirty = 1
    self._makeDirtyChildren()
        
  def permuteCols(self, plist):
    """
    Set the columns in the view to a particular permutation.

    The plist contains the order in which the data should appear.  It needs to
    have numCols() elements with each element in the range [0:numCols-1].
    Duplicates are not allowed.
    """
    
    self.base_cols = plist
    
    self.dirty = 1
    self._makeDirtyChildren()
