//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / UNI
//
//File: unipdu.h
//
//Version: $Revision: 1.6 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/01/22 15:47:15 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jari Katajavuori
//
//Description:
//      Contains PDUs and needed functionality to handle them.
//      PDUs are variable length and consist of elements called
//      Information Elements (IE) which are either optional or
//      mandatory.
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#ifndef __UNI_UNIPDU_H__
#define __UNI_UNIPDU_H__

#include <typeinfo>
#include <string>
#include <set>
#include <autoptr.h>

#include "pf/types.h"
#include "pf/messenge.h"
#include "pf/bytes.h"
#include "pf/bithandler.h"

#include "unidefs.h"
#include "unierrorinfo.h"

class pfFrame;

class uniCoOrdProtocol;
class uniProtocol;

// Limits for pdu/ie size
const pfUlong uniPduMinimumSize = 9;
const pfUlong uniIEMinimumSize = 4;
const pfUlong uniIEMaximumSize = 100;

// Standard position for message type identifier within pdu.
const pfUlong uniMessageTypePosition = 5;

// Call Reference Flag bit position and mask
const pfUlong uniCallReferenceFlagBitPosition = 23;
const pfUlong uniCallReferenceFlagBitMask = 0x800000;

// Protocol Discriminator for UNI pdus
const pfByte uniProtocolDiscriminator = B0000_1001;

// Constant for IE Coding Standard & Instruction Field
// (= ITU-T standardized & IE inst. field not significant)
const pfByte standardInstructionField = B1000_0000;
const pfByte specificInstructionField = B1110_0000;

//
// Class: uniPdu
//
// Description:
//      See file description. pfBitHandler is inherited for
//      simpler frame hanling with non-byte-oriented fields
//

class uniPdu : public pfMessenger, public pfBitHandler
{
    public:
        // Public enums

        enum BearerClass 
        {
            Unspecified      = B0000_0000,
            BCOB_A           = B0000_0001,
            BCOB_C           = B0000_0011,
            BCOB_X           = B0001_0000
        };

        enum TDCombinations
        {
            TD_Unspecified   = B0000_0000,
            TD_PCR_CLP0      = B0000_0011,
            TD_PCR_CLP1      = B0000_0010,
            TD_SCR_CLP0      = B0001_0110,
            TD_SCR_CLP1      = B0010_1010,
            TD_BE            = B0100_0010
        };

        enum TDCombinationMasks
        {
            TD_PCR_CLP0_MASK = B0000_0001,
            TD_PCR_CLP1_MASK = B0000_0010,
            TD_SCR_CLP0_MASK = B0000_0100,
            TD_SCR_CLP1_MASK = B0000_1000,
            TD_MBS_CLP0_MASK = B0001_0000,
            TD_MBS_CLP1_MASK = B0010_0000,
            TD_BE_MASK       = B0100_0000,
            TD_TAG_MASK      = B1000_0000
        };

        enum Bitrates
        {
            NIBR             = B0000_0000,
            CBR              = B0000_0001,
            VBR              = B0000_0010
        };

        // Typedefs
        typedef auto_ptr<uniErrorInfo> errorInfoType;

        // Destructor
        virtual ~uniPdu(void);

        // Cloning method
        virtual pfMessenger *clone(void);
        
        // Creates a new pdu by decoding a given frame
        // If an error occurs, throws an exception -> discard.
        static uniPdu *create(pfFrame &frame_,
                              uniCoOrdProtocol *protocol_ = 0);
        
        // Sets call reference and a mux reference fields
        // getting the needed information from a protocol conduit.
        void setCallReference(uniProtocol *protocol_);
        void setMuxReference(void);

        // Returns true if multipoint message
        bool isMultipointMessage(void);

        // Sets endpoint reference field
        void setEndpointReference(pfUlong endpointReference_);
        
        // Sets/gets UNI frame from storage. getFrame method
        // uses a method described in tvBithandler.
        void setUNIFrame(pfFrame &frame_);
        pfFrame getUNIFrame(void);

        // Shortcut for tvBitHandler
        void decreaseIfInExtension(pfLong &variable_, pfLong amount_ = 1);
        
