#ifndef __CONFIGURABLE_H
#define __CONFIGURABLE_H

#include <iostream>
#include <list>
#include <utility>
#include <string>
#include "stl_adds.h"


#ifdef AVR
// for some reason gcc-avr has problems with pure functions.
// Therefore we use the hack to define an empty function instead of a pure one.
// However we get a lot of warnings since we return nothing 
#define ABSTRACT {}
#else
#define ABSTRACT =0
#endif

/**
   Abstact class for configurable objects. Sort of Hashmap interface. Parameters are double values

The Configurator is a (planned) external tool that can be used for changing the values of configurable objects.

* Protocoll for Configurator:
\code
To Configurator (BNF notation):
Conf         := <Comp>*
Comp         := <CompName> <Pair>*
CompName     := [<string>][<int>]<newline>
Pair         := <alphanum>=<double><newline>
\endcode
the remaining tags are self explanatory

Example
\code
[Component name which can contain spaces and digits and .,- ][ID1]
key1 = value1
key2 = value2
.
.
[Other Component name which can contain spaces and digits and .,- ][ID2]
key3 = value3
\endcode

Answer: (from Communicator to Simulation environment)\n
1. On change of a parameter:
\code
[ID] key=newvalue
\endcode
or
\code
key=newvalue
\endcode
the latter one means that the parameter is changed in all components

2. Request of the description as defined above.
\code
#Something I don\'t care
\endcode
*/

class Configurable {
public:
  
  typedef std::string paramkey;
  typedef double paramval;
  typedef std::list< std::pair<paramkey, paramval> > paramlist;

  /// nice predicate function for finding by ID
  struct matchId : public std::unary_function<Configurable*, bool> {
    matchId(int id) : id(id) {}
    int id;
    bool operator()(Configurable* c) { return c->id == id; }
  };

  Configurable(){ id = rand();}
  /// intialise with name and revision (use "$ID$")
  Configurable(const std::string& name, const std::string& revision)
    : name(name), revision(revision) {
      id = rand();
    }
  virtual ~Configurable(){}

  /// return the id of the configurable objects, which is created by random on initialisation
  int getId() const { return id;}


  /// return the name of the object
  virtual paramkey getName() const {
    return name;
  } 

  /// returns the revision of the object
  virtual paramkey getRevision() const {
    return revision;
  }

  /// stes the name of the object
  virtual void setName(const paramkey& name){
    this->name = name;
  } 
  /// sets the revision Hint: {  return "$ID$"; }
  virtual void getRevision(const paramkey& revision) {
    this->revision = revision; 
  }

  /** returns the value of the requested parameter 
      or 0 (+ error message to stderr) if unknown.
  */
  virtual paramval getParam(const paramkey& key) const{
    std::cerr << __FUNCTION__ << ": parameter " << key << " unknown\n";
    return 0;
  }

  /** sets the value of the given parameter 
      or does nothing if unknown.
  */
  virtual bool setParam(const paramkey& key, paramval val){
    return false; // fprintf(stderr, "%s:parameter %s unknown\n", __FUNCTION__, key);
  }
  /** The list of all parameters with there value as allocated lists.
      @return list of key-value pairs 
  */
  virtual paramlist getParamList() const {
    return paramlist();
  }

  /** This is a utility function for inserting the filename and the revision number
      at the beginning of the given string buffer str and terminates it.
      @param str buffer (call by reference) 
        that should have space for file+revision+2 characters
      @param file filename given by CVS i.e. $RCSfile: configurable.h,v $
      @param revision revision number given by CVS i.e. $Revision: 1.12 $
  */
  static void insertCVSInfo(paramkey& str, const char* file, const char* revision);

#ifndef AVR
  /** stores the key values paires into the file : filenamestem.cfg */
  bool storeCfg(const char* filenamestem);
  /** restores the key values paires from the file : filenamestem.cfg */
  bool restoreCfg(const char* filenamestem);
  void print(FILE* f, const char* prefix) const;
  void parse(FILE* f);
#endif  
private: 
  int id;
  paramkey name;
  paramkey revision;
};


#endif
