/* -*- c++ -*- */
#ifndef AKAXISO_NAMESPACES_H__
#define AKAXISO_NAMESPACES_H__

#include <akaxiso/classes/types.h>
#include <akaxiso/classes/mutex.h>
#include <map>
#include <vector>

namespace aka2 {

  void xmlns(const std::string &prefix, const std::string &uri);
  const std::string &get_namespace_uri(const std::string &prefix);
  const std::string &get_namespace_uri(const id_type ns_id);
  const std::string &get_prefix(const std::string &uri);
  const std::string &get_prefix(const id_type &ns_id);
  const id_type get_uri_id(const std::string &uri);
  const id_type get_prefix_id(const std::string &prefix);



  class namespace_map {
    typedef std::map<id_type, std::string> urimap_type;
    typedef std::map<std::string, id_type> idmap_type;

  public:
    namespace_map(id_type initial_id = 1) : current_id_(initial_id) {}
    const id_type register_namespace_uri(const std::string &uri);
    const std::string &get_namespace_uri(const id_type id) const;
    const id_type get_namespace_id(const std::string &uri) const;

    // Used for system globals.
    void initialize();

    void clear();

  private:
    id_type current_id_;
    urimap_type urimap_;
    idmap_type idmap_;
  };


  class any_namespace_map : public namespace_map {
  public:
    any_namespace_map() : namespace_map(0x8000) {}
    const std::string &get_namespace_uri(const id_type id) const;
    const id_type get_namespace_id(const std::string &uri);

    void clear();
  private:
    mutable mutex mutex_;
  };


  class any_prefix_cache {
  public:
    any_prefix_cache(const std::string &prefix = "tmpns") : prefix_(prefix) { } //!!!!!!!!!!
    const std::string &get_prefix(id_type nsid) const;
    const id_type get_namespace_id(const std::string &prefix) const;
  private:
    std::string prefix_;
    mutable std::vector<std::string> cache_;
  };

  class prefix_map {
    typedef std::vector<std::string> prefixes;
    typedef std::vector<id_type> id_stack;

    // URI -> prefix mapping.
    typedef std::map<id_type, prefixes> prefixmap_type;
    // Preix is unique, but some prefixes may be associated with the same id.
    typedef std::map<std::string, id_stack> idmap_type;
  public:
    typedef prefixmap_type::const_iterator const_iterator;

    prefix_map();
    const_iterator begin() const { return prefixmap_.begin(); }
    const_iterator end() const { return prefixmap_.end(); }

    void assign_prefix(const std::string &prefix, const std::string &url);
    void clear_prefix(const std::string &prefix);
    const id_type get_prefix_id(const std::string &prefix) const;
    const std::string &get_prefix(const id_type id) const;

    static void initialize();
    void clear();

  private:
    static bool is_prefix_xml(const std::string &prefix);
    static std::string xml_prefix_;
    prefixmap_type prefixmap_;
    any_prefix_cache any_cache_;
    idmap_type idmap_;
  };

} // namespace aka2

#endif /* AKAXISO_NAMESPACES_H__ */
