//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project/CC
//
//File: ccstate.cpp
//
//Version: $Revision: 1.49 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/02 09:41:03 $
//
//Organisation:
//      University of Technology
// 
//Author:
//      Pasi Nummisalo
//
//Description:
//     See header.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//      
//Licence:
//     
//
//History:
//

#include "ccstate.h"
#include "ccprotocol.h"
#include "ccdpstate.h"
#include "iface/sigif/sigdownprimitives.h"
#include "pf/error.h"
#include <string>

ccState :: ccState(void)
    : pfState()
{
    return;
}

ccState :: ~ccState(void)
{
    return;
}

//
//Function: exitAction 
//
//Description: exit action from PIC to DP
//      
//

void ccState :: exitAction(pfProtocol *protocol_, ccState *state_)
{
    protocol_->changeState(state_);

    ccProtocol *ccprotocol = dynamic_cast<ccProtocol*>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(ccprotocol);
    state_->proceed(ccprotocol);
    return;
}

//
//Function: exitAction
//
//Description:
//        Exit action for DP -> PIC
//

void ccState :: exitAction(ccProtocol *protocol_, ccDpState *state_)
{
    protocol_->changeState(state_);
    state_->proceed(protocol_);
    return;
}

//
//Function: exitAction
//
//Description:
//        Entry action for DP and PIC.
//

ccProtocol *ccState :: entryAction(pfProtocol *protocol_)
{
    ccProtocol *ccprotocol = dynamic_cast<ccProtocol*>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(ccprotocol);
    return ccprotocol;
}

//
//Function: releaseAction
//
//Description:
//        Common release actions.
//

void ccState :: releaseAction(ccProtocol *protocol_)
{

    if (protocol_->_data.isVariableDefined("releaseActive"))
    {
        // Down          CC           CC
        //            (active)       
        //                <-------RELEASE_ACTIVE/RELEASE
        //             (null)
        //  <---- RELEASEreq
        // ......................................
        //             (null)
        // RELEASEconf--->
        //             (null)
        // [<--RELEASEresp]
        //           (destroyed)
        
#if CC_DEBUG    
traceSendHelper(protocol_, ccDOWN, "RELEASEreq");
#endif 
        sigRELEASEreq *releaseReq = new sigRELEASEreq;
        protocol_->copyData(releaseReq, "releaseActive");
        protocol_->toDown(releaseReq);     
        // wait for RELEASEconf
    }
    else if (protocol_->_data.isVariableDefined("releaseIndActive"))
    {
        // Down        CC           CC
        //              (active)
        // RELEASEind---->
        //             (null)
        //               RELEASE_ACTIVE---->
        // <-------RELEASEresp
        //           (destroyed)

#if CC_DEBUG    
traceSendHelper(protocol_, ccCC,"RELEASE_ACTIVE");
#endif
         // We don't care if there is T-side or not 
         ccRELEASE_ACTIVEpdu *release = new ccRELEASE_ACTIVEpdu; 
         protocol_->copyData(release, "releaseIndActive");
         protocol_->toOtherSide(release);

#if CC_DEBUG    
traceSendHelper(protocol_, ccDOWN,"RELEASEresp");
#endif
         // Release Complete
         sigRELEASEresp *releaseResp = new sigRELEASEresp;
         protocol_->copyData(releaseResp, "releaseIndActive");
         protocol_->toDown(releaseResp);
    }
    else if (protocol_->_data.isVariableDefined("release"))
    {
        // Down         CC           CC
        //              (x)       
        //                <--------- RELEASE
        //             (null)
        //  <---- RELEASEresp
        //           (destroyed)
        
#if CC_DEBUG    
traceSendHelper(protocol_, ccDOWN,"RELEASEresp");
#endif
         // Release Complete
         sigRELEASEresp *releaseResp = new sigRELEASEresp;
         protocol_->copyData(releaseResp,"release");
         protocol_->toDown(releaseResp);

    }
    else if(protocol_->_data.isVariableDefined("releaseInd"))
    {
        // Down        CC           CC
        //              (x)
        // RELEASEind---->/
        //               <------wrong message
        //             (null)
        //               RELEASE---->
        // <-------RELEASEresp
        //           (destroyed)

#if CC_DEBUG
traceSendHelper(protocol_, ccCC,"RELEASE");
#endif
         // We don't care if there is T-side or not 
         ccRELEASEpdu *release = new ccRELEASEpdu; 
         protocol_->copyData(release, "releaseInd");
         protocol_->toOtherSide(release);

#if CC_DEBUG    
traceSendHelper(protocol_, ccDOWN,"RELEASEresp");
#endif
         // Release Complete
         sigRELEASEresp *releaseResp = new sigRELEASEresp;
         protocol_->copyData(releaseResp, "releaseInd");
         protocol_->toDown(releaseResp);
    }    
    else if(protocol_->_data.isVariableDefined("releaseConf"))
    {
        // Down          CC         CC
        //              (x)
        // RELEASEconf--->
        //             (null)
        //               RELEASE---->
        //             (null)
        // [<---RELEASEresp]
        //           (destroyed)
 
         // We don't care if there is T-side or not 
         ccRELEASEpdu *release = new ccRELEASEpdu; 
         protocol_->copyData(release, "releaseConf");
         protocol_->toOtherSide(release);

#if CC_DEBUG
traceSendHelper(protocol_, ccCC,"RELEASE");
#endif

         sendReadyForDeletionMessage(protocol_);
    }

    // Common close actions
    protocol_->close();
    
    // Notification to manager
    // toveManager::instance()->callReleased((long) protocol_->getId());
    
    return;
}

