//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / UNI
//
//File: uniprotocol.h
//
//Version: $Revision: 1.24 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/14 06:56:32 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jari Katajavuori
//
//Description:
//      Uni protocol conduit implementation. This conduit is connection-
//      oriented so instances are created dynamically above a mux. It
//      implements the main functionality of the signaling protocol.
//
//Copyright:
//
//
//Licence:
//
//
//History: 

#ifndef __UNI_UNIPROTOCOL_H__
#define __UNI_UNIPROTOCOL_H__

#include "pf/protocol.h"
#include "pf/storage.h"
#include "unidefs.h"
#include "uniset.h"

class uniMode;
class uniPdu;
class uniSETUPpdu;
class uniCONNECTpdu;
class uniCALL_PROCEEDINGpdu;
class uniALERTINGpdu;
class uniCONNECT_ACKpdu;
class uniRELEASE_COMPLETEpdu;
class uniRELEASEpdu;
class uniADD_PARTYpdu;
class uniADD_PARTY_ACKpdu;
class uniADD_PARTY_REJECTpdu;
class uniDROP_PARTYpdu;
class uniDROP_PARTY_ACKpdu;
class uniSTATUSpdu;
class uniSTATUS_ENQUIRYpdu;
class sigSETUPreq;
class sigSETUPresp;
class sigPROCEEDINGreq;
class sigALERTINGreq;
class sigRELEASEreq;
class sigRELEASEresp;
class uniADD_PARTYreq;
class uniADD_PARTYresp;
class uniADD_PARTYerror;
class uniDROP_PARTYreq;
class uniDROP_PARTYresp;
class uniSTATUSreq;
class uniSTATUSresp;
class uniErrorInfo;

class ccProtocol;
//class uniTestCCProtocol;

// Constants

const pfUlong uniMaxEndpointReference = 0xffff;

//
// Class: uniProtocol
//
// Description:
//      Implements uni protocol conduit.
// 

class uniProtocol : public pfProtocol, public pfStorage
{
    public:
        static uniProtocol *create(uniMode *mode_);

        uniProtocol(const uniProtocol &other_);
        virtual ~uniProtocol(void);
        pfProtocol *cloneImplementation(void) const;

        // Enabling point-to-point or point-to-multipoint capabilities.
        pfConduit createPointToPointConduits(void);
        pfConduit createMultipointConduits(void);
        
        pfConduit getSideB(void);
        ccProtocol *getCC(void);

        // PMP management
        void addPMP(pfMessenger *message_);
        void removePMP(pfMessenger *message_);
        bool isExistingPMP(pfUlong endpointReference_);
        bool isPMPSetEmpty(void);

        void saveSetupData(uniSETUPpdu *message_);
        void putSavedSetupDataInto(uniADD_PARTYreq *message_);
        
        // To CC
        void sendSETUPindToCC(uniSETUPpdu *pdu_);
        void sendSETUPconfToCC(uniCONNECTpdu *pdu_);
        void sendSETUP_COMPLETEindToCC(uniCONNECT_ACKpdu *pdu_);
        void sendPROCEEDINGindToCC(uniCALL_PROCEEDINGpdu *pdu_);
        void sendALERTINGindToCC(uniALERTINGpdu *pdu_);
        
        void sendRELEASEconfToCC(pfUlong cause_);
        void sendRELEASEconfToCC(uniRELEASE_COMPLETEpdu *pdu_);
        void sendRELEASEconfToCC(uniRELEASEpdu *pdu_);
        void sendRELEASEindToCC(uniRELEASEpdu *pdu_);
        void sendRELEASEindToCC(pfUlong cause_);
        
        void sendRESET_ERRORindToCC(pfStorage &storage_);
        void sendRESETconfToCC(pfStorage &storage_);
        void sendRESETindToCC(pfStorage &storage_);

        // To PMP

        void sendADD_PARTYreqToPMP(uniADD_PARTYpdu *message_);
        void sendADD_PARTYrespToPMP(uniADD_PARTY_ACKpdu *message_);
        void sendADD_PARTYerrorToPMP(uniADD_PARTY_REJECTpdu *message_);
        void sendDROP_PARTYreqToPMP(uniDROP_PARTYpdu *message_);
        void sendDROP_PARTYrespToPMP(uniDROP_PARTY_ACKpdu *message_);
        void sendDROP_PARTYreqToAllPMPs(pfMessenger *message_);
        void sendSTATUSreqToPMP(uniSTATUS_ENQUIRYpdu *message_);
        
