from importlibs import *


__author__   = "Andrea Maffezzoli"
__revision__ = "$Revision: 0.13 - 13 Dec 2010$"
__name__     = "dataprocflow"
__all__      = ["sorting"]



class sorting(object):
    """
    The steps in our data processing flow:
    - Read/import input data
    - Do PCA on data
    - Represent data in the PCA space
    - Cluster data in PCA space with k-means (if enabled)
    - Find/remove outliers samples (both from all data and from any cluster)
    The module doesn't get any data in input but only a pointer
    'objectwithdata' to an object, as a class,..., with data to 
    be processed here, named 'objectwithdata.datatoproc', in order 
    to store only the results, not unnecessary input data
    """

    varnr = 3
    min_clusters_nr = max_clusters_nr = None
    rmvOutliers, Mahalanobis_threshold, normalize = False, 1.5, True

    def __init__(self, *args, **kwargs):
    
        for k, v in kwargs.iteritems(): setattr(self, k, v)

        ############################
        # Fix clusters nr and if to perform Outliers Detection on clusters
        ############################
        while True:
            if self.min_clusters_nr != None and self.max_clusters_nr != None: break
            clust_nr = raw_input("Digit the number of clusters: ")
            try:
                if ',' in clust_nr:
                    self.min_clusters_nr, self.max_clusters_nr = map(int, clust_nr.split(','))
                    break
                self.min_clusters_nr = self.max_clusters_nr = int(clust_nr) if clust_nr else 2 ; break
            except ValueError: print "Give in input an integer number of clusters.."
        while True:
            if self.rmvOutliers != None: break
            rmvOutliers = raw_input("To remove outliers press Enter, otherwise digit 'N' then Enter: ")
            if rmvOutliers in ('', 'N'): self.rmvOutliers = not(bool(rmvOutliers)); break

    def __call__(self, *args, **kwargs): self.__clustering__(*args, **kwargs)

    def __pcaprojection__(self, samplesData):
        
        if self.normalize:
            samplesData = numpy.array(samplesData, copy=True)
            samplesData -= samplesData.sum(axis=0, dtype='float')
            samplesData /= numpy.array([i  if i else 1 for i in samplesData.std(axis=0, dtype='float')])
        pcaobj = pca.pca(samplesData)
        if pcaobj: return pcaobj[:,:self.varnr]
        return samplesData[:,:self.varnr]
    
    def __clustering__(self, samplesData, samplesID = None):

        ##########################################################
        # Setting clustering settings
        # clusters_names is a dict having the ordinal of the cluster as key and 
        # as corresponding value the list of names of neurons in the given cluster.
        ##########################################################
        kmeans_dict = {'replicates_nr':   25,
                       'data_name':       samplesID,
                       'min_clusters_nr': self.min_clusters_nr,
                       'max_clusters_nr': self.max_clusters_nr,
                       'scatter_method':  kmeans.scatterwithin_no_samplesnr,
                       'outliers_detect': self.rmvOutliers,
                       'Mahalanobis_threshold': self.Mahalanobis_threshold, 
                       'scaling_down':    False,
                       'verbose':         False}            
        kmr = kmeans.kmeans_replica(self.__pcaprojection__(samplesData), **kmeans_dict)
        outliers_names = dict.copy(getattr(kmr, "all_outliers_names", {}))
        return dict((i, (j, outliers_names.get(i, []))) for i, j in kmr.clusters_names.iteritems())