//
//Function: sendReadyForDeletionMessage
//
//Description:
//      Send Release response to inform signalling layer
//      that we are ready to be destroyed.
//      (not part of standard signalling sequence)
//

void ccState :: sendReadyForDeletionMessage(ccProtocol *protocol_)
{
    sigRELEASEresp *releaseResp = new sigRELEASEresp; 
    protocol_->toDown(releaseResp);
    
#if CC_DEBUG    
traceSendHelper(protocol_, ccDOWN,"RELEASEresp (ready)");
#endif

    return;
}

void ccState :: traceSendHelper(ccProtocol *sender_,
                                int receiver_,
                                const char *messenger_)
{
#if CC_DEBUG
    string messenger(messenger_);
    string state("null");
    ccDebug::instance()->sendHelper(sender_, receiver_,
                                    state, messenger);
#endif
  
}

void ccState :: handleBinapMessage(binapPdu *)
{
#if CC_DEBUG
    debugUser("Got inap message during basic call processing. Discarding!");
#endif
    return;
}

// **********************************************************************
//
//Functions: Input functions for signalling interface (sigif/up) 
//
//Description:
//
//

void ccState :: sigSETUPindAct(sigSETUPind *, pfProtocol *)
{
    debugUser("Unexpected message sigSETUPind. Discarding!");
    return;
}
               
void ccState :: sigPROCEEDINGindAct(sigPROCEEDINGind *, pfProtocol *)
{
    debugUser("Unexpected message sigPROCEEDINGind. Discarding!");
    return;
}

void ccState :: sigSETUPconfAct(sigSETUPconf *, pfProtocol *)
{
    debugUser("Unexpected message sigSETUPconf. Discarding!");
    return;
}

void ccState :: sigSETUP_COMPLETEindAct(
    sigSETUP_COMPLETEind *, pfProtocol *)
{
    debugUser("Unexpected message sigSETUP_COMPLETEind. Discarding!");
    return;
}

void ccState :: sigRELEASEindAct(sigRELEASEind *, pfProtocol *)
{
    debugUser("Unexpected message sigRELEASEind. Discarding!");
    return;
}
         
void ccState :: sigRELEASEconfAct(sigRELEASEconf *, pfProtocol *)
{
    debugUser("Unexpected message sigRELEASEconf. Discarding!");
    return;
}
                
void ccState :: sigRESETindAct(sigRESETind *, pfProtocol *)
{
    debugUser("Unexpected message sigRESETind. Discarding!");
    return;
}
        
void ccState :: sigRESETconfAct(sigRESETconf *, pfProtocol *)
{
    debugUser("Unexpected message sigRESETconf. Discarding!");
    return;
}
        
void ccState :: sigRESET_ERRORindAct(sigRESET_ERRORind *, pfProtocol *)
{
    debugUser("Unexpected message sigRESET_ERRORind. Discarding!");
    return;
}


//----------------- Additional --------------------------------

/*
       
void ccState :: sigNOTIFYindAct(sigNOTIFYind *, pfProtocol *)
{
    return;
}
 
       
void ccState :: sigALERTINGindAct(sigALERTINGind *, pfProtocol *)
{
    return;
}

  
void ccState :: sigMORE_INFOindAct(sigMORE_INFOind *, pfProtocol *)
{
    return;
}

void ccState :: sigINFOindAct(sigINFOind *, pfProtocol *)
{
    return;
}
        
void ccState :: sigPROGRESSindAct(sigPROGRESSind *, pfProtocol *)
{
    return;
}
*/


// **********************************************************************
//
//Functions: Input functions for binap interface (from SCP)
//
//Description:
//    Maybe binap messages must be saved if they arrive during
//    state processing and process later?
//
//

void ccState :: binapANALYSE_INFORMATIONpduAct(
    binapANALYSE_INFORMATIONpdu *pdu_,
    ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapAUTHORIZE_ORIGINATIONpduAct(
    binapAUTHORIZE_ORIGINATIONpdu *pdu_,
    ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapCOLLECT_INFORMATIONpduAct(
    binapCOLLECT_INFORMATIONpdu *pdu_,
    ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapREQUEST_REPORT_BCSM_EVENTpduAct(
    binapREQUEST_REPORT_BCSM_EVENTpdu *pdu_,
    ccProtocol *protocol_)
{
    // Arm EDPs and continue
    pdu_->setDPValues(protocol_);
    return;
}

void ccState :: binapCONTINUEpduAct(
            binapCONTINUEpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapSELECT_ROUTEpduAct(
            binapSELECT_ROUTEpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapPRESENT_CALLpduAct(
            binapPRESENT_CALLpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapSELECT_FACILITYpduAct(
            binapSELECT_FACILITYpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapAUTHORIZE_TERMINATIONpduAct(
            binapAUTHORIZE_TERMINATIONpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

void ccState :: binapRELEASE_CALLpduAct(
            binapRELEASE_CALLpdu *pdu_,
            ccProtocol *)
{
    handleBinapMessage(pdu_);
    return;
}

