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

#include <akaxiso/classes/types.h>
#include <string>

namespace aka2 {

  class prefix_map;

  class qname {
  public:
    friend struct qname_less;
    qname() : uri_id_(empty_token) {}
    qname(const std::string &rawname) { set(rawname); }
    qname(id_type uri_id, const std::string &localname) {
      set(uri_id, localname);
    }
    void set(const std::string &uri, const std::string &name);
    void set(const id_type uri_id, const std::string &name);
    void set(const std::string &rawname);
    void set(const std::string &rawname,
	     const prefix_map &pfs);
    
    bool is_qualified() const { return uri_id_ != empty_token; }
    
    /** using user-defined namespace maps. */
    std::string qualified(const prefix_map &pfmap) const;
    std::string qualified() const;
    const std::string &prefix(const prefix_map &pfs) const;
    const std::string &prefix() const;
    
    const id_type get_uri_id() const { return uri_id_; }

    std::string &local();
    const std::string &local() const;

    bool operator ==(const qname &rhs) const {
      return (uri_id_ == rhs.uri_id_) && (name_ == rhs.name_);
    }
    bool operator !=(const qname &rhs) const {
      return (uri_id_ != rhs.uri_id_) || (name_ != rhs.name_);
    }

    bool empty() const;

  private:
    void validate_name() const;

    id_type uri_id_;
    std::string name_;
    mutable const char *prefix_cache_;
  };

  struct qname_less {
    bool operator ()(const qname &lhs, const qname &rhs) const {
      if (lhs.uri_id_ < rhs.uri_id_)
        return true;
      else if (lhs.uri_id_ == rhs.uri_id_)
        return (lhs.name_ < rhs.name_);
      return false;
    }
  };

  inline std::ostream & operator <<(std::ostream &ostm, const aka2::qname &name) {
    ostm << name.qualified();
    return ostm;
  }

  inline bool operator <(const aka2::qname &lhs, const aka2::qname &rhs) {
    return aka2::qname_less()(lhs, rhs);
  }

} // namespace aka2

#endif /* AKAXISO_QNAME_H__ */
