/***************************************************************************
                          lconfig.cpp  -  description
                             -------------------
    begin                : Fri Jan 17 2003
    copyright            : (C) 2003 by Sheldon Lee Wen
    email                : leewsb@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <lineak/lconfig.h>
#include <lineak/lineak_util_functions.h>
#include <lineak/lineak_core_functions.h>
#include <lineak/configdirectives.h>
#include <lineak/lkbd.h>
#include <lineak/lobject.h>
#include <lineak/lkey.h>
#include <lineak/lcommand.h>

using namespace lineak_util_functions;
using namespace lineak_core_functions;

//vector<string> LConfig::special_dirs;
//bool LConfig::special_dirs_init = false;

LConfig::LConfig() {
}
LConfig::LConfig(const LConfig & rhs) : LConfigData() {
	if (this != &rhs) {
		keycommtable = rhs.keycommtable;
		
                directives.clear();
    		directives = rhs.directives;
                vec.clear();
                vec = rhs.vec;
	}
}
LConfig & LConfig::operator=(const LConfig & rhs) {
	if (this != &rhs) {
		keycommtable = rhs.keycommtable;
		
                directives.clear();
    		directives = rhs.directives;
                vec.clear();
                vec = rhs.vec;
	}
	return *this;
}
LConfig::LConfig(ConfigDirectives &dirs) {
	directives = dirs;
	if (directives.isEmpty())
		error("Creating a config with no ConfigDirectives!");
}
LConfig::~LConfig(){
}
/** Empty all data */
void LConfig::clear() {
  directives.clear();
  keycommtable.clear();
  vec.clear();
}
/** Return a list of keynames that we have LCommands for. */
/*const vector<string>& LConfig::getCommandKeyNames(){
	vec.clear();
	for (map<const string, LCommand>::const_iterator i = comtable.begin(); i != comtable.end(); i++)
		vec.push_back(i->first);
	return vec;
} */
/** Return a map of commands indexed by keycodes. */
/* map<const int,  LCommand> LConfig::getKeyCommandIndex(const map< string, LObject*>& skeys) {
	map<const int,  LCommand> table;
	string comm;
	for ( map< string, LObject*>::const_iterator i = skeys.begin(); i != skeys.end(); i++ ) {
	   if( i->second->getType() == CODE || i->second->getType() == SYM ) {
	      const LKey * key = static_cast<const LKey*>(i->second);
	      table[key->getKeyCode()] = comtable[i->first];
	   }
	}
	return (table);
} */
/** Return a map of commands indexed by keycodes. */
/* map<const int,  LCommand> LConfig::getKeyCommandIndex(const LKbd& keyboard) {
	return (getKeyCommandIndex(keyboard.getObjects()));
} */
/** Return a map of commands indexed by keycodes. */
/* map<const unsigned int,  LCommand> LConfig::getButtonCommandIndex(const map< string, LObject*>& skeys) {
	map<const unsigned int,  LCommand> table;
	string comm;
	for ( map< string, LObject*>::const_iterator i = skeys.begin(); i != skeys.end(); i++ ) {
	   if( i->second->getType() == BUTTON ) {
	      const LKey * key = static_cast<const LKey*>(i->second);
	      table[key->getKeyCode()] = comtable[i->first];
	   }
	}
	return (table);
} */
/** Return a map of commands indexed by keycodes. */
/* map<const unsigned int,  LCommand> LConfig::getButtonCommandIndex(const LKbd& keyboard) {
	return (getButtonCommandIndex(keyboard.getObjects()));
} */
/* LCommand& LConfig::getCommand(const string& key) {
	return comtable[key];
} */
/*
void LConfig::setCommand(string key, LCommand command) {
	comtable[key] = command;
} */
/*
void LConfig::addKey(string key, LCommand command, bool respect_toggle) {
//  cout << "Setting command\n";
//  lineak_util_functions::inspect_vector(command.getArgs());
	if (!respect_toggle)
		setCommand(key, command);

} */
/** Add a name, modifier mapping to the modtable map */
/* void LConfig::addModifier(string key, unsigned int modifiers) {
   modtable[key] = modifiers;
} */
/** Get a modifier for a key */
/* unsigned int LConfig::getModifier(const string & key) {
   return modtable[key];
} */
string LConfig::getValue(string key) const {
	return directives.getValue(key);
}
void LConfig::setValue(string key, string value) {
	directives.addValue(key,value);
}
int LConfig::getIntValue(string key) const {
	return directives.getIntValue(key);
}
void LConfig::setValue(string key, int value) {
	directives.addValue(key,value);
}
/** Set the configfilename */
void LConfig::setFilename(string file) {
	directives.addValue(_CD_USERCONFFILE, file);
}
/** Add a keycomm to the configuration. */
void LConfig::addKeycomm(const string key, keycommand_info info) {
    map<const string, vector<keycommand_info> >::iterator it = keycommtable.begin();
    it = keycommtable.find(key);
    if (key.find('+') != string::npos)
       cerr << "WARNING, YOU ARE ADDING AN UNPARSED KEYNAME TO THE LCONFIG. THIS WILL NOT WORK!!!" << endl;
    if ( it == keycommtable.end() ) {
       vector<keycommand_info> tvec;
       tvec.push_back(info);
       keycommtable[key] = tvec;
    }
    else {
       // Check to make sure you are not adding a duplicate, that is exactly the same.
       vector<keycommand_info> tmp = keycommtable[key];
       vector<keycommand_info>::iterator mit = tmp.begin();
       for (; mit != tmp.end(); mit++) {
	       if ( mit->config_name == info.config_name &&
		    mit->parsed_name == info.parsed_name &&
		    mit->modifiers == info.modifiers &&
		    mit->command.getCommand() == info.command.getCommand() ) break;
       }
       
       //mit = tmp.find(info);
       if ( mit == tmp.end() ) {
//FIXME       if ( /** if the vector already contains this keycommand_info, we are adding a duplicate */ )
          //cout << "Adding keycommand_info" << endl;
          keycommtable[key].push_back(info); }
       else {
	  // This was the default before.
	  cout << "Attempting to add duplicate entry: WARNING I MAY BE BREAKING MODIFIERS HERE!" << endl;
	  cout << "string = " << key << " command = " << info.command.getCommand() << endl;
          //keycommtable[key].push_back(info);
       }
    }
}
vector<keycommand_info>& LConfig::getKeycomm(const string key) {
    map<const string, vector<keycommand_info> >::iterator it = keycommtable.begin();
    it = keycommtable.find(key);
    if ( it != keycommtable.end() ) {
       return (keycommtable[key]);
    }
    else {
       tv.clear();
       return tv;
    }
}
/** Is this an empty object? Our critieria of being empty is:
	if both the conffilename and KeyboardType values are undefined or snull
	if the command table is empty
	*/
