#undef PARAMETER_NONE
#undef PARAMETER_STR
#undef PARAMETER_BOOL
#undef PARAMETER_NUM
#undef PARAMETER_LIST
#undef PARAMETER_SECTION
#undef PARAMETER_PAIR
#undef PUBLIC_PARM
#undef VECTOR_BOOL
#undef VECTOR_NUM
#undef VECTOR_STR
#undef VECTOR_MENU

#if !defined PARAM_CLASS
#undef PARAM_BASE
#undef CONFIG_INSTANCE
#undef CONFIG_DEFAULT
#undef CONFIG_DEFAULT_DONE
#undef CONFIG_PARSER
#undef CONFIG_PARSER_DONE
#undef CONFIG_WRITER
#undef CONFIG_WRITER_DONE
#undef WRITER_PROTO

/*****************************************
        Macros to declare the class
 *****************************************/

#define PARAM_CLASS(class_name) class class_name

// MACRO to declare Base functions, constructor & destructor

#ifdef USE_WRITER
#define WRITER_PROTO(class_name) void save_configuration_file();
#else
#define WRITER_PROTO(class_name)
#endif

#define PARAM_BASE(class_name) \
private: \
  static class_name *instance; \
  void set_default_configuration(); \
\
protected: \
  class_name(); \
\
public: \
  void parse_configuration_file(); \
  static class_name *get_instance(); \
  ~class_name(); \
  WRITER_PROTO(class_name)

// MACROs to define constructor, destructor, instanciator

#define CONFIG_INSTANCE(class_name) \
 class_name *class_name::instance = 0; \
 class_name *class_name::get_instance() \
{ \
  if (instance == 0) instance = new class_name; \
  return instance; \
} \
\
 class_name::~class_name() {} \
\
 class_name::class_name() { set_default_configuration(); }

// MACROs to define default_init

