#!/usr/bin/env python3

# Copyright (c) 2020-2022 Danny van Dyk
#
# This file is part of the EOS project. EOS is free software;
# you can redistribute it and/or modify it under the terms of the GNU General
# Public License version 2, as published by the Free Software Foundation.
#
# EOS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA  02111-1307  USA

import argparse
import eos
from eos import debug, info, warn, error
import logging
import numpy as _np
import os
import pypmc
import scipy
import sys
import yaml

# return the value of the environment variable, or a default value if the variable is unset.
def get_from_env(envvar, default):
    if not envvar in os.environ:
        return default

    return os.environ[envvar]


def _parser():
    parser = argparse.ArgumentParser(description='Carry out a Bayesian analysis using EOS')
    # 'parent' parser for common arguments
    common_subparser = argparse.ArgumentParser(add_help=False)
    # add verbosity arg and analysis-file arg to all commands
    common_subparser.add_argument('-v', '--verbose',
        help = 'Increases the verbosity of the script',
        dest = 'verbose', action = 'count', default = 0
    )
    common_subparser.add_argument('-f', '--analysis-file',
        help = 'The analysis file. Defaults to \'.analysis.yaml\'.',
        dest = 'analysis_file', action = 'store', default = '.analysis.yaml'
    )
    subparsers = parser.add_subparsers(title = 'commands')

    ## begin of commands

    # list-priors
    parser_list_priors = subparsers.add_parser('list-priors',
        parents = [common_subparser],
        description =
'''
Lists the named prior PDFs defined within the scope of this analysis file.
''',
        help = 'Lists the named priors defined in the analysis file.'
    )
    parser_list_priors.set_defaults(cmd = cmd_list_priors)


    # list-likelihoods
    parser_list_likelihoods = subparsers.add_parser('list-likelihoods',
        parents = [common_subparser],
        description =
'''
Lists the named likelihoods defined within the scope of this analysis file.
''',
        help = 'Lists the named likelihoods defined in the analysis file.'
    )
    parser_list_likelihoods.add_argument('-d', '--display-details',
        help = 'Whether to display further details for each likelihood.',
        dest = 'display', action = 'store_true', default = False
    )
    parser_list_likelihoods.set_defaults(cmd = cmd_list_likelihoods)


    # list-posteriors
    parser_list_posteriors = subparsers.add_parser('list-posteriors',
        parents = [common_subparser],
        description =
'''
Lists the named posterior PDFs defined within the scope of this analysis file.
''',
        help = 'Lists the named posteriors defined in the analysis file.'
    )
    parser_list_posteriors.set_defaults(cmd = cmd_list_posteriors)


    # list-predictions
    parser_list_predictions = subparsers.add_parser('list-predictions',
        parents = [common_subparser],
        description =
'''
Lists the named prediction sets defined within the scope of this analysis file.
''',
        help = 'Lists the named predictions define in the analysis file.'
    )
    parser_list_predictions.set_defaults(cmd = cmd_list_predictions)


    # sample-mcmc
    parser_sample_mcmc = subparsers.add_parser('sample-mcmc',
        parents = [common_subparser],
        description =
'''
Samples from a named posterior PDF using Markov Chain Monte Carlo (MCMC) methods.

The output file will be stored in EOS_BASE_DIRECTORY/POSTERIOR/mcmc-IDX.
''',
        help = 'Samples from a posterior using Marko Chain Monte Carlo methods.'
    )
    parser_sample_mcmc.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which to draw the samples.'
    )
    parser_sample_mcmc.add_argument('chain', metavar = 'CHAIN-IDX',
        help = 'The index assigned to the Markov chain. This value is used to seed the RNG for a reproducible analysis.',
        type = int
    )
    parser_sample_mcmc.add_argument('-N', '--number-of-samples',
        help = 'The number of samples to be stored in the output file.',
        dest = 'N', action = 'store', type = int, default = 1000
    )
    parser_sample_mcmc.add_argument('-S', '--stride',
        help = 'The ratio of samples drawn over samples stored. For every S samples, S - 1 will be discarded.',
        dest = 'stride', action = 'store', type = int, default = 5
    )
    parser_sample_mcmc.add_argument('-p', '--number-of-preruns',
        help = 'The number of prerun steps, which are used to adapt the MCMC proposal to the posterior.',
        dest = 'preruns', action = 'store', type = int, default = 3
    )
    parser_sample_mcmc.add_argument('-n', '--number-of-prerun-samples',
        help = 'The number of samples to be used for an adaptation in each prerun steps. These samples will be discarded.',
        dest = 'pre_N', action = 'store', type = int, default = 150
    )
    parser_sample_mcmc.add_argument('-s', '--start-point',
        help = 'Optional starting point for the chain',
        dest = 'start_point', action = 'store', type = lambda s: [float(item) for item in s.split(',')]
    )
    parser_sample_mcmc.add_argument('-c', '--cov-scale',
        help = 'Scale factor for the initial guess of the covariance matrix.',
        dest = 'cov_scale', action = 'store', type = float, default = 0.1
    )
    parser_sample_mcmc.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_sample_mcmc.set_defaults(cmd = cmd_sample_mcmc)


    # sample-pmc
    parser_sample_pmc = subparsers.add_parser('sample-pmc',
        parents = [common_subparser],
        description =
'''
Samples from a named posterior using the Population Monte Carlo (PMC) methods.

The results of the find-cluster command are expected in EOS_BASE_DIRECTORY/POSTERIOR/clusters.
The output file will be stored in EOS_BASE_DIRECTORY/POSTERIOR/pmc.
''',
        help = 'Samples from a posterior using the Population Monte Carlo method.'
    )
    parser_sample_pmc.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which to draw the samples.'
    )
    parser_sample_pmc.add_argument('-n', '--number-of-adaptation-samples',
        help = 'The number of samples to be used in each adaptation step. These samples will be discarded.',
        dest = 'step_N', action = 'store', type = int, default = 500
    )
    parser_sample_pmc.add_argument('-s', '--number-of-adaptation-steps',
        help = 'The number of adaptation steps, which are used to adapt the PMC proposal to the posterior.',
        dest = 'steps', action = 'store', type = int, default = 10
    )
    parser_sample_pmc.add_argument('-t', '--perplexity-threshold',
        help = 'The threshold for the perplexity in the last step after which further adaptation steps are to be skipped.',
        dest = 'perplexity_threshold', action = 'store', type = float, default = 1.0
    )
    parser_sample_pmc.add_argument('-w', '--weight-threshold',
        help = 'Mixture components with a weight smaller than this threshold are pruned.',
        dest = 'weight_threshold', action = 'store', type = float, default = 1e-10
    )
    parser_sample_pmc.add_argument('-N', '--number-of-final-samples',
        help = 'The number of samples to be stored in the output file.',
        dest = 'final_N', action = 'store', type = int, default = 5000
    )
    parser_sample_pmc.add_argument('--pmc_iterations',
        help = 'The maximum number of update of the PMC, changing this value may make the update unstable',
        dest = 'pmc_iterations', action = 'store', type = int, default = 1
    )
    parser_sample_pmc.add_argument('--pmc-rel-tol',
        help = 'Relative tolerance of the PMC update.',
        dest = 'pmc_rel_tol', action = 'store', type = float, default = 1e-10
    )
    parser_sample_pmc.add_argument('--pmc-abs-tol',
        help = 'Absolute tolerance of the PMC update.',
        dest = 'pmc_abs_tol', action = 'store', type = float, default = 1e-5
    )
    parser_sample_pmc.add_argument('-l', '--pmc-lookback',
        help = 'The number of previous steps whose samples are used to update the PMC. 1 (default) means that only last step is used ; 0 means that all available steps are used.',
        dest = 'pmc_lookback', action = 'store', type = int, default = 1
    )
    parser_sample_pmc.add_argument('-p', '--initial-proposal',
        help = """Specify where the initial proposal should be taken from; 'clusters' (default): use the proposal obtained using `find-clusters`;
            'product': use the proposal obtained from `mixture_product`; 'pmc': continue sampling from the previous `sample-pmc` results.""",
        dest = 'initial_proposal', action = 'store', type = str, default = 'clusters'
    )
    parser_sample_pmc.add_argument('-S', '--sigma-test-stat',
        help = 'If provided, the inverse CDF of -2*log(PDF) will be evaluated, using the provided values as the respective significance.',
        dest = 'sigma_test_stat', action = 'store', type = lambda s: [float(item) for item in s.split(',')]
    )
    parser_sample_pmc.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_sample_pmc.set_defaults(cmd = cmd_sample_pmc)


    # sample-nested
    parser_sample_nested = subparsers.add_parser('sample-nested',
        parents = [common_subparser],
        description =
'''
Samples from a likelihood associated with a named posterior using dynamic nested sampling.

The output file will be stored in EOS_BASE_DIRECTORY/POSTERIOR/nested.
''',
        help = 'Samples from a likelihood (associated with a posterior) using dynamic nested sampling.'
    )
    parser_sample_nested.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which to draw the samples.'
    )
    parser_sample_nested.add_argument('-B', '--target-bound',
        help = 'The method used to approximately bound the prior using the current set of live points. Conditions the sampling methods used to propose new live points. For valid values, see the dynesty documentation.',
        dest = 'bound', action = 'store', type = str, default = 'multi'
    )
    parser_sample_nested.add_argument('-n', '--number-of-live-points',
        help = 'The number of live points.',
        dest = 'nlive', action = 'store', type = int, default = 250
    )
    parser_sample_nested.add_argument('-d', '--evidence-tolerance',
        help = 'The relative tolerance for the remaining evidence.',
        dest = 'dlogz', action = 'store', type = float, default = 1.0
    )
    parser_sample_nested.add_argument('-m', '--max-number-iterations',
        help = 'The maximum number of iterations. Iterations may stop earlier if the termination condition is reached.',
        dest = 'maxiter', action = 'store', type = int, default = None
    )
    parser_sample_nested.add_argument('-s', '--use-random-seed',
        help = 'The seed used to initialize the Mersenne Twister pseudo-random number generator.',
        dest = 'seed', action = 'store', type = int, default = 10
    )
    parser_sample_nested.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_sample_nested.set_defaults(cmd = cmd_sample_nested)


    # plot-samples
    parser_plot_samples = subparsers.add_parser('plot-samples',
        parents = [common_subparser],
        description =
'''
Plots all samples obtained for a named posterior.

The results of either the sample-mcmc or the sample-pmc command are expected in
EOS_BASE_DIRECTORY/POSTERIOR/mcmc-* or EOS_BASE_DIRECTORY/POSTERIOR/pmc, respectively.
The plots will be stored as PDF files within the respective sample inputs.
''',
        help = 'Plots samples for a named posterior.'
    )
    parser_plot_samples.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which to draw the samples.'
    )
    parser_plot_samples.add_argument('-B', '--bins',
        help = 'The number of bins per histogram.',
        dest = 'bins', action = 'store', type = int, default = 50
    )
    parser_plot_samples.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_plot_samples.set_defaults(cmd = cmd_plot_samples)


    # find-mode
    parser_find_mode = subparsers.add_parser('find-mode',
        parents = [common_subparser],
        description =
'''
Finds the mode of the named posterior.

The optimization process can be initialized either with a random point,
a provided parameter point, or by extracting the point with the largest posterior
from among previously obtained MCMC samples. The optimization can be iterated to
increase the accuracy of the result. The output will be stored
in EOS_BASE_DIRECTORY/posterior/mode-LABEL.
''',
        help = 'Finds the mode of a named posterior.'
    )
    parser_find_mode.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF that will be maximized.',
    )
    parser_find_mode.add_argument('-o', '--optimizations',
        help = 'The number of calls to the optimization algorithm.',
        dest = 'optimizations', action = 'store', type = int, default = 3
    )
    parser_find_mode.add_argument('-c', '--from-mcmc',
        help = 'The chain index of an MCMC data file from which the maximization is started.',
        dest = 'chain', action = 'store', type = int, default = None
    )
    parser_find_mode.add_argument('-p', '--from-point',
        help = 'The point from which the minimization is started.',
        dest = 'start_point', action = 'store', type = str, default = None
    )
    parser_find_mode.add_argument('-s', '--use-random-seed',
        help = 'The seed used to generate the random starting point of the minimization.',
        dest = 'seed', action = 'store', type = int, default = None
    )
    parser_find_mode.add_argument('-L', '--label',
        help = 'The label used for the generated data file.',
        dest = 'label', action = 'store', type = str, default = '-default'
    )
    parser_find_mode.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_find_mode.set_defaults(cmd = cmd_find_mode)


    # mixture_product
    parser_mixture_product = subparsers.add_parser('mixture-product',
        parents = [common_subparser],
        description =
'''
    Compute the cartesian product of the densities listed in posteriors. Note that this product is not commutative.

    The input densities are read from EOS_BASE_DIRECTORY/POSTERIOR_i/pmc, where POSTERIOR_i is listed in posteriors.
    The output density will be stored in EOS_BASE_DIRECTORY/POSTERIOR/product.
''',
        help = 'Compute the cartesian product of named posteriors.'
    )
    parser_mixture_product.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF for which the product is computed',
        action = 'store', type = str
    )
    parser_mixture_product.add_argument('posteriors', metavar = 'POSTERIORS',
        help = 'The list of name of the posteriors PDF that will be concatenated.',
        action = 'store', type = lambda s: s.split(',')
    )
    parser_mixture_product.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_mixture_product.set_defaults(cmd = cmd_mixture_product)


    # find-clusters
    parser_find_clusters = subparsers.add_parser('find-clusters',
        parents = [common_subparser],
        description =
'''
Finds clusters among posterior MCMC samples, grouped by Gelman-Rubin R value, and creates a Gaussian mixture density.

Finding clusters and creating a Gaussian mixture density is a necessary intermediate step before using the sample-pmc subcommand.
The input files are expected in EOS_BASE_DIRECTORY/POSTERIOR/mcmc-*. All MCMC input files present will be used in the clustering.
The output files will be stored in EOS_BASE_DIRECTORY/POSTERIOR/clusters.
''',
        help = 'Finds clusters within MCMC samples of a named posterior.'
    )
    parser_find_clusters.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which MCMC samples have previously been drawn.',
        action = 'store', type = str
    )
    parser_find_clusters.add_argument('-t', '--threshold',
        help = 'The R value threshold. If two sample subsets have an R value larger than this threshold, they will be treated as two distinct clusters. (default: 2.0)',
        dest = 'threshold', action = 'store', type = float, default = 2.0
    )
    parser_find_clusters.add_argument('-c', '--clusters-per-group',
        help = 'The number of mixture components per cluster. (default: 1)',
        dest = 'K_g', action = 'store', type = int, default = 1
    )
    parser_find_clusters.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_find_clusters.set_defaults(cmd = cmd_find_clusters)


    # predict-observables
    parser_predict_observables = subparsers.add_parser('predict-observables',
        parents = [common_subparser],
        description =
'''
Predicts a set of observables based on previously obtained PMC samples.

The input files are expected in EOS_BASE_DIRECTORY/POSTERIOR/pmc.
The output files will be stored in EOS_BASE_DIRECTORY/POSTERIOR/pred-PREDICTION.
''',
        help = 'Predicts observables based on PMC samples.'
    )
    parser_predict_observables.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which to draw the samples.'
    )
    parser_predict_observables.add_argument('prediction', metavar = 'PREDICTION',
        help = 'The name of the set of observables to predict.',
        action = 'store', type = str
    )
    parser_predict_observables.add_argument('-B', '--begin-index',
        help = 'The index of the first sample to use for the predictions.',
        dest = 'begin', action = 'store', type = int, default = 0
    )
    parser_predict_observables.add_argument('-E', '--end-index',
        help = 'The index beyond the last sample to use for the predictions.',
        dest = 'end', action = 'store', type = int, default = -1
    )
    parser_predict_observables.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_predict_observables.set_defaults(cmd = cmd_predict_observables)


    # corner-plot
    parser_corner_plot = subparsers.add_parser('corner-plot',
        parents = [common_subparser],
        description =
'''
Generate a corner plot of the 1-D and 2-D marginalized posteriors.

The input files are expected in EOS_BASE_DIRECTORY/POSTERIOR/samples.
The output files will be stored in EOS_BASE_DIRECTORY/POSTERIOR/plots.
''',
        help = 'Generate a corner plot of the 1-D and 2-D marginalized posteriors.'
    )
    parser_corner_plot.add_argument('posterior', metavar = 'POSTERIOR',
        help = 'The name of the posterior PDF from which the samples were drawn.'
    )
    parser_corner_plot.add_argument('-B', '--begin-parameter',
        help = 'The index of the first parameter to plot.',
        dest = 'begin', action = 'store', type = int, default = 0
    )
    parser_corner_plot.add_argument('-E', '--end-parameter',
        help = 'The index beyond the last parameter to plot.',
        dest = 'end', action = 'store', type = int, default = None
    )
    parser_corner_plot.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_corner_plot.set_defaults(cmd = cmd_corner_plot)


    # run
    parser_run = subparsers.add_parser('run',
        parents = [common_subparser],
        description =
'''
Runs a list of subcommands based on the pre-recorded steps defined within an analysis.
''',
        help = 'Runs a list of subcommands.'
    )
    parser_run.add_argument('-b', '--base-directory',
        help = 'The base directory for the storage of data files. Can also be set via the EOS_BASE_DIRECTORY environment variable.',
        dest = 'base_directory', action = 'store', default = get_from_env('EOS_BASE_DIRECTORY', './')
    )
    parser_run.add_argument('-d', '--dry-run',
        help = 'Perform a dry run only. Outputs the list of subcommands that would be run instead of running them.',
        dest = 'dry_run', action = 'store_true', default = False
    )
    parser_run.set_defaults(cmd = cmd_run)

    ## end of commands

    return parser