        // To CoOrd
        void sendRESETreqToCoOrd(pfStorage &storage_);
        void sendRESETrespToCoOrd(pfStorage &storage_);
        void sendRESET_ERRORrespToCoOrd(pfStorage &storage_);

        void sendSETUPpduToCoOrd(void);
        void sendSETUPpduToCoOrd(sigSETUPreq *primitive_);
        void sendSETUPpduToCoOrd(pfStorage &storage_); // to protected?
        void sendCONNECTpduToCoOrd(sigSETUPresp *primitive_);
        void sendCONNECT_ACKpduToCoOrd(void);
        void sendCALL_PROCEEDINGpduToCoOrd(sigPROCEEDINGreq *primitive_);
        void sendALERTINGpduToCoOrd(sigALERTINGreq *primitive_);
        
        void sendRELEASEpduToCoOrd(void);
        void sendRELEASEpduToCoOrd(sigRELEASEreq *primitive_);
        void sendRELEASEpduToCoOrd(pfStorage &storage_); // to protected?
        void sendRELEASEpduToCoOrd(pfUlong cause1_, pfUlong cause2_ = 0);
        void sendRELEASE_COMPLETEpduToCoOrd(sigRELEASEresp *primitive_);
        void sendRELEASE_COMPLETEpduToCoOrd(pfUlong cause_);

        void sendSTATUSpduToCoOrd(pfUlong cause_);
        void sendSTATUSpduToCoOrd(uniSTATUSresp *message_);
        void sendSTATUSpduToCoOrd(uniSTATUS_ENQUIRYpdu *message_);
        void sendSTATUS_ENQUIRYpduToCoOrd(void);
        void sendSTATUSpduToCoOrd(uniErrorInfo &errorInfo_, 
                          uniStateValue stateValue_);
        bool verifyMessage(uniPdu *pdu_, uniStateValue stateAfter_);
        
        void sendLINK_ESTABLISHreqToCoOrd(void);
        void sendLINK_RELEASEreqToCoOrd(void);

        void sendADD_PARTYpduToCoOrd(uniADD_PARTYreq *message_);
        void sendADD_PARTY_ACKpduToCoOrd(uniADD_PARTYresp *message_);
        void sendADD_PARTY_REJECTpduToCoOrd(uniADD_PARTYerror *message_);
        void sendDROP_PARTYpduToCoOrd(uniDROP_PARTYreq *message_);
        void sendDROP_PARTY_ACKpduToCoOrd(uniDROP_PARTYresp *message_);
        
        // State changes
        void changeToNullState(void); 
        void changeToCallInitiatedState(void);
        void changeToOutgoingCallProceedingState(void);
        void changeToCallDeliveredState(void);
        void changeToCallPresentState(void);
        void changeToCallReceivedState(void);
        void changeToConnectRequestState(void);
        void changeToIncomingCallProceedingState(void);
        void changeToActiveState(void);
        void changeToReleaseRequestState(void);
        void changeToReleaseIndicationState(void);

        // Status enquiry procedure
        void statusEnquiry(void);
        bool isCompatibleState(pfUlong state_);
        
        // Call clearing, miscellaneous
        void clearCall(void);
        void clearCall(pfUlong cause_);
        void clearCallIfNullState(uniSTATUSpdu *message_);
        void startReleaseProcess(pfUlong causeUp_,
                                 pfUlong causeDown_ = 0);
        void stopAllTimers(void);
        void clearPMPs(pfMessenger *message_);
        void triggerContinueClearing(void);
        void finalClearing(void);

        void reportIncompatibleMessage(uniPdu *message_);

        void setZeroEndpointReference(pfMessenger *message_);
        
        void setMultipointConnection(void);
        bool isMultipointConnection(void);

        void setUserMode(void);
        void setNetworkMode(void);
        bool isNetworkMode(void);
        bool compareCI(uniPdu *pdu_);
 
    protected:
        uniProtocol(void);

        void setMode(uniMode *mode_);
        void setDefaultLocation(void);
        void initTimers(void);

        void toAllPMPs(pfMessenger *primitive_);
        void toCC(pfMessenger *primitive_);
        
    private:
        uniSet _multipointSet;
        uniMode *_mode;
        ccProtocol *_cc;
};

#endif // __UNI_UNIPROTOCOL_H__

