/*
 * Vega Strike
 * Copyright (C) 2001-2002 Daniel Horn
 *
 * http://vegastrike.sourceforge.net/
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/*
 *  xml Configuration written by Alexander Rawass <alexannika@users.sourceforge.net>
 */

#include <expat.h>
#include "xml_support.h"
#include <assert.h>
#include "configxml.h"
#include "easydom.h"

using std::cout;
using std::cerr;
using std::endl;

/* *********************************************************** */

VegaConfig::VegaConfig( const char *configfile )
{
    configNodeFactory *domf = new configNodeFactory();
    configNode *top = (configNode*) domf->LoadXML( configfile );
    if (top == NULL) {
        cout<<"Panic exit - no configuration"<<endl;
        exit( 0 );
    }
    variables = NULL;
    colors    = NULL;
    checkConfig( top );
}

VegaConfig::~VegaConfig()
{
    if (variables != NULL)
        delete variables;
    if (colors != NULL)
        delete colors;
    if (bindings != NULL)
        delete bindings;
}

/* *********************************************************** */

bool VegaConfig::checkConfig( configNode *node )
{
    if (node->Name() != "vegaconfig") {
        cout<<"this is no Vegastrike config file"<<endl;
        return false;
    }
    vector< easyDomNode* >::const_iterator siter;
    for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        if (cnode->Name() == "variables")
            doVariables( cnode );
        else if (cnode->Name() == "colors")
            doColors( cnode );
        else if (cnode->Name() == "bindings")
            bindings = cnode;              //delay the bindings until keyboard/joystick is initialized
        else
            cout<<"Unknown tag: "<<cnode->Name()<<endl;
    }
    return true;
}

/* *********************************************************** */

void VegaConfig::doVariables( configNode *node )
{
    if (variables != NULL) {
        cout<<"only one variable section allowed"<<endl;
        return;
    }
    variables = node;

    vector< easyDomNode* >::const_iterator siter;
    for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        checkSection( cnode, SECTION_VAR );
    }
}

/* *********************************************************** */

void VegaConfig::doSection( string prefix, configNode *node, enum section_t section_type )
{
    string section = node->attr_value( "name" );
    if ( section.empty() )
        cout<<"no name given for section"<<endl;
    vector< easyDomNode* >::const_iterator siter;
    for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        if (section_type == SECTION_COLOR) {
            checkColor( prefix, cnode );
        } else if (section_type == SECTION_VAR) {
            if (cnode->Name() == "var")
                doVar( prefix, cnode );
            else if (cnode->Name() == "section")
                doSection( prefix+cnode->attr_value( "name" )+"/", cnode, section_type );
            else
                cout<<"neither a variable nor a section"<<endl;
        }
    }
}

/* *********************************************************** */

void VegaConfig::checkSection( configNode *node, enum section_t section_type )
{
    if (node->Name() != "section") {
        cout<<"not a section"<<endl;
        node->printNode( cout, 0, 1 );

        return;
    }
    doSection( node->attr_value( "name" )+"/", node, section_type );
}

/* *********************************************************** */

void VegaConfig::doVar( string prefix, configNode *node )
{
    string name     = node->attr_value( "name" );
    string value    = node->attr_value( "value" );
    string hashname = prefix+name;
    map_variables[hashname] = value;
    if ( name.empty() )
        cout<<"no name given for variable "<<name<<" "<<value<<" "<<endl;
}

/* *********************************************************** */

void VegaConfig::checkVar( configNode *node )
{
    if (node->Name() != "var") {
        cout<<"not a variable"<<endl;
        return;
    }
    doVar( "", node );
}

/* *********************************************************** */

bool VegaConfig::checkColor( string prefix, configNode *node )
{
    if (node->Name() != "color") {
        cout<<"no color definition"<<endl;
        return false;
    }
    if ( node->attr_value( "name" ).empty() ) {
        cout<<"no color name given"<<endl;
        return false;
    }
    string  name     = node->attr_value( "name" );
    string  hashname = prefix+name;

    vColor *color;
    if ( node->attr_value( "ref" ).empty() ) {
        string r = node->attr_value( "r" );
        string g = node->attr_value( "g" );
        string b = node->attr_value( "b" );
        string a = node->attr_value( "a" );
        if ( r.empty() || g.empty() || b.empty() || a.empty() ) {
            cout<<"neither name nor r,g,b given for color "<<node->Name()<<endl;
            return false;
        }
        float   rf = atof( r.c_str() );
        float   gf = atof( g.c_str() );
        float   bf = atof( b.c_str() );
        float   af = atof( a.c_str() );

        vColor &vc = map_colors[hashname];
        vc.name.erase();
        vc.r     = rf;
        vc.g     = gf;
        vc.b     = bf;
        vc.a     = af;

        color    = new vColor;

        color->r = rf;
        color->g = gf;
        color->b = bf;
        color->a = af;
    } else {
        float  refcol[4];

        string ref_section = node->attr_value( "section" );
        string ref_name    = node->attr_value( "ref" );
        if ( ref_section.empty() ) {
            cout<<"you have to give a referenced section when referencing colors"<<endl;
            ref_section = "default";
        }
        getColor( ref_section, ref_name, refcol );

        vColor &vc = map_colors[hashname];
        vc.name  = ref_section+"/"+ref_name;
        vc.r     = refcol[0];
        vc.g     = refcol[1];
        vc.b     = refcol[2];
        vc.a     = refcol[3];

        color    = new vColor;

        color->r = refcol[0];
        color->g = refcol[1];
        color->b = refcol[2];
        color->a = refcol[3];
    }
    color->name = node->attr_value( "name" );

    node->color = color;

    return true;
}

