########################################
# 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: Diane Trout, Benjamin J. Bornstein
# Last Modified: 26-Apr-2001, 5:31p
#

"""
Usage: HutSOM.py parameter_filename input_filename results_filename

 Wrapper for Matlab SOM Toolbox Algorithm

 Depends on the following environment variables:
   MATLAB_CODE_HOME   (e.g., /home/proj/code/matlab)
   SOM_TOOLBOX_HOME   (e.g., /home/proj/code/matlab/somtoolbox)

 transform_method
   One of 'none', 'log', 'histD', 'var'
 init_method
   Choose initial positioning of the SOM nodes
   One of 'linear', 'random'
 som_x_dimension
   Map x dimension
 som_y_dimension
   Map y dimension
 num_iterations
   number of iterations update node locations
"""

import os
import sys
import tempfile
import string
import types

from compClust.mlx.labelings import Labeling
from compClust.mlx.models import DistanceFromMean
import compClust.mlx.ML_Algorithm as ML_Algorithm
from compClust.util import WrapperUtil
from compClust.util import Usage
from compClust.util import Verify
from compClust.util.TimeStampedPrintStream import TimeStampedPrintStream

import compClust.mlx.wrapper

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


class HutSOM(ML_Algorithm.ML_Algorithm):
  def __init__(self, dataset=None, parameters=None):
    self.setMessageStream( MESSAGE_STREAM )
    self.dataset    = dataset
    self.parameters = parameters
    self.model      = None
    self.labeling   = None

    self.default_tempdir = tempfile.gettempdir()
    
  def __create_matlab_startup_file__(self, temp_dir_name, parameters):
    """startup_filename = create_matlab_startup_file(temp_dir_name, parameters)

    Creates a Matlab startup filename (startup.m) in the given temporary
    directory (which must already exist) suitable for running the
    Helsinki University of Technology (HUT) SOM Toolbox.  Parameters is
    a dictionary containing all required parameters to write the starup
    file.

    The full-path of the starup filename is returned.
    """


    startup_filename = temp_dir_name + "startup.m"
    startup_file     = open(startup_filename, "w")

    run_som_cmd = "run_hutsom('%s', '%s', '%s', [%d %d], %d, '%s'" % \
                  ( parameters[ "clustering_input_filename" ],
                    parameters[ "transform_method"          ],
                    parameters[ "init_method"               ],
                    parameters[ "som_x_dimension"           ],
                    parameters[ "som_y_dimension"           ],
                    parameters[ "num_iterations"            ],
                    parameters[ "output_filename"           ] )

    #
    # Special case: (random) seed parameter.
    #
    if (parameters["init_method"] == "random"):
      if (parameters.has_key("seed")):
        run_som_cmd += ", %d" % (parameters["seed"])

    run_som_cmd += ");\n"


    startup_file.write("addpath( '%s' );\n" % (os.environ[ "MATLAB_CODE_HOME" ]))
    startup_file.write("addpath( '%s' );\n" % (os.environ[ "SOM_TOOLBOX_HOME" ]))
    startup_file.write(run_som_cmd)
    startup_file.write("quit;\n")

    startup_file.close()

    return startup_filename


  def copy(self):
    new_obj = HutSOM(self.dataset, self.parameters)
    new_obj.labeling = self.labeling
    return new_obj
   

  def getLabeling(self):
    return self.labeling

  def getModel(self):
    if self.model is None:
      dataset  = self.dataset
      labeling = self.labeling
      self.model = DistanceFromMean(data=dataset, labels=labeling)
    return self.model

  def run(self):
    """run(parameter_filename, data_filename, output_filename)

    Prepares the inputs to the clustering algorithm and runs it.
    """
    # invalidate the current model
    self.model = None
    
    # store what directory we start in
    start_dir = os.getcwd()
    
    #
    # Create temporary directory.
    #
    temp_dir_name = WrapperUtil.create_temporary_directory("som_")

    #
    # Ensure that output_filename is a full (absolute) path and filename.
    #
    #= self.parameters[ 'output_filename' ]
    tempfile.tempdir = temp_dir_name
    cluster_output_filename = tempfile.mktemp("cluster_output")
    cluster_output_filename = os.path.abspath(cluster_output_filename)
    # set output destination for matlab script
    self.parameters[ 'output_filename' ] = cluster_output_filename

    #  
    # Prepare data file and store in temporary location.
    #
    self.parameters[ "clustering_input_filename" ] =   \
      WrapperUtil.create_clustering_input_file(        \
        self.dataset,                                  \
        temp_dir_name )

    #
    # Prepare startup script for matlab.
    #
    matlab_filename = self.__create_matlab_startup_file__(temp_dir_name, self.parameters)

    #
    # Launch Matlab to run SOM clustering.
    #
    print "Changing to ", temp_dir_name
    os.chdir ( temp_dir_name )
    os.system( "matlab -display null" )
    
    #
    # Load clustering results
    #
    labeling_stream = open(cluster_output_filename , "r")
    labeling_text = map(string.strip, labeling_stream.readlines())
    labeling_stream.close()
    
    labeling = Labeling(self.dataset)
    labeling.labelRows(labeling_text)
    
    #
    # Cleanup temporary files and directory.
    #

    files = os.listdir( temp_dir_name )
    for file in files:
      os.remove(os.path.join(temp_dir_name, file ))
    os.rmdir ( temp_dir_name )

    # return tempfile.tempdir to its default tempdir
    tempfile.tempdir = self.default_tempdir
    
    os.chdir(start_dir)
    
    self.labeling = labeling
    return compClust.mlx.wrapper.WRAPPER_STATUS_DONE



  def validate(self):
    """validate_parameters(parameters)

    Ensures that all parameters and environment variables nescessary
    to run the SOM Toolbox are defined.
    """

    environment_names = [ "SOM_TOOLBOX_HOME",
                          "MATLAB_CODE_HOME" ]

    parameter_names   = [ "transform_method",
                          "init_method"     ,
                          "som_x_dimension" ,
                          "som_y_dimension" ,
                          "num_iterations"  ]

    err = 0
    
    if Verify.environment_variables_exist( environment_names ):
      err = 1
      
    if Verify.parameters_exist( parameter_names, self.parameters ):
      err = 1
      
    return not err


if (__name__ == "__main__"):
  from compClust.mlx.wrapper import Launcher

  Launcher.main(sys.argv, HutSOM())
