"""WrapperBuilder provides a convienent way to collect composable
clustering algorithms together that use the WrapperParamters interface.

For instance if you want to do a MultiRun sweep over k and seed for
DiagEM, this should hopefully make doing such a thing easier.
"""

from compClust.mlx.ML_Algorithm import ML_Algorithm, ML_Composable_Algorithm
from compClust.util.CCWarnings import DebugWarning, warn

class WrapperBuilder:
  def __init__(self, dataset):
    self.dataset = dataset
    self.algorithms = []

  def algorithm_names(self):
    """Return list of algorithm names in this wrapper builder instance."""
    names = []
    for alg in self.algorithms:
      names.append(alg.name)
    return names
  
  def append(self, algorithm):
    """Add an algorithm to the wrapper chain
    """
    if issubclass(algorithm, ML_Algorithm):
       algorithm = algorithm(self.dataset)
    if not isinstance(algorithm, ML_Algorithm):
      raise ValueError("Algorithm must be a subclass of ML_Algorithm")
    
    self.algorithms.append(algorithm)

  def isFinalized(self):
    """Do we have a simple algorithm added.

    Return true if the chain has a simple algorithm (aka not a composible
    algorithm like MultiRun or Hierarchical) as the last algorithm.
    """
    if len(self.algorithms) == 0:
      return False
    else:
      return not isinstance(self.algorithms[-1], ML_Composable_Algorithm)
                                           
  def __iter__(self):
    return self.algorithms.__iter__()
                                              
  def __getitem__(self, key):
    """Get a particular algorithm
    """
    return self.algorithms[key]

  def __len__(self):
    """Return the number of algorithms attached to this WrapperBuilder chain.
    """
    return len(self.algorithms)

  def getLabeling(self):
    """Return labeling of the finish nested clustering
    """
    return self.algorithms[0].getLabeling()
  
  def run(self):
    """Run the algorithm change
    """
    if not self.validate():
      raise ValueError("Parameters are not set correctly")

    for i in xrange(len(self.algorithms)-1):
      warn("adding %s to %s" % (self.algorithms[i+1], self.algorithms[i]), DebugWarning)
      self.algorithms[i].algorithm = self.algorithms[i+1]

    return self.algorithms[0].run()

  def validate(self):
    """Make sure that the algorithms have a 
    """
    for a in self.algorithms:
      if not a.validate():
        return False
    return True
      