        // Pdu spesific part of FSMs.
        virtual void globalCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);
        virtual void noProtocolCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);
        virtual void protocolRelatedCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);

        // Pdu spesific part of FSMs containing functionality
        // of error handling.
        virtual void uniMandatoryIEMissingAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        virtual void uniMandatoryIEContentErrorAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);

        // Error checking
        uniErrorInfo *getErrorInfo(void);
        
        // Message decoding & encoding
        virtual void decode(void);
        virtual pfFrame encode(void);

        // Methods for defining pdu fields in storage

        pfStorage &defineAALParameters(void);
        pfStorage &defineATMTrafficDescriptor(void);
        pfStorage &defineBroadbandBearerCapability(void);
        pfStorage &defineBroadbandHighLayerInfo(void);
        pfStorage &defineBroadbandLowLayerInfo(char num_);
        pfStorage &defineBroadbandLockingShift(void);
        pfStorage &defineBroadbandNonlockingShift(void);
        pfStorage &defineBroadbandSendingComplete(void);
        pfStorage &defineCalledPartyNumber(void);
        pfStorage &defineCalledPartySubaddress(void);
        pfStorage &defineCallingPartyNumber(void);
        pfStorage &defineCallingPartySubaddress(void);
        pfStorage &defineCallState(void);
        pfStorage &defineCause(void);
        pfStorage &defineConnectionIdentifier(void);
        pfStorage &defineEndpointReference(void);
        pfStorage &defineEndpointState(void);
        pfStorage &defineQoSParameters(void);
        pfStorage &defineRestartIndicator(void);
        pfStorage &defineTransitNetworkSelection(void);
        
    protected:
        // Message types

        enum MsgType
        {
            uniMsgAlerting               = B0000_0001,
            uniMsgCallProceeding         = B0000_0010,
            uniMsgSetup                  = B0000_0101,
            uniMsgConnect                = B0000_0111,
            uniMsgConnectAck             = B0000_1111,
            uniMsgRelease                = B0100_1101,
            uniMsgReleaseComplete        = B0101_1010,
            uniMsgRestart                = B0100_0110,
            uniMsgRestartAck             = B0100_1110,
            uniMsgNotify                 = B0110_1110,
            uniMsgStatus                 = B0111_1101,
            uniMsgStatusEnquiry          = B0111_0101,
            uniMsgAddParty               = B1000_0000,
            uniMsgAddPartyAck            = B1000_0001,
            uniMsgAddPartyReject         = B1000_0010,
            uniMsgDropParty              = B1000_0011,
            uniMsgDropPartyAck           = B1000_0100
        };
        
        // Variable length information element identifiers        
        enum IEType
        {
            uniIEUndefined               = B0000_0000,
            uniIECause                   = B0000_1000,
            uniIECallState               = B0001_0100,
            uniIEEndpointReference       = B0101_0100,
            uniIEEndpointState           = B0101_0101,
            uniIEAALParameters           = B0101_1000,
            uniIEATMTrafficDescriptor    = B0101_1001,
            uniIEConnectionIdentifier    = B0101_1010,
            uniIEQoSParameters           = B0101_1100,
            uniIEBHighLayerInfo          = B0101_1101,
            uniIEBBearerCapability       = B0101_1110,
            uniIEBLowLayerInfo           = B0101_1111,
            uniIEBLockingShift           = B0110_0000,
            uniIEBNonlockingShift        = B0110_0001,
            uniIEBSendingComplete        = B0110_0010,
            uniIEBRepeatIndicator        = B0110_0011,
            uniIECallingPartyNumber      = B0110_1100,
            uniIECallingPartySubaddress  = B0110_1101,
            uniIECalledPartyNumber       = B0111_0000,
            uniIECalledPartySubaddress   = B0111_0001,
            uniIETransitNetworkSelection = B0111_1000,
            uniIERestartIndicator        = B0111_1001
        };

        // Typedefs for a sets of IE:s inside a particular pdu.
        typedef set<IEType, less<IEType> > IETypeSet; 
        typedef IETypeSet::iterator IETypeIter;
        typedef pair<IETypeIter, bool> IEInsResult; 
        
        // These sets contain information wether an IE is
        // either optional or mandatory
        IETypeSet _mandatory;
        IETypeSet _optional;

        errorInfoType _errorInfo;

        // Constructors
        uniPdu(void);
        uniPdu(const uniPdu &other_);
        
    private:

        // Encoding methods
        IETypeSet encodeIEs(void);
        void encodeIE(IEType type_);

        void encodeCommonFields(void);

        void encodeAALParameters(void);
        void encodeATMTrafficDescriptor(void);
        void encodeBroadbandBearerCapability(void);
        void encodeBroadbandHighLayerInfo(void);
        void encodeBroadbandLowLayerInfo(void);
        void encodeOneBLLI(string ieName_);
        void encodeBroadbandRepeatIndicator(void);
        void encodeBroadbandSendingComplete(void);
        void encodeCalledPartyNumber(void);
        void encodeCalledPartySubaddress(void);
        void encodeCallingPartyNumber(void);
        void encodeCallingPartySubaddress(void);
        void encodeCallState(void);
        void encodeCause(void);
        void encodeConnectionIdentifier(void);
        void encodeEndpointReference(void);
        void encodeEndpointState(void);
        void encodeQoSParameters(void);
        void encodeRestartIndicator(void);
        void encodeTransitNetworkSelection(void);
        
        // These methods are called from above (two or more) encoding
        // methods.
        void encodeOneCause(pfStorage &storage_);

        // Decoding methods
        void decodeIEs(void);
        IEType decodeIE(void);
        
        void decodeCommonFields(void);
        
        void decodeCallState(void);
        void decodeCause(void);
        void decodeEndpointReference(void);
        void decodeEndpointState(void);
        void decodeAALParameters(void);
        void decodeATMTrafficDescriptor(void);
        void decodeConnectionIdentifier(void);
        void decodeQoSParameters(void);
        void decodeBroadbandHighLayerInfo(void);
        void decodeBroadbandBearerCapability(void);
        void decodeBroadbandLowLayerInfo(void);
        void decodeBroadbandLockingShift(void);
        void decodeBroadbandNonlockingShift(void);
        void decodeBroadbandSendingComplete(void);
        void decodeBroadbandRepeatIndicator(void);
        void decodeCallingPartyNumber(void);
        void decodeCallingPartySubaddress(void);
        void decodeCalledPartyNumber(void);
        void decodeCalledPartySubaddress(void);
        void decodeTransitNetworkSelection(void);
        void decodeRestartIndicator(void);
        void decodeUnimplemented(void);
        void skipIE(void);

        // Decoding/Encoding tools
        string toolDecodeNSAP(pfLong &ieLength);
        string toolDecodeISDN(pfLong &ieLength);
        pfUlong toolEncodeNSAP(string &digits);
        pfUlong toolEncodeISDN(string &digits);
        
        // IE lenght checking and length error detection
        void checkIEAbsLength(const pfUlong length_);
        pfUlong checkIELength(const pfUlong rangeMin_,
                              const pfUlong rangeMax_ = uniIEMaximumSize);

        // Shortcut for adding message length variable
        void addMessageLength(pfUlong amount_);

        // Checks if an IE is mandatory or not
        bool isMandatoryIE(IEType type_) const;

        // Defines an integer variable and gives it a value
        void defineAndSetInteger(string variable_, pfUlong int_);
};

