########################################
# 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.
########################################

"""
The AlgorithmFactory returns a clustering algorithm instace based on either
an instance of, or the name of the algorithm.
"""

import imp
import types

from compClust.util.TimeStampedPrintStream import TimeStampedPrintStream

#
# MESSAGE_STREAM
#

MESSAGE_STREAM = TimeStampedPrintStream("%Y-%b-%d %H:%M: Factory: ")

def newInstanceByType(algorithm):
  """
  Returns a new instance of an algorithm based on the type of the the object.
  """

  from compClust.mlx.wrapper import *

  if isinstance(algorithm, DiagEM):
    return DiagEM()
  elif isinstance(algorithm, FullEM):
    return FullEM()
  elif isinstance(algorithm, Hierarchical):
    return Hierarchical()
  elif isinstance(algorithm, HutSOM):
    return HutSOM()
  elif isinstance(algorithm, KMeans):
    return KMeans()
  elif isinstance(algorithm, MCCV):
    return MCCV()
  elif isinstance(algorithm, Monkey):
    return Monkey()
  elif isinstance(algorithm, TSplit):
    return TSplit()
  elif isinstance(algorithm, XClust):
    return XClust()
  else:
    MESSAGE_STREAM.write(" Unknown algorithm instance type")
    
def newInstanceByName(name):
  """
  Returns a new instance of an algorithm based on the name given.  The
  recognized names are:

    * 'DiagEM'

    * 'FullEM'

    * 'Hierarchical'

    * 'HutSOM'

    * 'KMeans'

    * 'MCCV'

    * 'Monkey'

    * 'TSplit'

    * 'XClust'

  The names are case-insensitive.
  """

  from compClust.mlx.wrapper import *
  
  uname = name.upper()
  
  if uname == "DIAGEM":
    return DiagEM()
  elif uname == "FULLEM":
    return FullEM()
  elif uname == "HIERARCHICAL":
    return Hierarchical()
  elif uname == "HUTSOM":
    return HutSOM()
  elif uname == "KMEANS":
    return KMeans()
  elif uname == "MCCV":
    return MCCV()
  elif uname == "MONKEY":
    return Monkey()
  elif uname == "TSPLIT":
    return TSplit()
  elif uname == "XCLUST":
    return XClust()
  else:
    MESSAGE_STREAM.write(" Unknown algorithm name: " + name)
     
   
def loadWrapperClass(wrapper_name):
  """class = load_wrapper_class(wrapper_name)

  Attempts to load the wrapper class of name 'wrapper_name' from
  the compClust.mlx.wrapper.'wrapper_name' package.
  """

  from compClust.mlx.interfaces import IML_Algorithm
  
  algorithm_class = None
  
  #
  # FIXME: Should we have an exception handler?
  # FIXME: we can't really do anything about a failure.
  #
  
  module_info = imp.find_module(wrapper_name, compClust.mlx.wrapper.__path__)
  module_stream, module_name, module_description = module_info
  algorithm_module = imp.load_module(wrapper_name,
                                     module_stream,
                                     module_name,
                                     module_description)
  algorithm_class = algorithm_module.__dict__[wrapper_name]
  
  
  if not issubclass(algorithm_class, IML_Algorithm):
    raise  ValueError("Parameter 'algorithm' must be for a "
                      "subclass of ML_algorithm. %s was not." % (alg_name))
  
  return algorithm_class