def main():
    parser = _parser()
    args = parser.parse_args()

    if not 'cmd' in args:
        parser.print_help()
    elif not callable(args.cmd):
        parser.print_help()
    else:
        if args.verbose > 3:
            args.verbose = 3

        levels = {
            0: logging.ERROR,
            1: logging.WARNING,
            2: logging.INFO,
            3: logging.DEBUG
        }

        logging.basicConfig(level=levels[args.verbose])

        args.cmd(args)



def make_analysis_file(args):
    analysis_file = eos.AnalysisFile(args.analysis_file)
    return analysis_file

def args_to_dict(args):
    result = vars(args)
    result.pop('verbose', None)
    result.pop('cmd', None)
    return result

class RNG:
    def __init__(self, seed):
        self._rng = _np.random.mtrand.RandomState(seed)

    def rand(self, *args):
        result = self._rng.rand(*args)
        print('rand: {}'.format(result))
        return result

    def normal(self, loc, scale=1, size=None):
        result = self._rng.normal(loc, scale, size)
        print('normal: {}'.format(result))
        return result

    def uniform(self, low, high, size=None):
        result = self._rng.uniform(low, high, size)
        print('uniform: {}'.format(result))
        return result


# Find mode
def cmd_find_mode(args):
    return eos.tasks.find_mode(**args_to_dict(args))