class uniSETUPpdu : public uniPdu
{
    public:
        uniSETUPpdu(const uniSETUPpdu &other_);
        virtual ~uniSETUPpdu(void);
        virtual pfMessenger *clone(void);
        static uniSETUPpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
        virtual void noProtocolCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);
        virtual void protocolRelatedCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);

        virtual void uniMandatoryIEMissingAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        virtual void uniMandatoryIEContentErrorAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        
    protected:
        uniSETUPpdu(void);
};

class uniCALL_PROCEEDINGpdu : public uniPdu
{
    public:
        uniCALL_PROCEEDINGpdu(const uniCALL_PROCEEDINGpdu &other_);
        virtual ~uniCALL_PROCEEDINGpdu(void);
        virtual pfMessenger *clone(void);
        static uniCALL_PROCEEDINGpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
    protected:
        uniCALL_PROCEEDINGpdu(void);
};

class uniALERTINGpdu : public uniPdu
{
    public:
        uniALERTINGpdu(const uniALERTINGpdu &other_);
        virtual ~uniALERTINGpdu(void);
        virtual pfMessenger *clone(void);
        static uniALERTINGpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniALERTINGpdu(void);
};

class uniCONNECTpdu : public uniPdu
{
    public:
        uniCONNECTpdu(const uniCONNECTpdu &other_);
        virtual ~uniCONNECTpdu(void);
        virtual pfMessenger *clone(void);
        static uniCONNECTpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniCONNECTpdu(void);
};

