/*
 * pxinject.c
 *
 * Copyright (C) 2006  Joshua Hoblitt
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; version 2 of the License.
 *
 * This program 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
 * program; see the file COPYING. If not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <ippdb.h>
#include <string.h>

#include "pxtools.h"
#include "pxinject.h"

static bool newExpMode(pxConfig *config);
static bool newImfileMode(pxConfig *config);
static bool updatenewExpMode(pxConfig *config);

# define MODECASE(caseName, func) \
    case caseName: \
    if (!func(config)) { \
        goto FAIL; \
    } \
    break;

int main(int argc, char **argv)
{
    psLibInit(NULL);

    pxConfig *config = pxinjectConfig(NULL, argc, argv);
    if (!config) {
        psError(PXTOOLS_ERR_CONFIG, false, "failed to configure");
        goto FAIL;
    }

    switch (config->mode) {
        MODECASE(PXINJECT_MODE_NEWEXP, newExpMode);
        MODECASE(PXINJECT_MODE_NEWIMFILE, newImfileMode);
        MODECASE(PXINJECT_MODE_UPDATENEWEXP, updatenewExpMode);
        default:
            psAbort("invalid option (this should not happen)");
    }

    psFree(config);
    pmConfigDone();
    psLibFinalize();

    exit(EXIT_SUCCESS);

FAIL:
    psErrorStackPrint (stderr, "failure\n");
    int exit_status = pxerrorGetExitStatus();

    psFree(config);
    pmConfigDone();
    psLibFinalize();

    exit(exit_status);
}

static bool newExpMode(pxConfig *config)
{
    PS_ASSERT_PTR_NON_NULL(config, false);

    bool status = false;
    psString tmp_exp_name = psMetadataLookupStr(&status, config->args, "-tmp_exp_name");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -tmp_exp_name");
        return false;
    }
    if (!tmp_exp_name) {
        psError(PS_ERR_UNKNOWN, true, "-tmp_exp_name is required");
        return false;
    }
    psString tmp_camera = psMetadataLookupStr(&status, config->args, "-tmp_inst");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -tmp_inst");
        return false;
    }
    if (!tmp_camera) {
        psError(PS_ERR_UNKNOWN, true, "-tmp_inst is required");
        return false;
    }
    psString tmp_telescope = psMetadataLookupStr(&status, config->args, "-tmp_telescope");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -tmp_telescope");
        return false;
    }
    if (!tmp_telescope) {
        psError(PS_ERR_UNKNOWN, true, "-tmp_telescope is required");
        return false;
    }

    psString workdir = psMetadataLookupStr(&status, config->args, "-workdir");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -workdir");
        return false;
    }
    if (!workdir) {
        psError(PS_ERR_UNKNOWN, true, "-workdir is required");
        return false;
    }

    psString reduction = psMetadataLookupStr(&status, config->args, "-reduction");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -reduction");
        return false;
    }

    if (!newExpInsert(config->dbh,
                0x0, // exp_id
                tmp_exp_name,
                tmp_camera,
                tmp_telescope,
                "reg", // state
                workdir,
                "dirty",
                reduction
            )
        ) {
        psError(PS_ERR_UNKNOWN, false, "database error");
        return false;
    }

    psS64 lastInsertID = psDBLastInsertID(config->dbh);
    psString exp_id = psDBIntToString(lastInsertID);

    psMetadata *md = psMetadataAlloc();
    if (!psMetadataAddStr(md, PS_LIST_TAIL, "exp_id", 0, NULL, exp_id)) {
        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_id");
        psFree(md);
        psFree(exp_id);
    }
    psFree(exp_id);

    bool simple = false;
    {
        bool status = false;
        simple = psMetadataLookupBool(&status, config->args, "-simple");
        if (!status) {
            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
            psFree(md);
            return false;
        }
    }

    // negate simple so the default is true
    if (!ippdbPrintMetadata(stdout, md, !simple)) {
        psError(PS_ERR_UNKNOWN, false, "failed to print array");
        psFree(md);
        return false;
    }

    psFree(md);

    return true;
}

static bool newImfileMode(pxConfig *config)
{
    PS_ASSERT_PTR_NON_NULL(config, false);

    bool status = false;
    psString exp_id = psMetadataLookupStr(&status, config->args, "-exp_id");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -exp_id");
        return false;
    }
    if (!exp_id) {
        psError(PS_ERR_UNKNOWN, true, "-exp_id is required");
        return false;
    }
#if 0
    psString class = psMetadataLookupStr(&status, config->args, "-class");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -class");
        return false;
    }
    if (!class) {
        psError(PS_ERR_UNKNOWN, true, "-class is required");
        return false;
    }
#endif
    psString tmp_class_id = psMetadataLookupStr(&status, config->args, "-tmp_class_id");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -tmp_class_id");
        return false;
    }
    if (!tmp_class_id) {
        psError(PS_ERR_UNKNOWN, true, "-tmp_class_id is required");
        return false;
    }
    psString uri = psMetadataLookupStr(&status, config->args, "-uri");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -uri");
        return false;
    }
    if (!uri) {
        psError(PS_ERR_UNKNOWN, true, "-uri is required");
        return false;
    }

    // insert with error flag state set to 0 (no errors)
    if (!newImfileInsert(config->dbh, (psS64)atoll(exp_id), tmp_class_id, uri)) {
        psError(PS_ERR_UNKNOWN, false, "database error");
        return false;
    }

    return true;
}


static bool updatenewExpMode(pxConfig *config)
{
    PS_ASSERT_PTR_NON_NULL(config, false);

    bool status = false;
    psString exp_id = psMetadataLookupStr(&status, config->args, "-exp_id");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -exp_id");
        return false;
    }
    if (!exp_id) {
        psError(PS_ERR_UNKNOWN, true, "-exp_id is required");
        return false;
    }

    psString state = psMetadataLookupStr(&status, config->args, "-state");
    if (!status) {
        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -state");
        return false;
    }
    if (!state) {
        psError(PS_ERR_UNKNOWN, true, "-state is required");
        return false;
    }

    if (state) {
        // set detRun.state to state
        return pxnewExpSetState(config, exp_id, state);
    }

    return true;
}
