/** @file InitData.c
 *
 *  @ingroup ippToPsps
 *
 *  @author IfA
 *  Copyright 2011 Institute for Astronomy, University of Hawaii
 */

#include "InitData.h"
#include "Fits.h"


/**
  Gets an attribute value from XML node
  */
static bool getAttribute(xmlNode* node, const char* attName, char* _value) {

    xmlChar* value = xmlGetProp(node, (const xmlChar*)attName);
    if (!value) return false;
    sprintf(_value, "%s", value);
    xmlFree(value);

    return true;
}

/**
  Searches through this table and finds attribute value for a provided key
  */
static bool getRowAttribute(
        InitData* this, 
        xmlNode* tableNode,
        const char* keyName, 
        const char* keyValue,
        const char* attName, 
        char* attValue) {

    xmlNode* node = NULL;

    char buffer[100];

    // loop round all available rows for this table
    for (node = tableNode->children; node; node = node->next) {
        if (node->type == XML_ELEMENT_NODE) {
            //psLogMsg("ippToPsps", PS_LOG_INFO, "Node name '%s'",  (const char*)node->name );

            if (strcmp((const char*)node->name, "row")==0) {
                //psLogMsg("ippToPsps", PS_LOG_INFO, " Looking for key '%s'",  keyName );

                if (!getAttribute(node, keyName, buffer)) continue;
                //psLogMsg("ippToPsps", PS_LOG_INFO, "Found key '%s' value '%s'",  keyName, buffer );

                if (strcmp(buffer, keyValue) != 0) continue;
                getAttribute(node, attName, attValue);
                //printf("FOUND %s %s %s %s \n", keyName, buffer, attName, attValue );
                return true;

            }
        }
    }

    this->logger->print(this->logger, MSG_ERROR, 
            "InitData", "Could not find value for '%s' for '%s' with value '%s'\n", 
            attName, keyName, keyValue);

    return false;
}

/**
  Gets a value from the 'init' data 
  */
static bool getInitValue(
        InitData* this, 
        const char* tableName,
        const char* keyName, 
        const char* keyValue,
        const char* attName, 
        char* attValue) {

    bool ret = true;

    xmlNode* rootElement = xmlDocGetRootElement(this->doc);

    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
        this->logger->print(this->logger, MSG_ERROR, 
                "InitData", "Root node of XML is not 'tabledata', as it should be\n");
        return false;
    }

    xmlNode* node = NULL;
    char tempStr[100];

    // loop round all available tables
    for (node = rootElement->children; node; node = node->next) {
        if (node->type == XML_ELEMENT_NODE) {

            if (strcmp((const char*)node->name, "table")!=0) continue;
            if (!getAttribute(node, "name", tempStr)) continue;
            if (strcmp(tempStr, tableName)!=0) continue;

            ret = getRowAttribute(this, node, keyName, keyValue, attName, attValue);
            break;
        }

    }

    return ret;
}

/**
   Gets model fit ID from name
   */
static bool getModelFitId(InitData* this, const char* name, int8_t* id) {

    char buffer[10];
    if (!getInitValue(this, "FitModel", "name", name, "fitModelID", buffer)) {

        *id = -1;
        return false;
    }

    *id = atoi(buffer);
    return true;
}

/**
   Gets survey ID from survey name
   */
static bool getSurveyId(InitData* this, const char* name, int8_t* id) {

    char buffer[10];
    if (!getInitValue(this, "Survey", "name", name, "surveyID", buffer)) {

        *id = -1;
        return false;
    }

    *id = atoi(buffer);
    return true;
}

/**
   Gets stack type ID from stack type string
   */
static bool getStackTypeId(InitData* this, const char* type, int8_t* id) {

    char buffer[20];
    if (!getInitValue(this, "StackType", "stackType", type, "stackTypeID", buffer)) {

        *id = -1;
        return false;
    }

    *id = atoi(buffer);
    return true;
}

/**
   Gets filter ID from filter type string
   */
static bool getFilterId(InitData* this, const char* type, int8_t* id) {

    char tmp[2];
    strncpy(tmp, type,1);
    tmp[1] = '\0';
    char buffer[10];
    if (!getInitValue(this, "Filter", "filterType", tmp, "filterID", buffer)) {

        *id = -1;
        return false;
    }

    *id = atoi(buffer);
    return true;
}

/**
  Destructor.
  */
static void destroy(InitData* this) {

    if (this == NULL) return;

    if (this->doc != NULL) {

        xmlFreeDoc(this->doc);
        xmlCleanupParser();
    }

    this->logger->print(this->logger, MSG_DEBUG, "InitData", "Destructor\n");

    free(this);
}

/**
  Constructor.
  */
InitData* new_InitData(const char* path, Logger* logger) {

    InitData* this = (InitData*)calloc(1, sizeof(InitData));
    this->logger = logger;

    this->logger->print(this->logger, MSG_DEBUG, "InitData", "Constructor\n");

    sprintf(this->path, "%s/init/data.xml", path);

    this->doc = xmlReadFile(this->path, NULL, 0);

    if (this->doc == NULL)
        this->logger->print(this->logger, MSG_ERROR, 
                "InitData", "Unable to open init data file at '%s'\n", this->path);
    else
        this->logger->print(this->logger, MSG_INFO, 
                "InitData", "Using init data file at '%s'\n", this->path);


    // method pointers
    this->getFilterId = getFilterId;
    this->getSurveyId = getSurveyId;
    this->getStackTypeId = getStackTypeId;
    this->getModelFitId = getModelFitId;
    this->destroy = destroy;

    return this;
}

