//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / bisup
//
//File: bisuppducoder.cpp
//
//Version: $Revision: 1.22 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/08 07:42:31 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
// 
//Author:
//      Timo Kokkonen
//      Sami Raatikainen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History:
//

#include "bisuppducoder.h"
#include "bisuppducoders.h"
#include "nnimessages.h"
#include "iface/sigif/sigprimitive.h"
#include "niprotocol.h"
#include "protocol/sig/sigexceptions.h"
#include "pf/debug.h"
#include "pf/error.h"

bisupPduCoder :: bisupPduCoder(pfUlong pduType_)
    : pduCoder(pduType_)
{
    return;
}

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


//
//Function: create
//
//Description:
//      Static method to create a new PDU from frame, if create fails method
//      returns bisupERRORind or throws pfPDUDecodeFailedException.
//      We can catch all exceptions here by catching pfException but later
//      we have to act different way to each exceptions. For example protocol
//      sends different messages back (cause value depends on exception).
//

pfMessenger *bisupPduCoder :: create(pfFrame &frame_)
{
    bisupPduCoder *coder = 0;
    pfMessenger *msg = 0;
    
    if (frame_.length() < BISUP_PDU_MIN_LENGTH)
    {
        throw sigDiscardMessageException(PF_EX_INFO);
    }
    
    pfByte pduType = frame_.read(0);
    try
    {
        switch (pduType)
        {
            case B1111_1111:  // testcoder
                debugUser("received TESTFRAME");
                coder = new testCoder;
                msg = new sigPrimitive;
                break;
                
            case bisupMsgACM:
                debugUser("received ACM");
                coder = niProtocol::getACMCoder();
                msg = new nniACMpdu;
                break;
                
            case bisupMsgANM:
                debugUser("received ANM");
                coder = niProtocol::getANMCoder();
                msg = new nniANMpdu;
                break;

            case bisupMsgIAA:
                debugUser("received IAA");
                coder = niProtocol::getIAACoder();
                msg = new nniIAApdu;
                break;
                
            case bisupMsgIAR:
                debugUser("received IAR");
                coder = niProtocol::getIARCoder();
                msg = new nniIARpdu;
                break;
                
            case bisupMsgIAM:
                debugUser("received IAM");
                coder = niProtocol::getIAMCoder();
                msg = new nniIAMpdu;
                break;

            case bisupMsgREL:
                debugUser("received REL");
                coder = niProtocol::getRELCoder();
                msg = new nniRELpdu;
                break;
                
            case bisupMsgRLC:
                debugUser("received RLC");
                coder = niProtocol::getRLCCoder();
                msg = new nniRLCpdu;
                break;
                
            default:
                debugUser("received unrecognized pdu");
                throw sigDiscardMessageException(PF_EX_INFO);
                break;
        }
        if (coder == 0 || msg == 0)
        {
            throw sigException(PF_EX_INFO);
        }
        
        // Decode the received pdu
        coder->decode(frame_, msg);
        
        // Check if all mandatory parameters were decoded
        coder->checkMandatoryIEs();
    }
    
    // here is possibility to catch various exceptions and have a different
    // action for different situation
    catch (sigNonMandatoryIEContentErrorException &excep)
    {
        coder->nonMandatoryIEContentErrorAct();
    }
    catch (sigUnrecognizedIEException &excep)
    {
        coder->unrecognizedIEAct();
    }
    
    // Any other exception coming through causes discarding the message
    catch (...)
    {
        delete msg;
        throw;
    }
    return msg;
}


//
//Function: decodeHeader
//
//Description:
//      Decodes bisupPdu's header. Doesn't store any information
//      from the header part.
//

void bisupPduCoder :: decodeHeader(pfFrame &frame_, pfMessenger *)
{
    frame_.getFirst(); // PDU type
    pfUlong PDUlength = frame_.getFirst16bit();
    pfUlong length = frame_.length();
    
    if (PDUlength != length)
    {
        debugUser("Framelength did not match with message length!");
        // Decoding shall continue as far as possible.
    }
    
    // Don't use compatibility information and belive that compatibility's 
    // length is one octet even if extension bit is used.
    frame_.getFirst();
    return;
}

//
//Function: encodeHeader
//
//Description:
//      Encodes bisupPdu's header.
//

void bisupPduCoder :: encodeHeader(pfFrame &frame_, pfMessenger *)
{
    pfUlong length;
    frame_.putFirst(BISUP_PDU_COMPATIBILITY_OCTET);
    length = frame_.length();    
    frame_.putFirst16bit(length);
    frame_.putFirst(getType());
    return;
}


void bisupPduCoder:: nonMandatoryIEContentErrorAct(void)
{
    checkMandatoryIEs();
    return;
}

void bisupPduCoder:: unrecognizedIEAct(void)
{
    checkMandatoryIEs();
    return;
}