# Plot samples
def cmd_plot_samples(args):
    import pathlib
    input_path = pathlib.Path(os.path.join(args.base_directory, args.posterior))
    inputs  = [str(d) for d in input_path.glob('mcmc-*')]
    inputs += [str(d) for d in input_path.glob('samples')]
    for input in inputs:
        info('plotting samples in \'{}\''.format(input))
        basename = os.path.basename(os.path.normpath(input))
        if basename.startswith('mcmc-'):
            data = eos.data.MarkovChain(input)
        elif basename.startswith('samples'):
            data = eos.data.ImportanceSamples(input)
        else:
            raise RuntimeError('unsupported data set: {}'.format(input))

        parameters = eos.Parameters()
        for idx, p in enumerate(data.varied_parameters):
            info('plotting histogram for {}'.format(p['name']))
            if data.type in ['Prediction']:
                label = eos.Observables()[p['name']]
            elif data.type in ['MarkovChain', 'ImportanceSamples']:
                pp = parameters[p['name']]
                label = pp.latex()
            else:
                label = r'\verb+{}+'.format(p['name'])

            description = {
                'plot': {
                    'x': { 'label': label, 'range': [p['min'], p['max']] },
                    'y': { 'label': 'prob. density' }
                },
                'contents': [
                    {
                        'type': 'histogram', 'bins': args.bins,
                        'data': {
                            'samples': data.samples[:, idx],
                        }
                    }
                ]
            }
            plotter = eos.plot.Plotter(description, os.path.join(input, '{}.pdf'.format(idx)))
            plotter.plot()