/* *********************************************************** */

void VegaConfig::doColors( configNode *node )
{
    if (colors != NULL) {
        cout<<"only one variable section allowed"<<endl;
        return;
    }
    colors = node;

    vector< easyDomNode* >::const_iterator siter;
    for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        checkSection( cnode, SECTION_COLOR );
    }
}

/* *********************************************************** */

string VegaConfig::getVariable( string section, string subsection, string name, string defaultvalue )
{
    string hashname = section+"/"+subsection+"/"+name;
    std::map< string, string >::iterator it;
    if ( ( it = map_variables.find( hashname ) ) != map_variables.end() )
        return (*it).second;

    else
        return defaultvalue;
}

/* *********************************************************** */

string VegaConfig::getVariable( string section, string name, string defaultval )
{
    string hashname = section+"/"+name;
    std::map< string, string >::iterator it;
    if ( ( it = map_variables.find( hashname ) ) != map_variables.end() )
        return (*it).second;

    else
        return defaultval;
}

/* *********************************************************** */

string VegaConfig::getVariable( configNode *section, string name, string defaultval )
{
    vector< easyDomNode* >::const_iterator siter;
    for (siter = section->subnodes.begin(); siter != section->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        if ( (cnode)->attr_value( "name" ) == name )
            return (cnode)->attr_value( "value" );
    }
    static bool foundshouldwarn = false;
    static bool shouldwarn = true;
    if (!foundshouldwarn) {
        if (name != "debug_config") {
            shouldwarn = XMLSupport::parse_bool( getVariable( "general", "debug_config", "true" ) );
            foundshouldwarn = true;
        }
    }
    if (shouldwarn)
        cout<<"WARNING: no var named "<<name<<" in section "<<section->attr_value( "name" )<<" using default: "<<defaultval
            <<endl;
    return defaultval;
}

/* *********************************************************** */

void VegaConfig::gethColor( string section, string name, float color[4], int hexcolor )
{
    color[3] = ( (float) (hexcolor&0xff) )/256.0;
    color[2] = ( (float) ( (hexcolor&0xff00)>>8 ) )/256.0;
    color[1] = ( (float) ( (hexcolor&0xff0000)>>16 ) )/256.0;
    color[0] = ( (float) ( (hexcolor&0xff000000)>>24 ) )/256.0;

    getColor( section, name, color, true );
}

/* *********************************************************** */

void VegaConfig::getColor( string section, string name, float color[4], bool have_color )
{
    string hashname = section+"/"+name;
    std::map< string, vColor >::iterator it;
    if ( ( it = map_colors.find( hashname ) ) != map_colors.end() ) {
        color[0] = (*it).second.r;
        color[1] = (*it).second.g;
        color[2] = (*it).second.b;
        color[3] = (*it).second.a;
    } else if (!have_color) {
        color[0] = color[1] = color[2] = color[3] = 1.0f;
    }
}

/* *********************************************************** */

void VegaConfig::getColor( configNode *node, string name, float color[4], bool have_color )
{
    vector< easyDomNode* >::const_iterator siter;
    for (siter = node->subnodes.begin(); siter != node->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        if ( (cnode)->attr_value( "name" ) == name ) {
            color[0] = (cnode)->color->r;
            color[1] = (cnode)->color->g;
            color[2] = (cnode)->color->b;
            color[3] = (cnode)->color->a;
            return;
        }
    }
    if (have_color == false) {
        color[0] = 1.0;
        color[1] = 1.0;
        color[2] = 1.0;
        color[3] = 1.0;

        cout<<"WARNING: color "<<name<<" not defined, using default (white)"<<endl;
    } else {
        cout<<"WARNING: color "<<name<<" not defined, using default (hexcolor)"<<endl;
    }
}

/* *********************************************************** */

configNode* VegaConfig::findEntry( string name, configNode *startnode )
{
    return findSection( name, startnode );
}

/* *********************************************************** */

configNode* VegaConfig::findSection( string section, configNode *startnode )
{
    vector< easyDomNode* >::const_iterator siter;
    for (siter = startnode->subnodes.begin(); siter != startnode->subnodes.end(); siter++) {
        configNode *cnode = (configNode*) (*siter);
        string scan_name  = (cnode)->attr_value( "name" );
        if (scan_name == section)
            return cnode;
    }
    cout<<"WARNING: no section/variable/color named "<<section<<endl;

    return NULL;
}

/* *********************************************************** */

void VegaConfig::setVariable( configNode *entry, string value )
{
    entry->set_attribute( "value", value );
}

/* *********************************************************** */

bool VegaConfig::setVariable( string section, string name, string value )
{
    configNode *sectionnode = findSection( section, variables );
    if (sectionnode != NULL) {
        configNode *varnode = findEntry( name, sectionnode );
        if (varnode != NULL)
            //now set the thing
            setVariable( varnode, value );
    }
    string hashname = section+"/"+name;
    map_variables[hashname] = value;
    return true;
}

bool VegaConfig::setVariable( string section, string subsection, string name, string value )
{
    configNode *sectionnode = findSection( section, variables );
    if (sectionnode != NULL) {
        configNode *subnode = findSection( name, sectionnode );
        if (subnode != NULL) {
            configNode *varnode = findEntry( name, subnode );
            if (varnode != NULL)
                //now set the thing
                setVariable( varnode, value );
        }
    }
    string hashname = section+"/"+subsection+"/"+name;
    map_variables[hashname] = value;
    return true;
}