bool LConfig::isEmpty(){
	msg("Checking some isSet's to see if they are empty.");
	if ((!directives.isSet(_CD_KEYBOARD_TYPE) && !directives.isSet(_CD_USERCONFFILE)) || keycommtable.empty() )
		return false;
        msg("Checking the KeyboardType and conffilename to see if they are empty.");
	return ((directives.getValue(_CD_KEYBOARD_TYPE) == snull) && (directives.getValue(_CD_USERCONFFILE) == snull));
}
// /** UPdate the list of macros we support. */
// void LConfig::setDirectives(const vector<string>& directivelist) {
// 	if (specials_dirs_init)
// 		specials_dirs.clear();
// 
// 	special_dirs = directivelist;
// 	special_dirs_init = true;
// }

void LConfig::print(ostream &out) {
        //cout << "printing lconfig\n";
	//string value;
    	out << CONF_HEADER;
	//string kbtype, cd, mix, conf;

    	// WE MAY WANT TO JUST DO:  out << directives << endl;
	directives.print(out);
	out << endl;
	// Output all of the commands now.
    	LCommand command;
	for (map<const string, vector<keycommand_info> >::const_iterator i = keycommtable.begin(); i != keycommtable.end(); i++ ) {
	        const vector<keycommand_info>& comms = (i->second);
		
	        for (unsigned int j = 0; j < (i->second).size(); j++) {
		     out << comms[j].config_name << " = ";
		     command = comms[j].command;
		     out << command.getCommand() << endl;
		}
    	}
}