# Sample MCMC
def cmd_sample_mcmc(args):
    return eos.sample_mcmc(**args_to_dict(args))


# Find clusters
def cmd_find_clusters(args):
    return eos.find_clusters(**args_to_dict(args))


# Sample PMC
def cmd_sample_pmc(args):
    return eos.sample_pmc(**args_to_dict(args))


# Nested sampling
def cmd_sample_nested(args):
    return eos.sample_nested(**args_to_dict(args))


# Corner plot
def cmd_corner_plot(args):
    return eos.corner_plot(**args_to_dict(args))


# Cartesian product
def cmd_mixture_product(args):
    return eos.mixture_product(**args_to_dict(args))


# Predict observables
def cmd_predict_observables(args):
    return eos.predict_observables(**args_to_dict(args))


# Run steps
def cmd_run(args):
    return eos.run(**args_to_dict(args))


# List priors
def cmd_list_priors(args):
    analysis_file = make_analysis_file(args)
    for name, prior in analysis_file.priors.items():
        print(name)


# List likelihoods
def cmd_list_likelihoods(args):
    analysis_file = make_analysis_file(args)
    for name, lh in analysis_file.likelihoods.items():
        print(name)
        if not args.display:
            continue

        if not 'constraints' in lh and not 'manual_constraints' in lh:
            error('Likelihoods {name} specifies neither the \'constraints\' nor the \'manual_constraints\' key'.format(name=name))
            continue

        for c in lh['constraints'] if 'constraints' in lh else []:
            print(' - {}'.format(c))

        for mc in lh['manual_constraints'] if 'manual_constraints' in lh else {}:
            print(' - {} [manual]'.format(mc))


# List predictions
def cmd_list_predictions(args):
    analysis_file = make_analysis_file(args)
    for name, pred in analysis_file.predictions.items():
        print(name)


# List posteriors
def cmd_list_posteriors(args):
    analysis_file = make_analysis_file(args)
    for name, lh in analysis_file.posteriors.items():
        print(name)


if __name__ == '__main__':
    main()
