#include <Python.h>
#include "runpastml.h"
#include "pastml.h"
# include <stdbool.h>

extern int QUIET;

/*  wrapped pastml function */
static PyObject *infer_ancestral_states(PyObject *self, PyObject *args) {
    char *annotation_name;
    char *tree_name;
    char *out_annotation_name = NULL;
    char *out_tree_name = NULL;
    char *out_param_name = NULL;
    char *out_mp_name = NULL;
    char *in_param_name = NULL;
    char *model = JC;
    char *prob_method = MARGINAL_APPROXIMATION;
    int quiet = 0;
    int sts;

    if (!PyArg_ParseTuple(args, "ss|sssssssi", &annotation_name, &tree_name, &out_annotation_name,
                          &out_tree_name, &prob_method, &model, &out_param_name, &in_param_name, &out_mp_name, &quiet)) {
        printf("Could not parse parameters O_o\n");
        return NULL;
    }
    if (quiet != 0) {
        QUIET = true;
    }
    if (strcmp(in_param_name, "") == 0) {
        in_param_name = NULL;
    }
    if (strcmp(out_tree_name, "") == 0) {
        out_tree_name = NULL;
    }
    if (strcmp(out_param_name, "") == 0) {
        out_param_name = NULL;
    }
    if (strcmp(out_annotation_name, "") == 0) {
        out_annotation_name = NULL;
    }
    if (strcmp(out_annotation_name, "") == 0) {
        out_annotation_name = NULL;
    }
    if (strcmp(out_mp_name, "") == 0) {
        out_mp_name = NULL;
    }
    sts = runpastml(annotation_name, tree_name, out_annotation_name, out_tree_name, out_param_name, model, prob_method,
            in_param_name, out_mp_name);
    if (sts != EXIT_SUCCESS) {
        if (errno) {
            return PyErr_SetFromErrno(PyErr_NewException("pastml.error", NULL, NULL));
        } else {
            PyErr_SetString(PyErr_NewException("pastml.error", NULL, NULL), strerror(sts));
            return NULL;
        }
    }
    return PyLong_FromLong(sts);
}

/*  define functions in module */
static PyMethodDef PastmlMethods[] =
        {
                {"infer_ancestral_states", infer_ancestral_states, METH_VARARGS,
                        "Infer tree ancestral states with PASTML.\n"
                        "\n"
                        "   :param annotation_file: str, path to the annotation file containing tip states (in csv format: <tip_id>,<state>);\n"
                        "                           should not contain any header, must include all tips (leave <state> blank when unknown)\n"
                        "   :param tree_file: str, path to the rooted tree file (in newick format)\n"
                        "\n"
                        "optional arguments (set to \"\" to omit it):\n"
                        "   :param out_annotation_file: str, path where the output annotation file containing node states will be created (in csv format),\n"
                        "                               if not specified, it will be generated by adding a suffix to the input annotation file name\n"
                        "   :param out_tree_file: str, if specified, the tree with named internal nodes will be saved to this file (in newick format)\n"
                        "   :param prediction_method: str, ancestral state prediction method;\n"
                        "                             can be one of the ML methods: pastml.MARGINAL_APPROXIMATION (default, marginal posterior probabilities approximation (MPPA)),\n"
                        "                             pastml.MARGINAL, pastml.MAX_POSTERIORI (maximum a posteriori MAP), pastml.JOINT;\n"
                        "                             or one of the parsimonious methods: pastml.DOWNPASS, pastml.DELTRAN (delayed transformation),\n"
                        "                             or pastml.ACCTRAN (accelerated transformation)\n"
                        "\n"
                        "optional arguments for ML methods only (set to \"\" to omit it):\n"
                        "   :param model: str, state evolution model: pastml.F81 (default, Felsenstein 1981-like, character frequencies are optimised, or supplied via in_param_file argument),\n"
                        "                                             pastml.JC (Jukes-Cantor-like, all character frequencies and change rates are equal),\n"
                        "                                             or pastml.EFT (character frequencies are Estimated From the Tip state distribution)\n"
                        "   :param out_param_file: str, if specified, the model parameters (state frequencies, scaling factor)\n"
                        "                          will be saved to this file (in csv format)\n"
                        "   :param in_param_file: str, if specified, the parameters found in this file will be fixed to the corresponding values;\n"
                        "                         the file should be in csv format: <parameter>,<value>\n"
                        "                         where <parameter> can be scaling factor,\n"
                        "                         or (for F81 model only) state (<value> should contain its frequency, and all the states should be supplied);\n"
                        "                         all other parameters will be ignored; see the output of out_param_file for the file format example\n"
                        "   :param out_marginal_prob_file: str, (for marginal ML methods (MAP, MPPA, marginal) only) if specified,\n"
                        "                                  the marginal probabilities of node states will be saved to this file (in csv format)\n"
                        "\n"
                        "   :param quiet: int, set to non-zero value to prevent PASTML from printing log information.\n"},
                {NULL, NULL, 0, NULL}
        };

#if PY_MAJOR_VERSION >= 3
/* module initialization */
/* Python version 3*/
static struct PyModuleDef cModPyDem =
{
    PyModuleDef_HEAD_INIT,
    "pastml", "PASTML extension for Python 3",
    -1,
    PastmlMethods
};

PyMODINIT_FUNC
PyInit_pastml(void)
{
    PyObject *m = PyModule_Create(&cModPyDem);
    PyModule_AddStringMacro(m, MARGINAL_APPROXIMATION);
    PyModule_AddStringMacro(m, MARGINAL);
    PyModule_AddStringMacro(m, MAX_POSTERIORI);
    PyModule_AddStringMacro(m, DOWNPASS);
    PyModule_AddStringMacro(m, DELTRAN);
    PyModule_AddStringMacro(m, ACCTRAN);
    PyModule_AddStringMacro(m, JOINT);
    PyModule_AddStringMacro(m, JC);
    PyModule_AddStringMacro(m, EFT);
    PyModule_AddStringMacro(m, F81);
    return m;
}

#else

/* module initialization */
/* Python version 2 */
PyMODINIT_FUNC
initpastml(void) {
    (void) Py_InitModule("pastml", PastmlMethods);
}

#endif