// ---------------------------------------------------------------------------
// - AsnNode.hpp                                                             -
// - afnix:itu module - asn base node class definition                       -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  is  distributed in  the hope  that it will be useful, but -
// - without  any  warranty;  without  even   the   implied    warranty   of -
// - merchantability or fitness for a particular purpose.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2013 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  AFNIX_ASNNODE_HPP
#define  AFNIX_ASNNODE_HPP

#ifndef  AFNIX_BUFFER_HPP
#include "Buffer.hpp"
#endif

#ifndef  AFNIX_OUTPUTSTREAM_HPP
#include "OutputStream.hpp"
#endif

namespace afnix {

  /// The AsnNode class is the base class used to represent the asn tree.
  /// The structure of the node is defined in ITU-T X.690 recommendation.
  /// This implementation supports 64 bits tag number with natural machine
  /// length encoding. The Canonical Encoding Rule (CER) and Distinguished
  /// Encoding Rule (DER) are defined by the class. Since ASN.1 provides
  /// several encoding schemes, the class is designed to be as generic as 
  /// possible but does not provides the mechanism for changing from one 
  /// representation to another although it is perfectly valid to read a 
  /// DER representation and write it in the CER form.
  /// @author amaury darsch

  class AsnNode : public virtual Object {
  public:
    /// the encoding rules
    enum t_encr {
      ASN_BER,  // basic encoding rule
      ASN_CER,  // canonical encoding rule
      ASN_DER   // distinguished encoding rule
    };

    /// the node class
    enum t_ncls {
      CLS_UNIV, // class 00 : universal class
      CLS_APPL, // class 01 : application class
      CLS_CTXS, // class 10 : context specific class
      CLS_PRIV  // class 11 : private class
    };

  protected:
    /// the node class
    t_ncls d_ncls;
    /// the constructed flag
    bool   d_cstf;
    /// the tag number
    t_octa d_tagn;
    /// the indefinite content length flag
    bool   d_iclf;

    /// create a null node
    AsnNode (void);

    /// create a node by primitive tag
    /// @param tagn the tag number
    AsnNode (const t_octa tagn);

    /// create a node by primitive tag and flag
    /// @param tagn the tag number
    /// @param cstf the constructed flag
    AsnNode (const t_octa tagn, const bool cstf);

    /// copy construct this asn node
    /// @param that the node to copy
    AsnNode (const AsnNode& that);

    /// assign a node to this one
    /// @param that the node to assign
    AsnNode& operator = (const AsnNode& that);

    /// write the node header into a buffer
    /// @param encr the encoding rule
    /// @param buf  the buffer to write
    virtual void whead (const t_encr encr, Buffer& buf) const;

    /// write a node header into an output stream
    /// @param encr the encoding rule
    /// @param os   the output stream to write
    virtual void whead (const t_encr encr, OutputStream& os) const;

    /// write the node footer into a buffer
    /// @param encr the encoding rule
    /// @param buf  the buffer to write
    virtual void wfoot (const t_encr encr, Buffer& buf) const;

    /// write a node footer into an output stream
    /// @param encr the encoding rule
    /// @param os   the output stream to write
    virtual void wfoot (const t_encr encr, OutputStream& os) const;

    /// write the node body into a buffer
    /// @param encr the encoding rule
    /// @param buf  the buffer to write
    virtual void wbody (const t_encr encr, Buffer& buf) const =0;

    /// write a node body into an output stream
    /// @param encr the encoding rule
    /// @param os   the output stream to write
    virtual void wbody (const t_encr encr, OutputStream& os) const =0;

  public:
    /// @return the class name
    String repr (void) const;

    /// reset this node
    virtual void reset (void);

    /// @return the node class
    virtual t_ncls getcls (void) const;

    /// @return true if the node is primitive
    virtual bool isprm (void) const;

    /// @return true if the node is constructed
    virtual bool iscst (void) const;

    /// @return true if the indefinite content length is set
    virtual bool isicl (void) const;

    /// @return the node tag number
    virtual t_octa gettagn (void) const;

    /// get the node content length
    virtual t_long getclen (void) const;

    /// get the node content length
    /// @param encr the encoding rule
    virtual t_long getclen (const t_encr encr) const =0;

    /// get the total node length
    virtual t_long length (void) const;
    
    /// get the total node length
    /// @param encr the encoding rule
    virtual t_long length (const t_encr encr) const;

    /// write a node into a buffer
    /// @param buf the buffer to write
    virtual void write (Buffer& buf) const;

    /// write a node into a buffer by encoding rule
    /// @param encr the encoding rule
    /// @param buf  the buffer to write
    virtual void write (const t_encr encr, Buffer& buf) const;

    /// write a node into an output stream
    /// @param os the output stream to write
    virtual void write (OutputStream& os) const;

    /// write a node into an output stream
    /// @param encr the encoding rule
    /// @param os   the output stream to write
    virtual void write (const t_encr encr, OutputStream& os) const;

  public:

    /// evaluate an object data member
    /// @param robj  the current runnable
    /// @param nset  the current nameset
    /// @param quark the quark to evaluate
    static Object* meval (Runnable* robj, Nameset* nset, const long quark);

    /// @return true if the given quark is defined
    bool isquark (const long quark, const bool hflg) const;
    
    /// apply this object with a set of arguments and a quark
    /// @param robj  the current runnable
    /// @param nset  the current nameset    
    /// @param quark the quark to apply these arguments
    /// @param argv  the arguments to apply
    Object* apply (Runnable* robj, Nameset* nset, const long quark,
		   Vector* argv);
  };
}

#endif
