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

/** @file akaxiso/classes/occurrence.h */

#include <akaxiso/classes/shared_ptr.h>
#include <akaxiso/classes/qname.h>
#include <akaxiso/iosfwd.h>
#include <assert.h>

namespace aka2 {

  extern const int unbounded;

  struct occurrence {
    occurrence(int minOccurs = 1, int maxOccurs = 1)
      : minOccurs_(minOccurs), maxOccurs_(maxOccurs) {}
    int minOccurs_;
    int maxOccurs_;
    bool in_range(int count) const;
    bool is_array() const;
  };

  struct default_op {
    virtual void set_default(const std::string &defval) = 0;
    virtual bool has_default() const = 0;
    virtual const void *value() const = 0;
 };

  class element_props {
  public:
    element_props() : op_(0) {}
    element_props(const element_op &op) : op_(&op) {}
    void set_occurrence(int minOccurs, int maxOccurs) { occ_ = occurrence(minOccurs, maxOccurs); }
    void set_occurrence(const occurrence &occ) { occ_ = occ; }
    const occurrence &get_occurrence() const { return occ_; }
    //const default_op& get_default() const { return *default_; }
    void set_name(const qname &name){ name_ = name; }
    const qname &get_name() const  { return name_; }

    /**
     * methods when @fixed is specified.
     */
    bool is_fixed_string(const std::string &val, const preconditions &pcd) const;
    void write_fixed_string(std::ostream &ostm, const preconditions &pcd) const;
    void set_default_op(default_op *defop) {
      assert(defop != 0);
      default_ = shared_ptr<default_op>(defop);
    }

    void setup_default_value(const std::string &defval) { 
      default_->set_default(defval); 
    }

    schematype_id get_schematype() const {
      return op_->get_schematype();
    }

    const element_op& op() const { return *op_; }

    bool is_default_specified() const {
      if (default_.get() == 0)
	return false;
      return default_->has_default();
    }

    bool is_element() const { return name_.local()[0] != '&'; }

  protected:
    occurrence occ_;
    shared_ptr<default_op> default_;
    qname name_;
    const element_op *op_;

    /** Initialize member value to
     *    Given default value        : when @default is specified,
     *    Default construction value : when @default is not specified.
     *    Nothing to do              : when value is nill.
     */
    void set_default(void *e) const;
    bool is_default(const void *e) const;
  };

} // namespace aka2

#endif /* AKAXISO_OCCURRENCE_H__ */
