/* Assoc.H: associative arrays */

#ifndef _XRML_ASSOC_H_
#define _XRML_ASSOC_H_

#include "Array.H"

namespace xrml {

template<class keyT, class valueT>
class assoc: public PooledObj {
public:
  keyT default_key;
  valueT default_value;
  int size;

protected:
  struct key_value_pair {
    keyT k;
    valueT v;
    key_value_pair() 			{ }
    key_value_pair(const keyT& kk, const valueT& vv) 	{ k = kk; v = vv; }

    friend ostream& operator<<(ostream& s, const key_value_pair& a) { return s << a.k << " \t----> " << a.v; }
  };
  array<key_value_pair> table;

  void init(int len)
  {
    table.init(len, 0); size=table.size;
  }

public:
  assoc()        { init(0); }
  assoc(int len) { init(len); }

  // adds the key if not found (with default value) and returns a reference to the 
  // value. Finds the most recently added item with this key if the key occurs 
  // more than once.
  valueT& operator[](const keyT& kk)
  {
    // search back to front: find most recently added items first
    for (int i=table.size-1; i>=0; i--)
      if (table[i].k == kk)
	return table[i].v;		// found
    
    table.append(key_value_pair(kk, default_value));	// not found
    size = table.size;
    return table[table.size-1].v;
  }

  valueT& operator[](int i) const
  {
    return table[i].v;
  }

  keyT& key(int i) const
  {
    return table[i].k;
  }

  valueT& value(int i) const
  {
    return table[i].v;    
  }

  // returns the index of the value if found and -1 if not. Does not
  // add the key to the table. Returns last occurence if key appears
  // more than once.
  int operator() (const keyT& kk) const
  {
    for (int i=table.size-1; i>=0; i--)
      if (table[i].k == kk)
	return i;		// found
    return -1;			// not found
  }

  // adds the key-value pair and returns the index in the table
  int add(const keyT& kk, const valueT& vv)
  {
    table.append(key_value_pair(kk, vv));
    size = table.size;
    return table.size-1;
  }

  // counts how many times the specified key occurs in the table
  int count(const keyT& kk)
  {
    int count=0;
    for (int i=0; i<table.size; i++)
      if (table[i].k == kk)
	count++;
    return count;
  }

  void concat(const assoc& extra)
  {
    table.concat(extra.table);
    size = table.size;
  }
};

} // namespace xrml

#endif /*_XRML_ASSOC_H_*/