#define CONFIG_DEFAULT(class_name) \
  void class_name::set_default_configuration() {

#define CONFIG_DEFAULT_DONE }

// MACROS to define reader/parser

#define CONFIG_PARSER(class_name) \
 void class_name::parse_configuration_file() \
{ \
  std::ostringstream dev_null; \
  std::string config_location = "/etc/mms/config"; \
  struct stat file_stat; \
  if ((stat((homedir + "config").c_str(), &file_stat) == 0) ? true:false) \
    config_location = homedir + "config";	\
  Print print(gettext("Opening configuration file ") + config_location, \
	      Print::INFO, "Config"); \
  std::ostringstream conf; conf << config_location; \
  std::ifstream In(conf.str().c_str()); \
  std::string str; \
  bool version_correct = false; \
\
  if(!In) \
    Print perror(gettext("Config file not found ") + config_location, \
		 Print::DEBUGGING, "CONFIG"); \
  else \
  for( int line=1;getline(In, str);line++) { \
    std::string param, value; \
\
    std::string::size_type p0 = str.find_first_not_of("\t ");	\
    if ((p0 > str.size()) || (str[p0] == '#')) continue; \
\
    if (str[p0]=='[') { \
      p0=str.find_first_not_of("\t [",p0); \
      std::string::size_type p1 = str.find_last_not_of("\t ]"); \
      param = "[]"; \
      value = str.substr(p0,++p1-p0); \
   } else { \
\
    std::string::size_type p = str.find('=');	\
\
    if (!p) { \
      Print perror(gettext("Error while reading line ") + \
		   conv::itos(line) + gettext("missing '='"), \
		   Print::DEBUGGING, "CONFIG"); \
      continue; \
    } \
    std::string::size_type p1;			\
    for (std::string::size_type i = 0; i < str.size(); ++i)\
      if (str[i] == '\t' || str[i] == ' ' || str[i] == ':' || str[i] == '=') { \
									\
	p1 = i;								\
	break;								\
      }									\
    param = str.substr(p0, p1-p0); \
    p0=str.find_first_not_of("\t =",p); \
    p1=str.find_last_not_of("\t "); \
    value = p1<p0?"":str.substr(p0, ++p1-p0); \
\
    if (param == "version") { \
      if (value == MMS_CONFIG_VERSION) \
	version_correct = true; \
      else { \
        Print perror(Print::DEBUGGING, "CONFIG"); \
        perror.add_line(config_location + gettext(" is version ") + value + gettext(" and mms expecting version ") + MMS_CONFIG_VERSION); \
        perror.add_line(gettext("Please upgrade your config file")); \
        perror.print(); \
	version_correct = true; \
      } \
      continue; \
    } else if (!version_correct) { \
      Print perror(Print::DEBUGGING, "CONFIG"); \
      perror.add_line(gettext("Version string not found")); \
      perror.add_line(gettext("Please upgrade your config file")); \
      perror.print(); \
      exit(1); \
    } \
\
    } \
\
    dev_null << param << "PARSED VALUE =" << value << std::endl;

#define CONFIG_PARSER_DONE \
  Print perror(gettext("Unknown token '") + param + \
	       gettext("' on line ") + conv::itos(line), \
	       Print::DEBUGGING, "CONFIG"); \
  } \
}


#ifdef USE_WRITER

// Macros to  define writer/formatter

#define CONFIG_WRITER(class_name) \
\
void class_name::save_configuration_file()\
{ \
\
  std::ostringstream conf; conf << PARAMETER_FILE; \
  std::ofstream Out(conf.str().c_str()); \
\
  if (!Out) { \
    DebugPrint perror(gettext("Can't write configuration file!"), 
		      Print::DEBUGGING, DebugPrint::CRITICAL, "CONFIG"); \
    return; \
  } else { \
    Out << "# Config File Definition Tool" << std::endl << std::endl;

#define CONFIG_WRITER_DONE \
  } \
}
#else
#define CONFIG_WRITER(class_name)
#endif

// MACROs to inhibit unneeded config parameters

#define PARAMETER_NONE(name)
#define PARAMETER_STR(name,variable,default)
#define PARAMETER_BOOL(name,variable,default)
#define PARAMETER_NUM(name,variable,default)
#define PARAMETER_LIST(name,variable)
#define PARAMETER_SECTION(variable)
#define PARAMETER_PAIR(name,variable)
#define PUBLIC_PARM(x)
#define VECTOR_BOOL(name,variable,default)
#define VECTOR_NUM(name,variable,lowbound,hibound,default)
#define VECTOR_STR(name,variable,value_list,default)
#define VECTOR_MENU(name,variable,value_list)



#elif !defined PRIVATE_PAR


/*****************************************
  Macros to declare Private Variables
 *****************************************/

#define PRIVATE_PAR

#define PARAMETER_NONE(name)
#define PARAMETER_STR(name,variable,default)  std::string variable;
#define PARAMETER_BOOL(name,variable,default) bool variable;
#define PARAMETER_NUM(name,variable,default)  int  variable;
#define PARAMETER_LIST(name,variable) std::list<std::string> variable;
#ifdef USE_SECTION
#define PARAMETER_SECTION(variable) std::list<std::string>variable;
#endif
#define PARAMETER_PAIR(name,variable) std::list<std::pair<std::string,std::string> > variable;
#define PUBLIC_PARM(x)

#define VECTOR_BOOL(name,variable,default) 
#define VECTOR_NUM(name,variable,lowbound,hibound,default) 
#define VECTOR_STR(name,variable,value_list,default) 
#define VECTOR_MENU(name,variable,value_list) 


#elif !defined PUBLIC_PAR

/*****************************************
    Macros to declare public Variables
 *****************************************/

#define PUBLIC_PAR

#define ADD_PARAM(variable,type) type p_##variable() const { return variable; }
#define PARAMETER_NONE(name)
#define PARAMETER_STR(name,variable,default)  ADD_PARAM(variable,std::string)
#define PARAMETER_BOOL(name,variable,default) ADD_PARAM(variable,bool)
#define PARAMETER_NUM(name,variable,default)  ADD_PARAM(variable,int)
#define PARAMETER_LIST(name,variable)         ADD_PARAM(variable,std::list<std::string>)
#ifdef USE_SECTION
#define PARAMETER_SECTION(variable)           ADD_PARAM(variable,std::list<std::string>)
#endif
#define PARAMETER_PAIR(name,variable)         std::list<std::pair<std::string,std::string> > p_##variable() const { return variable; }
#define PUBLIC_PARM(x)                        x;

#define VECTOR_BOOL(name,variable,default) \
 bool variable; \
 std::vector<bool> variable##_values;

#define VECTOR_NUM(name,variable,lowbound,hibound,default) \
 int variable;\
 std::vector<int> variable##_values;

#define VECTOR_MENU(name,variable,value_list) \
 std::vector<std::string> variable;

#define VECTOR_STR(name,variable,value_list,default) \
 std::vector<std::string> variable##_values;\
 std::string variable;


/*****************************************
    Macros to define init/default values
 *****************************************/

#elif !defined DEFAULT_PAR
#define DEFAULT_PAR

// These MACROS are working the opposite as indirect stringifier STR_
// they remove parenthesis from a parameter and insert a comma
// making a list for an array

#define UNPACK_0(x)    x
#define CHOICE_(x)     x,

#define PARAMETER_NONE(name) 
#define PARAMETER_STR(name,variable,default)  variable = default;
#define PARAMETER_BOOL(name,variable,default) variable = default;
#define PARAMETER_NUM(name,variable,default)  variable = default;
#define PARAMETER_LIST(name,variable) 
#define PARAMETER_SECTION(variable)
#define PARAMETER_PAIR(name,variable) 
#define PUBLIC_PARM(x) 

#define VECTOR_BOOL(name,variable,default) \
 variable##_values.push_back("true"); \
 variable##_values.push_back("false");\
 variable=default;

#define VECTOR_NUM(name,variable,lowbound,hibound,default) \
 for (int i=lowbound;i<=hibound;i++) variable##_values.push_back(i);\
 variable=default;

#define VECTOR_MENU(name,variable,value_list) \
{ \
  char *tmp[]={ UNPACK_0##value_list 0 }; \
  for(int i=0;tmp[i];i++) variable.push_back(tmp[i]);\
}

#define VECTOR_STR(name,variable,value_list,default)  \
{ \
  char *tmp[]={ UNPACK_0##value_list 0 }; \
  for(int i=0;tmp[i];i++) variable##_values.push_back(tmp[i]);\
  variable=default;\
}


#elif !defined CONFIG_READER


/*****************************************
       Macros to fill parser boddy
 *****************************************/

#define CONFIG_READER

// MACROs for Configuration Parser

#define PUBLIC_PARM(x)

#define PARAMETER_NONE(name) \
 if (param == name) continue; \
 else

#define PARAMETER_STR(name,variable,default)  \
 if (param == name) \
  variable = value; \
 else

#define PARAMETER_BOOL(name,variable,default) \
 if (param == name) { \
   variable = ((value == "y") || \
               (value == "yes") || (value == "on") || \
               (value == "true") || (value == "1")); \
 } else

#define PARAMETER_NUM(name,variable,default) \
 if (param == name) \
   if (strcasecmp(value.c_str(),"none")==0) variable = NONE; \
   else if (strcasecmp(value.c_str(),"playlist")==0) variable = PLAYLIST; \
   else if (strcasecmp(value.c_str(),"both")==0) variable = BOTH; \
   else if (strcasecmp(value.c_str(),"keyboard")==0) variable = KEYBOARD; \
   else if (strcasecmp(value.c_str(),"lirc")==0) variable = LIRC; \
   else if (strcasecmp(value.c_str(),"evdev")==0) variable = EVDEV; \
   else if (strcasecmp(value.c_str(),"mplayer")==0) variable = MPLAYER; \
   else if (strcasecmp(value.c_str(),"xine")==0) variable = XINE; \
   else if (strcasecmp(value.c_str(),"dxr3player")==0) variable = DXR3PLAYER; \
   else if (strcasecmp(value.c_str(),"full_layout")==0) variable = FULL_LAYOUT; \
   else if (strcasecmp(value.c_str(),"mobile")==0) variable = MOBILE; \
   else variable = atoi(value.c_str());			  \
 else

#define PARAMETER_LIST(name,variable) \
 if (param == name) \
  while (!value.empty()) { \
    std::string::size_type pos1 = value.find(','); \
    std::string::size_type pos2 = value.find_last_not_of("\t ,",pos1); \
    variable.push_back(value.substr(0,++pos2)); \
    pos1 = value.find_first_not_of("\t ,",pos1); \
    value.replace(0,--pos1,""); \
  } else

#ifdef USE_SECTION
#define PARAMETER_SECTION(variable) \
  if (param == "[]") { \
    std::string::size_type pos1 = value.find_first_not_of("\t ["); \
    std::string::size_type pos2 = value.find_last_not_of("\t ]"); \
    variable.push_back(value.substr(pos1,++pos2)); \
  } else
#endif

#define PARAMETER_PAIR(name,variable) \
 if (param == name) { \
  std::string::size_type pos1 = value.find(','); \
  std::string::size_type pos2 = value.find_last_not_of("\t ,",pos1); \
  std::string first = value.substr(0, ++pos2); \
  pos2 = value.find_first_not_of("\t ,",pos2); \
  std::string::size_type pos3 = value.find_last_not_of("\t "); \
  std::string second = value.substr(pos2, ++pos3-pos2); \
  MyPair temp = MyPair(first, second); \
  variable.push_back(temp); \
} else

#define VECTOR_BOOL(name,variable,default)                 PARAMETER_BOOL(name,variable,default)
#define VECTOR_NUM(name,variable,lowbound,hibound,default) PARAMETER_NUM(name,variable,default)
#define VECTOR_STR(name,variable,value_list,default)       PARAMETER_STR(name,variable,default)
#define VECTOR_MENU(name,variable,value_list)


#elif !defined CONFIG_WRITER


/*****************************************
       Macros to fill writer boddy
 *****************************************/

#define CONFIG_WRITER

#define PARAMETER_NONE(name)
#define PUBLIC_PARM(x)

#define PARAMETER_STR(name,variable,default)  if (!(variable == default)) \
  Out << name << " = " << variable << std::endl;

#define PARAMETER_BOOL(name,variable,default) if (!(variable == default)) \
  Out << name << " = " << variable << std::endl;

#define PARAMETER_NUM(name,variable,default)  if (!(variable == default)) \
  Out << name << " = " << variable << std::endl;

#define PARAMETER_LIST(name,variable) \
  for (std::list<std::string>::const_iterator iter = variable.begin(); iter != variable.end(); iter++) \
    Out << name << " = " << (*iter) << std::endl;

#ifdef USE_SECTION
#define PARAMETER_SECTION(variable) \
  for (std::list<std::string>::const_iterator iter = variable.begin(); iter != variable.end(); iter++) \
    Out << '[' << (*iter) << ']' << std::endl;
#endif

#define PARAMETER_PAIR(name,variable) \
  for (std::list<MyPair>::const_iterator iter =  variable.begin(); iter != variable.end(); iter++) \
    Out  << name << " = " << iter->first << ',' << iter->second << std::endl;

#define VECTOR_BOOL(name,variable,default)                 PARAMETER_BOOL(name,variable,default)
#define VECTOR_NUM(name,variable,lowbound,hibound,default) PARAMETER_NUM(name,variable,default)
#define VECTOR_STR(name,variable,value_list,default)       PARAMETER_STR(name,variable,default)
#define VECTOR_MENU(name,variable,value_list)

#endif
