//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / ILMI
//
//File: ilmistate.cpp
//
//Version: $Revision: 1.15 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/12/16 16:53:02 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Timo Pärnänen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include "ilmiprotocol.h"
#include "ilmistate.h"
#include "pf/error.h"

// Implementation of the singleton pattern

ilmiState *ilmiState::_only = 0;

ilmiState *ilmiState :: instance(void)
{
    if (_only == 0)
    {
        _only = new ilmiState;
    }
    return _only;
}

ilmiState :: ilmiState(void)
    : pfState(),
      cpcsUpInputs()
{
    return;
}

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

void ilmiState :: cpcsUNITDATAindAct(cpcsUNITDATAind *messenger_,
                                     pfProtocol *protocol_) const
{
    ilmiProtocol *protocol = dynamic_cast<ilmiProtocol *>(protocol_);
    THROW_IF_DYNAMIC_CAST_FAILED(protocol);
    
    protocol->setUDPAddress(messenger_->getAddress());
    
    pfFrame inputFrame = messenger_->getInterfaceData();
    int dataSize = (int)inputFrame.length();

    char data[dataSize];   
    inputFrame.copyData((unsigned char*)data);
    
    AsnBuf inputData;
    inputData.InstallData(data, dataSize);

    Message message;
    size_t decodedLength;

    // Decoding errors are not informed by SNMP protocol, but
    // it discards the message (RFC 1157 / 4.1).
    
    if (message.BDecPdu(inputData, decodedLength) != 0)
    {
        // This implementation accepts messages with any length.
        // (so it supports datagrams whose length exceeds 484 octets).
        
        // If there is a mismitch in version number or
        // authentication (community name) verifying,
        // the message is discarded (RFC 1157 / 4.1).

        if (protocol->verifyVersionNumber(message.version) != 0 &&
            protocol->communityCheck(message.community) != 0)
        {
            PDUs *pduData = message.data;

            switch(pduData->choiceId)
            {
                case PDUs::get_requestCid :
                    getRequestPduAct(pduData->get_request, protocol);
                    break;
                case PDUs::get_next_requestCid :
                    getNextRequestPduAct(pduData->get_next_request, protocol);
                    break;
                case PDUs::get_responseCid :
                    getResponsePduAct(pduData->get_response, protocol);
                    break;
                case PDUs::set_requestCid :
                    setRequestPduAct(pduData->set_request, protocol);
                    break;
                case PDUs:: trapCid:
                    trapPduAct(pduData->trap, protocol);
                    break;
                default :
                    // Message is discarded (RFC 1157 / 4.1).
                    break;
            }
        }
    }
    return;
}

//
//Functions: PDU inputs
//
//Description:
//    These PDU inputs are handled synchronously after ddecoding
//    in cpcsUNITDATAindAct method.
//

void ilmiState :: getRequestPduAct(GetRequest_PDU* pdu_,
                                   ilmiProtocol *protocol_) const
{
    protocol_->handleGetPDU(pdu_->request_id, pdu_->variable_bindings);
    return;
}

void ilmiState :: getNextRequestPduAct(GetNextRequest_PDU* pdu_,
                                       ilmiProtocol *protocol_) const
{
    protocol_->handleGetNextPDU(pdu_->request_id, pdu_->variable_bindings);
    return;
}

void ilmiState :: getResponsePduAct(GetResponse_PDU* pdu_,
                                    ilmiProtocol *protocol_) const
{
    protocol_->handleGetResponsePDU(pdu_->request_id,
                                    pdu_->error_status,
                                    pdu_->error_index,
                                    pdu_->variable_bindings);
    return;
}

void ilmiState :: setRequestPduAct(SetRequest_PDU* pdu_,
                                   ilmiProtocol *protocol_) const
{
    protocol_->handleSetPDU(pdu_->request_id, pdu_->variable_bindings);
    return;
}

void ilmiState :: trapPduAct(Trap_PDU* pdu_,
                             ilmiProtocol *protocol_) const
{
    protocol_->handleTrapPDU(pdu_->enterprise,
                             pdu_->agent_addr,
                             pdu_->generic_trap,
                             pdu_->specific_trap,
                             pdu_->time_stamp,
                             pdu_->variable_bindings);
    return;
}

