#include "NuoscParam.h"
#include "options.h"
#include <iostream>
#include <vector>

NuoscParam::NuoscParam()
{
    this->init();
}
NuoscParam::NuoscParam(int& argc, const char** argv)
{
    this->init();
    this->parse_args(argc,argv);
}
NuoscParam::~NuoscParam() 
{
    if (options) delete options;
}

void NuoscParam::usage(const char* msg) 
{
    if (!options) return;
    options->usage(cerr,msg);
}

void NuoscParam::init() 
{
    type = 2;
    matter = 1;
    ss2t12 = 0.8;
    ss2t23 = 1.0;
    ss2t13 = 0.1;
    cpphase = 0.0;
    dm2sol = 5.0e-5;
    dm2atm = 3.0e-3;
    baseline = 735.340e5;
    options = 0;
}

Options* NuoscParam::parse_args(int& argc, const char** argv)
{
    const char * optv[] = {
        "t+theta <theta_12 theta_23 theta_13> degrees",
        "S+sin  <sin^2(2theta_12) sin^2(2theta_23) sin^2(2theta_13)>",
        "s:sol <dm2_sol|dm2_21> default = 5.0e-5 eV^2",
        "a:atm <dm2_atm|dm2_32> default = 3.0e-3 eV^2",
        "d:delta <CP phase>, default = 0 degrees",
        "v+neturino-vector <nue numu nutau>, default=0 1 0",
        "1|nue",                // equiv to -v 1 0 0
        "2|numu",               // equiv to -v 0 1 0
        "3|nutau",              // equiv to -v 0 0 1
        "4|antinue",                // equiv to -v -1  0  0
        "5|antinumu",               // equiv to -v  0 -1  0
        "6|antinutau",              // equiv to -v  0  0 -1
        "b:baseline <baseline> default = 735 km",
        "m|use-matter-effects", // default
        "n|no-matter-effects",
        0
    };

    options = new Options(*argv, optv);
    OptArgvIter optitr(argc-1,argv+1);
    const char* optarg;

    vector<const char*> newargv;
    newargv.push_back(argv[0]);

    char optchar;
    cerr << "NuoscProb: ctrls: " << options->ctrls() << endl;
    options->ctrls(Options::PARSE_POS);
    while ((optchar = (*options)(optitr,optarg))) {
        switch (optchar) {
        case 't':
            if (optarg) {
                double theta_12 = atof(optarg)*M_PI/180.0;
                double ss = sin(2*theta_12);
                ss2t12 = ss*ss;
            }
            else usage("Bad theta_12 value");
            optarg = optitr();
            if (optarg) {
                double theta_23 = atof(optarg)*M_PI/180.0;
                double ss = sin(2*theta_23);
                ss2t23 = ss*ss;
            }
            else usage("Bad theta_23 value");
            optarg = optitr();
            if (optarg) {
                double theta_13 = atof(optarg)*M_PI/180.0;
                double ss = sin(2*theta_13);
                ss2t13 = ss*ss;
            }
            else usage("Bad theta_13 value");
            break;
        case 'S':
            if (optarg) ss2t12 = atof(optarg);
            else usage("Bad theta_12 value");
            optarg = optitr();
            if (optarg) ss2t23 = atof(optarg);
            else usage("Bad theta_23 value");
            optarg = optitr();
            if (optarg) ss2t13 = atof(optarg);
            else usage("Bad theta_13 value");
            break;
        case 's':
            if (optarg) dm2sol = atof(optarg);
            else usage("Bad dm2_sol value");
            break;
        case 'a':
            if (optarg) dm2atm = atof(optarg);
            else usage("Bad dm2_atm value");
            break;
        case 'd':
            cerr << "using cp phase: " << optarg << endl;
            if (optarg) cpphase = atof(optarg)*M_PI/180.0;
            else usage("Bad CP phase value");
            break;
        case '1':               // pure nue
            type = 1;
            break;
        case '2':               // pure numu
            type = 2;
            break;
        case '3':               // pure nutau
            type = 3;
            break;
        case '4':               // pure antinue
            type = -1;
            break;
        case '5':               // pure antinumu
            type = -2;
            break;
        case '6':               // pure antinutau
            type = -3;
            break;
        case 'b':
            if (optarg) baseline = atof(optarg)*1.0e5;
            else usage("Bad baseline value");
            break;
        case 'm':
            matter = 1;
            break;
        case 'n':
            matter = 0;
            break;
        case Options::POSITIONAL:
            newargv.push_back(optarg);
            break;
        default:                // pass along unknown
            cerr << "optitr.index=" << optitr.index() << endl;
            newargv.push_back(argv[optitr.index()]);
//            usage("Unknown option");
            break;
        }
    }

    argc =  newargv.size();
    for (int i = 0; i < argc; ++i) {
        argv[i] = newargv[i];
    }
    
    return options;
}