class uniCONNECT_ACKpdu : public uniPdu
{
    public:
        uniCONNECT_ACKpdu(const uniCONNECT_ACKpdu &other_);
        virtual ~uniCONNECT_ACKpdu(void);
        virtual pfMessenger *clone(void);
        static uniCONNECT_ACKpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
    protected:
        uniCONNECT_ACKpdu(void);
};

class uniRELEASEpdu : public uniPdu
{
    public:
        uniRELEASEpdu(const uniRELEASEpdu &other_);
        virtual ~uniRELEASEpdu(void);
        virtual pfMessenger *clone(void);
        static uniRELEASEpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

        virtual void uniMandatoryIEMissingAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        virtual void uniMandatoryIEContentErrorAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        
    protected:
        uniRELEASEpdu(void);
};

class uniRELEASE_COMPLETEpdu : public uniPdu
{
    public:
        uniRELEASE_COMPLETEpdu(const uniRELEASE_COMPLETEpdu &other_);
        virtual ~uniRELEASE_COMPLETEpdu(void);
        virtual pfMessenger *clone(void);
        static uniRELEASE_COMPLETEpdu *create(void);
        static uniRELEASE_COMPLETEpdu *buildReply(
            pfMessenger *original_, uniErrorInfo &errorInfo_);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
        virtual void noProtocolCallReferenceProcedures(
            uniCoOrdProtocol *);

        virtual void uniMandatoryIEMissingAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
        virtual void uniMandatoryIEContentErrorAct(
            uniCoOrdProtocol *protocol_,
            uniErrorInfo &errorInfo_);
         
    protected:
        uniRELEASE_COMPLETEpdu(void);
};

class uniNOTIFYpdu : public uniPdu
{
    public:
        uniNOTIFYpdu(const uniNOTIFYpdu &other_);
        virtual ~uniNOTIFYpdu(void);
        virtual pfMessenger *clone(void);
        static uniNOTIFYpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniNOTIFYpdu(void);
};
        
class uniSTATUSpdu : public uniPdu
{
    public:
        uniSTATUSpdu(const uniSTATUSpdu &other_);
        virtual ~uniSTATUSpdu(void);
        virtual pfMessenger *clone(void);
        static uniSTATUSpdu *create(void);
        static uniSTATUSpdu *buildReply(
            pfMessenger *original_,
            uniErrorInfo &errorInfo_,
            pfUlong state_ = uniState_Null);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
        virtual void globalCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);
        virtual void noProtocolCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);
        
    protected:
        uniSTATUSpdu(void);
};

class uniSTATUS_ENQUIRYpdu : public uniPdu
{
    public:
        uniSTATUS_ENQUIRYpdu(const uniSTATUS_ENQUIRYpdu &other_);
        virtual ~uniSTATUS_ENQUIRYpdu(void);
        virtual pfMessenger *clone(void);
        static uniSTATUS_ENQUIRYpdu *create(void);

        virtual void noProtocolCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
    protected:
        uniSTATUS_ENQUIRYpdu(void);
};

class uniRESTARTpdu : public uniPdu
{
    public:
        uniRESTARTpdu(const uniRESTARTpdu &other_);
        virtual ~uniRESTARTpdu(void);
        virtual pfMessenger *clone(void);
        static uniRESTARTpdu *create(void);

        virtual void globalCallReferenceProcedures(
            uniCoOrdProtocol *protocol_);

        virtual void apply(pfState *state_, pfProtocol *protocol_);
        
    protected:
        uniRESTARTpdu(void);
};

