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

"""
Find where all of the compClust support packages are.

compClust.config is going to be the central module responsible 
for locating where all of the compClust support packages are. 
This should help manage finding the template files, examples, and
clustering algorithms when both running from the source directory 
and when installed.

"""

from ConfigParser import RawConfigParser as ConfigParser
import os
import sys

# What do we need to find
# clustering algorithms ['kmeans', 'diagem']
# Template files ['cluster.xml', ]
# example data ['ChoCellCycling.dat', 'cho.lab']
# documentation ['compclusttk_tutorial']
# in which situations do we need to find them
#   running out of source directory
#   installed on linux box
#   installed on os x box
#   installed on windows box

class Config:
  """
  Provide an abstract way of identifying where our components are.
  
  The properties mechanism provides a nice way of calling hidden
  functions to query our installation state
  """

  def __init__(self, base_dir=None, installing=False):
    """Construct a config object
    
    @param{base_dir} sets the default root for our installation variables
    this is mostly for testing purposes.
    """
    import compClust
    
    self.__installing = installing
    # collect information out of ini file
    parser = ConfigParser()
    parser.read(['compclust.ini', os.path.expanduser('~/compclust.ini')])
    
    # location of compClust package
    compclust_package_dir = compClust.__path__[0]
    
    self.__in_source_dir = False
    
    # what base directory should we use
    # the user wants to override any auto detection
    if base_dir is not None:
      self.__base_dir = base_dir
    # lets make sure we can find where we're supposed to install things
    elif self.__installing:
      self.__base_dir = self.data_install_path()
    # the environment variable comes next
    elif os.environ.has_key('COMPCLUST_DIR'):
      self.__base_dir = os.environ['COMPCLUST_DIR']
    # next we look in the config file
    elif parser.has_option('base', 'base_dir'):
      self.__base_dir = parser.get('base', 'base_dir')
    # perhaps we're running from the source tree
    elif os.path.isfile(os.path.join(compclust_package_dir, '..', 'setup.py')):
      self.__base_dir = compclust_package_dir
    # and finally where were we most likely to install it
    else:
      # look in the default installation location
      self.__base_dir = self.data_install_path()
      
    if os.path.isfile(os.path.join(self.__base_dir, '..', 'setup.py')):
      self.__in_source_dir = True
    
    self.__set_doc_dirs()  
    self.__set_algorithms()
    self.__matplotlib(parser)
      
  def __set_algorithms(self):
    """Set the path of the various clustering algorithms
    """
    # in the mls source tree the algorithms are in sub directories
    # so we need the doubled diagem/diagem paths
    self.__commands = {}
    self.__alg_dir = os.path.join(self.__base_dir,'..','src','mls')
    if self.__in_source_dir and os.path.exists(self.__alg_dir):
      # we have the C code
      self.__commands['kmeans'] = os.path.join(self.__alg_dir, 'kmeans','kmeans')
      self.__commands['kmedians'] = os.path.join(self.__alg_dir, 'kmedians','kmedians')
      self.__commands['diagem'] = os.path.join(self.__alg_dir, 'diagem','diagem')
      self.__commands['fullem'] = os.path.join(self.__alg_dir, 'fullem','fullem')
    else:
      if self.__in_source_dir:
        # we're in the python dir but don't have the C code
        if sys.platform == 'linux2':
          platform = 'linux-x86'
        elif sys.platform == 'darwin':
          platform = 'osx-ppc'
        else:
          platform ='win32'
        self.__alg_dir = os.path.join(self.__base_dir, '..', 'extra',
                                      'clustering-alg', platform)
      else:
        # we've been installed
        self.__alg_dir = os.path.join(self.__base_dir, 'bin')
      # the missing C code and installed case both lack the double up in
      # name that happens when you have the C code
      self.__commands['kmeans'] = os.path.join(self.__alg_dir, 'kmeans')
      self.__commands['kmedians'] = os.path.join(self.__alg_dir, 'kmedians')
      self.__commands['diagem'] = os.path.join(self.__alg_dir, 'diagem')
      self.__commands['fullem'] = os.path.join(self.__alg_dir, 'fullem')    
      
    # add the .exe for windows
    for k,v in self.__commands.items():
      self.__commands[k] = v + self.get_executable_extension()
	
  def __set_doc_dirs(self):
    """Set the path of the various 'document' drectories
    """
    if not self.__installing and self.__in_source_dir:
      self.__example_dir = os.path.join(self.__base_dir, 'gui', 'Examples')
      self.__cho_dir = os.path.join(self.__example_dir, 'ChoCellCycling')
      self.__template_dir = os.path.join(self.__base_dir, 'gui')
      self.__tkdoc_dir = os.path.join(self.__base_dir, 'gui', 'Docs')
    else:
      self.__example_dir = os.path.join(self.__base_dir,'examples')
      self.__cho_dir = os.path.join(self.__example_dir, 'ChoCellCycling')
      self.__template_dir = os.path.join(self.__base_dir, 'templates')
      self.__tkdoc_dir = os.path.join(self.__base_dir, 'docs')

    
  def get_executable_extension(self):
    """"Return the extension of executable files"""
    if sys.platform == 'win32':
      return ".exe"
    else:
      return ""

  def get_python_shared_library_extension(self):
    """Return the filename extension for compiled moudles"""
    if sys.platform == 'win32':
      return ".pyd"
    else:
      return ".so"

  def data_install_path(self):
    """Return the root of where to install things other than python code 
    """
    # if we didn't find anything useful, try for the default location
    if sys.platform == 'win32':

      python_dev_share = os.path.join(sys.exec_prefix, 'share')
      if os.path.exists(python_dev_share):
        # we're installed into a python developer installation
        return os.path.join(python_dev_share, "compclust")
      else:
        return os.path.join(sys.exec_prefix)
 
      #Hack to make setup.py bdist_wininst work properly.
      #if len([arg for arg in sys.argv if arg == 'bdist_wininst']):
      #  return 'compclust'

      #compclust = os.path.join(os.environ['ProgramFiles'], 'compclust')
      #if not os.path.isdir(compclust):
      #  compclust = os.path.join(sys.exec_prefix, 'compclust')
      #  if not os.path.isdir(compclust):
      #    msg = 'Can\'t find compclust!'
      #    raise IOError, msg
                                 
    else:
      # pretened everything else in the world is unix like
      compclust = '/usr/share/compclust'
    return compclust
        
  def data_path(self):
    """Return the root of where the data files live
    """
    compclust = self.data_install_path()
    
    if not os.path.isdir(compclust):
      raise RuntimeError("Couldn't find compclust data directory")
    else:
      return compclust

  def __get_base_dir(self):
    return self.__base_dir
  base_dir = property(__get_base_dir, doc="base directory for all datafiles")
  def __get_cho_data(self):
    return self.__cho_dir
  cho_data_dir = property(__get_cho_data, 
                          doc="where the Cho Cell Cycling data is stored")
  def __get_template_dir(self):
    return self.__template_dir
  template_dir = property(__get_template_dir,
                          doc="where the web server page templates are stored")
  def __get_tkdoc_dir(self):
   return self.__tkdoc_dir
  compclusttk_tutorial_dir = property(__get_tkdoc_dir,
                                      doc="CompClustTk tutorial directory")
  def __get_kmeans_command(self):
    return self.__commands['kmeans']
  kmeans_command = property(__get_kmeans_command,
                            doc="the location of the kmeans binary")
  def __get_kmedians_command(self):
    return self.__commands['kmedians']
  kmedians_command = property(__get_kmedians_command,
                              doc="the location of the kmedians binary")
  def __get_diagem_command(self):
    return self.__commands['diagem']
  diagem_command = property(__get_diagem_command,
                            doc="the location of the diagem binary")
  def __get_fullem_command(self):
    return self.__commands['fullem']
  fullem_command = property(__get_fullem_command,
                            doc="the location of the fullem binary")

  def __matplotlib(self, parser):
    """Consider setting the MATPLOTLIB environment variable
    """
    if not os.environ.has_key('MATPLOTLIBDATA') and \
       parser.has_option('matplotlib', 'data'):
        os.environ['MATPLOTLIBDATA'] = parser.get('matplotlib','data')
config = Config()                           
