from phycas.utilities.PhycasCommand import *
from phycas import mcmc, P  #, partition
from phycas.commands.GGImpl import GGImpl

class GG(PhycasCommand):
    def __init__(self):
        args = tuple(
                [
                ("data_source",     P.characters,    "The DataSource that provides the data to be used in the GG analysis. Should be a DataSource object", DataSourceValidate),
                ("params",          None,           "Name of file containing parameter samples", FileExistsValidate),
                ("trees",           None,           "Name of file containing tree samples", TreeSourceValidate),
                ("nreps",           1,              "The number of replicate simulations to do every MCMC sample", IntArgValidate(min=0)),
                ("skip  ",          1,              "Number of starting samples to skip when computing Gelfand-Ghosh measures", IntArgValidate(min=1)),
                ("kvalues",         [1.0],          "Vector of overall measures (one for each k in kvalues)")
                ] + PhycasCommand._getRNGOptions()
                )

        o = PhycasCommandOutputOptions()
        o.__dict__["_help_order"] = ["log", "bincounts", "postpred"]

        logf_spec = TextOutputSpec(prefix='gg-output', suffix=".txt", help_str="The file specified by this setting saves the console output generated by gg() (set gg.out.log.prefix = None to avoid creating this file).")
        o.__dict__["log"] = logf_spec

        t = TextOutputSpec(prefix=None, suffix=".txt", help_str="The file in which bin counts are stored for each simulated data set. Note: this file is not normally generated; set gg.out.bincounts.prefix = 'bincounts' (or another prefix string of your choice) to generate.")
        o.__dict__["bincounts"] = t

        t = TextOutputSpec(prefix=None, suffix=".nex", help_str="The files in which posterior-predictive simulated data sets are saved. Note: this file is not normally generated; set gg.out.postpred.prefix = 'postpred' (or another prefix string of your choice) to generate. Note: normally mode = ADDNUMBER should be used for this output option; if mode = REPLACE is used, only the last posterior-predictive data set will be saved.")
        o.__dict__["postpred"] = t

        PhycasCommand.__init__(self, args, "gg", "Performs a Gelfand-Ghosh analysis.", o)

        # The data members added below should be hidden from the user because they are irrelevant to simulating data
        # They must be present, however, because they are referenced in the LikelihoodCore class, which is also used
        # for likelihood and Bayesian analyses.
        #
        # The roundabout way of introducing these data members is necessary because PhycasCommand.__setattr__ tries
        # to prevent users from adding new data members (to prevent accidental misspellings from causing problems)
        self.__dict__["gg_Pm"]                = 0.0       # Penalty component (same for all k)
        self.__dict__["gg_Gm"]                = []        # Vector of goodness-of-fit components (one for each k in gg_kvect)
        self.__dict__["gg_Dm"]                = []        # Vector of overall measures (one for each k in gg_kvect)
        self.__dict__["gg_outfile"]           = 'gg.txt'  # File in which to save gg results (use None to not save results)
        self.__dict__["gg_bin_patterns"]      = True      # If True, patterns will be classified into 7 or 15 bins, with 7 bins corresponding to 'A only', 'C only', 'G only', 'T only', 'any 2 states', 'any 3 states' and 'any 4 states' and 15 bins corresponding to 'A', 'C', 'G', 'T', 'AC', 'AG', 'AT', 'CG', 'CT', 'GT', 'ACG', 'ACT', 'AGT', 'CGT', and 'ACGT'. Gelfand-Ghosh statistics will be computed on this vector of counts instead of the complete vector of pattern counts. Can only be used for DNA/RNA data.
        self.__dict__["gg_num_bins"]          = 15        # Should be either 7 or 15 (see gg_bin_patterns)
        #self.__dict__["gg_bincount_filename"] = None      # If not None, and if gg_bin_patterns is True, the binned counts for the original dataset and all posterior predictive data sets will be saved to a file by this name
        #self.__dict__["gg_postpred_prefix"]   = None      # Prefix to use for posterior predictive dataset filenames (no datasets will be saved if set to None)

        # needed only because MarkovChain.py consults this (see setupChain function)
        #self.__dict__["partition"]                     = partition

        # data members hidden from users
        self.__dict__["uf_num_edges"]                   = mcmc.uf_num_edges
        #self.__dict__["fix_topology"]                   = mcmc.fix_topology
        #self.__dict__["slice_max_units"]                = mcmc.slice_max_units
        #self.__dict__["slice_weight"]                   = mcmc.slice_weight
        #self.__dict__["doing_steppingstone_sampling"]   = mcmc.doing_steppingstone_sampling
        #self.__dict__["state_freq_weight"]              = mcmc.state_freq_weight
        #self.__dict__["state_freq_psi"]                 = mcmc.state_freq_psi
        #self.__dict__["state_freq_psi0"]                = mcmc.state_freq_psi0
        #self.__dict__["rel_rate_weight"]                = mcmc.rel_rate_weight
        #self.__dict__["rel_rate_psi"]                   = mcmc.rel_rate_psi
        #self.__dict__["rel_rate_psi0"]                  = mcmc.rel_rate_psi0
        #self.__dict__["tree_scaler_weight"]             = mcmc.tree_scaler_weight
        #self.__dict__["tree_scaler_lambda"]             = mcmc.tree_scaler_lambda
        #self.__dict__["tree_scaler_lambda0"]            = mcmc.tree_scaler_lambda0
        #self.__dict__["ls_move_weight"]                 = mcmc.ls_move_weight
        #self.__dict__["ls_move_lambda"]                 = mcmc.ls_move_lambda
        #self.__dict__["ls_move_lambda0"]                = mcmc.ls_move_lambda0
        #self.__dict__["allow_polytomies"]               = mcmc.allow_polytomies
        #self.__dict__["ss_heating_likelihood"]          = mcmc.ss_heating_likelihood

    def hidden():
        """
        Overrides the PhycasCommand.hidden method to keep this command's name from being displayed
        in the list of classes displayed when users type help. Change the return value to
        False when it is ready to be advertised.
        """
        return False

    hidden = staticmethod(hidden)

    def __call__(self, **kwargs):
        self.set(**kwargs)
        c = copy.deepcopy(self)
        ggimpl = GGImpl(c)
        ggimpl.run()