class uniRESTART_ACKpdu : public uniPdu
{
    public:
        uniRESTART_ACKpdu(const uniRESTART_ACKpdu &other_);
        virtual ~uniRESTART_ACKpdu(void);
        virtual pfMessenger *clone(void);
        static uniRESTART_ACKpdu *create(void);

        virtual void globalCallReferenceProcedures(
            uniCoOrdProtocol *protocol_); 

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniRESTART_ACKpdu(void);
};

class uniADD_PARTYpdu : public uniPdu
{
    public:
        uniADD_PARTYpdu(const uniADD_PARTYpdu &other_);
        virtual ~uniADD_PARTYpdu(void);
        virtual pfMessenger *clone(void);
        static uniADD_PARTYpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniADD_PARTYpdu(void);
};

class uniADD_PARTY_ACKpdu : public uniPdu
{
    public:
        uniADD_PARTY_ACKpdu(const uniADD_PARTY_ACKpdu &other_);
        virtual ~uniADD_PARTY_ACKpdu(void);
        virtual pfMessenger *clone(void);
        static uniADD_PARTY_ACKpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniADD_PARTY_ACKpdu(void);
};

class uniADD_PARTY_REJECTpdu : public uniPdu
{
    public:
        uniADD_PARTY_REJECTpdu(const uniADD_PARTY_REJECTpdu &other_);
        virtual ~uniADD_PARTY_REJECTpdu(void);
        virtual pfMessenger *clone(void);
        static uniADD_PARTY_REJECTpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniADD_PARTY_REJECTpdu(void);
};

class uniDROP_PARTYpdu : public uniPdu
{
    public:
        uniDROP_PARTYpdu(const uniDROP_PARTYpdu &other_);
        virtual ~uniDROP_PARTYpdu(void);
        virtual pfMessenger *clone(void);
        static uniDROP_PARTYpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniDROP_PARTYpdu(void);
};

class uniDROP_PARTY_ACKpdu : public uniPdu
{
    public:
        uniDROP_PARTY_ACKpdu(const uniDROP_PARTY_ACKpdu &other_);
        virtual ~uniDROP_PARTY_ACKpdu(void);
        virtual pfMessenger *clone(void);
        static uniDROP_PARTY_ACKpdu *create(void);

        virtual void apply(pfState *state_, pfProtocol *protocol_);

    protected:
        uniDROP_PARTY_ACKpdu(void);
};

//----------------------------------------------------------------

class uniRSNMessageInputs
{
    public:
        virtual void uniRESTART_ACKpduAct(
            uniRESTART_ACKpdu *message_,
            pfProtocol *protocol_) = 0;
};

class uniRRNMessageInputs
{
    public:
        virtual void uniRESTARTpduAct(
            uniRESTARTpdu *message_,
            pfProtocol *protocol_) = 0;
};

class uniStatusMessageInputs
{
    public:
        virtual void uniSTATUSpduAct(
            uniSTATUSpdu *message_,
            pfProtocol *protocol_) = 0;
};

class uniMessageInputs : public uniStatusMessageInputs
{
    public:
        virtual void uniSETUPpduAct(
            uniSETUPpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniCALL_PROCEEDINGpduAct(
            uniCALL_PROCEEDINGpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniALERTINGpduAct(
            uniALERTINGpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniCONNECTpduAct(
            uniCONNECTpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniCONNECT_ACKpduAct(
            uniCONNECT_ACKpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniRELEASEpduAct(
            uniRELEASEpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniRELEASE_COMPLETEpduAct(
            uniRELEASE_COMPLETEpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniNOTIFYpduAct(
            uniNOTIFYpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniSTATUS_ENQUIRYpduAct(
            uniSTATUS_ENQUIRYpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniADD_PARTYpduAct(
            uniADD_PARTYpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniADD_PARTY_ACKpduAct(
            uniADD_PARTY_ACKpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniADD_PARTY_REJECTpduAct(
            uniADD_PARTY_REJECTpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniDROP_PARTYpduAct(
            uniDROP_PARTYpdu *message_,
            pfProtocol *protocol_) = 0;
        virtual void uniDROP_PARTY_ACKpduAct(
            uniDROP_PARTY_ACKpdu *message_,
            pfProtocol *protocol_) = 0;
};

#endif // __UNI_UNIPDU_H__



