//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project/CC
//
//File: ccostate_sendcall.cpp
//
//Version: $Revision: 1.17 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/17 13:29:18 $
//
//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 "protocol/cc/ccprotocol.h"
#include "ccodp_answer.h"
#include "ccodp_noanswer.h"
#include "ccodp_busy.h"
#include "ccodp_termseized.h"
#include "ccodp_abandon.h"
#include "ccostate_sendcall.h"
#include "ccostate_selectroute.h"
#include "ccostate_exception.h"
#include "protocol/uni/unidefs.h"
#include "pf/debug.h"
#include "ie/connectionidentifier.h"
#include "pf/error.h"

ccOstateSendCall *ccOstateSendCall :: _only = 0;

ccOstateSendCall :: ccOstateSendCall(void)
    : ccOstate()
{
    return;
}

ccOstateSendCall :: ~ccOstateSendCall(void)
{
    _only = 0;
    return;
}

ccOstateSendCall *ccOstateSendCall :: instance(void)
{
    if(_only == 0)
    {
        _only = new ccOstateSendCall;
        assert(_only != 0);
    }
    return _only;
}

//
//Function: proceed
//
//Description:
//    Entry event: Indication of desire to set up a call to the
//    specified called party ID on the terminating call portion.
//

void ccOstateSendCall :: proceed(ccProtocol *protocol_)
{
    // ++TODO++ check busy condition from ? module
    // if busy: goto called party busy DP
    // if not busy: send setup
    
    sendSetup(protocol_);

    return;
}

//
//Function: sendSetup
//
//Description:
//    Create sigSETUPreq primitive and copy data to it
//    and send to opposite side.
//      

void ccOstateSendCall :: sendSetup(ccProtocol *protocol_)
{ 
    ieConnectionInfo *out = protocol_->getOutConnection();

    ieConnectionIdentifier *atmOutConnection = 
        dynamic_cast<ieConnectionIdentifier*>(out);
    THROW_IF_DYNAMIC_CAST_FAILED(atmOutConnection)

    pfUlong outVpci = atmOutConnection->getVPCI();
    pfUlong outVci = atmOutConnection->getVCI();

    pfStorage data = protocol_->getData("setup");
    pfStorage &ci = data[sigConnectionIdentifierStr];
    ci.setInteger(sigCI_VPCIStr, outVpci);
    ci.setInteger(sigCI_VCIStr, outVci);
    
    // Don't forward
    data.undefine(sigTransitNetworkSelectionStr);

    ccSETUPpdu *setup = new ccSETUPpdu(data);

#if CC_DEBUG
    char str[30];
    sprintf(str, "(VPI=%d,VCI=%d)", (int) outVpci, (int) outVci);
    string text("SETUP ");
    text+=str;    
    traceSend(ccCC,ccCCT,"SendCall", (char*) text.c_str());
#endif

    protocol_->toOtherSide(setup);

    return;
}


//
//Functions: signalling inputs.
//
//Description: none
//    
//
//


//
//Functions: inputs for messages from terminating side.
//
//Description:
//    
//
//

void ccOstateSendCall :: ccALERTINGpduAct(ccALERTINGpdu *,
                                          ccProtocol *protocol_)
{
#if CC_DEBUG
traceInput(ccCCT,ccCC,"SendCall","ALERTING");
#endif    
   
    // ++TODO++ Alerting is not supprted
    //protocol_->saveData("alerting", messenger_);
    
    exitAction(protocol_, ccOdpTermSeized::instance());

    return;
}

void ccOstateSendCall :: ccSETUPpduAct(ccSETUPpdu *messenger_,
                                       ccProtocol *protocol_)
{
#if CC_DEBUG
traceInput(ccCCT,ccCC,"SendCall","SETUP");
#endif

    protocol_->saveData("connect", messenger_);
   
    exitAction(protocol_, ccOdpAnswer::instance());

    return;
}
  
void ccOstateSendCall :: ccRELEASEpduAct(ccRELEASEpdu *messenger_,
                                         ccProtocol *protocol_)
{
#if CC_DEBUG
traceInput(ccCCT,ccCC,"SendCall","RELEASE");
#endif

    protocol_->saveData("releaseActive", messenger_);

    const pfStorage &storage =
        messenger_->getStorage(sigCauseStr);
    int cause = storage.getInteger(sigCause_ValueStr);
    
#if CC_DEBUG    
    cout << "Cause: " << cause << endl;
#endif
    
    // Different state transition with different cause values.

    if (cause == uniCauseValue_NoUserResponding)
    {
        exitAction(protocol_,ccOdpNoAnswer::instance());
    }
    else if (cause == uniCauseValue_UserBusy)
    {
        exitAction(protocol_,ccOdpCalledPartyBusy::instance());   
    }
    else // Exception
    {
        exitAction(protocol_, ccOstateException::instance());
    }
    
    return;
}








