from phycas import randomtree
from phycas.utilities.PhycasCommand import *
from phycas.commands.PWKImpl import PartitionWeightedKernelEstimator
import copy

class PWK(PhycasCommand):
    def __init__(self):
        args = (
                   ("skip",                 1, "Number of lines from the input trees and parameters to skip (first line stores starting parameter values, so this value should normally be at least 1)", IntArgValidate(min=0)),
                   ("minsample",          100, "Minimum number of samples for a topology to be included", IntArgValidate(min=2)),
                   ("params",              "", "Name of file containing sampled parameter values", FileExistsValidate),
                   ("reach",              1.0, "Radius of outermost hypersphere for any one topology will be the product of this fraction and the radius of the outermost sample", FloatArgValidate(min=0.01)),
                   ("shells",              50, "Number of hyperspherical shells forming the partition", IntArgValidate(min=1)),
                   ("trees", TreeCollection(), "A source of trees (list of trees or the name of the input tree file) to be used", TreeSourceValidate)
                )
        o = PhycasCommandOutputOptions()

        o.__dict__["_help_order"] = ["log"]

        logf_spec = TextOutputSpec(prefix='pwkoutput', help_str="The file specified by this setting saves the console output generated by sump(). If set to None, console output will not be saved to a file.")
        o.__dict__["log"] = logf_spec

        PhycasCommand.__init__(self, args, "pwk", "The pwk command is used to estimate the marginal likelihood from a posterior sample of trees and parameter values produced by an MCMC simulation.", o)

        # The data members added below should be hidden from the user because they are for use by phycas developers.
        # 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__["cposmooth"] = 20.0   # ("cposmooth", 20.0, "Standard deviation to use in smoothing CPO plot", FloatArgValidate(min=1.0))

    def hidden():
        """
        Overrides the PhycasCommand.hidden method to keep PWK's name from being displayed
        in the list of classes displayed when users type help. Delete this function, or
        change its return value to False, when it is ready to be advertised.
        """
        return True

    hidden = staticmethod(hidden)

    def __call__(self, **kwargs):
        self.set(**kwargs)
        c = copy.deepcopy(self)
        pwk_estimator = PartitionWeightedKernelEstimator(c)
        marginal_likelihood = pwk_estimator.run()
        return marginal_likelihood
