//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project/CC
//
//File: dp.cpp
//
//Version: $Revision: 1.33 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/11/18 09:56:31 $
//
//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 "ccprotocol.h"
#include "dp.h"
#include "ccdpstate.h"
#include "trigger_digitstring.h"
#include "trigger_freephone.h"

ccDp :: ccDp(ccDpState *dpState_)
    : _monitorMode(toveinap_transparent),
      _messageType(toveinap_notification),
      _TDP(false),
      _triggers(),
      _iter(_triggers.begin()),
      _dpState(dpState_),
      _count(0)
{  
    return;    
}

ccDp :: ccDp(const ccDp &other_)
    : _monitorMode(other_._monitorMode),
      _messageType(other_._messageType),
      _TDP(other_._TDP),
      _triggers(other_._triggers),
      _iter(_triggers.begin()),
      _dpState(other_._dpState),
      _count(0)
{
    return;
}
    
ccDp :: ~ccDp(void)
{
    return;
}

const ccDp &ccDp :: operator = (const ccDp &other_)
{
    if (this != &other_) // if not x = x situation
    {
        _monitorMode = other_._monitorMode;
        _messageType = other_._messageType;
        _TDP = other_._TDP;
        _triggers = other_._triggers;
        _iter = other_._iter;
        _dpState = other_._dpState;
    }
    return *this;
}

ccDp *ccDp :: cloneImplementation(void) const 
{
    ccDp *newDp = new ccDp(*this);
    assert(newDp != 0);
    return newDp;
}

//
//Functions: DP's state
//
//Description: 
//   Functions indicating DP's current state.   
//

bool ccDp :: isArmed(void) const
{
    bool result = false;
    if ((_monitorMode != toveinap_transparent) || (_TDP != false))
    {
        result = true;
    }
    return result;
}

bool ccDp :: isEDP_N(void) const
{
    bool result = false;
    if (_monitorMode == toveinap_notifyAndContinue)
    {
        result = true;
    }
    return result;
}

bool ccDp :: isEDP_R(void) const
{
    bool result = false;
    if (_monitorMode == toveinap_interrupted)
    {
        result = true;
    }
    return result;
}

bool ccDp :: isTDP_N(void) const
{
    bool result = false;
    if (_TDP != false && _messageType == toveinap_notification)
    {
        result = true;
    }
    return result;
}

bool ccDp :: isTDP_R(void) const
{
    bool result = false;
    if (_TDP != false && _messageType == toveinap_request)
    {
        result = true;
    }
    return result;
}

//
//Functions: getAllowedTriggers
//
//Description:
//    Returns allowed triggers for manager.
//

ccIf_TriggersType ccDp :: getAllowedTriggers(void) const
{
    ccIf_TriggersType result;
    
    if (_dpState != 0)
    {
        result = _dpState->allowedTriggers();
    }
    
    return result;
}

//
//Functions: getActiveTriggers
//
//Description:
//    Returns armed triggers for manager.
//

ccIf_TriggersType ccDp :: getActiveTriggers(void) const
{
    ccIf_TriggersType triggers;
    unsigned int index = 0;
    unsigned int size = 0;
    
    size = _triggers.size();
    triggers.length(size);
    
    listType::const_iterator iter = _triggers.begin();
               
    for (; iter != _triggers.end(); ++iter)
    {
        string tmpStr;
        
        tmpStr = (*iter).getType();
        triggers[index].type = CORBA_string_dup(tmpStr.c_str());

        tmpStr = (*iter).getCriteria();
        triggers[index].criteria = CORBA_string_dup(tmpStr.c_str());

        tmpStr = (*iter).getCategory();
        triggers[index].category = CORBA_string_dup(tmpStr.c_str());

        triggers[index].serviceKey = (*iter).getServiceKey();
        
        ++index;
    }

    return triggers;
}

//
//Functions: set/get DP monitor mode
//
//Description: For manager.
//

void ccDp :: setMonitorMode(toveinap_MonitorModeType monitorMode_)
{
    _monitorMode = monitorMode_;    
    return;
}

toveinap_MonitorModeType ccDp :: getMonitorMode() const
{
    return _monitorMode;
}

//
//Functions: get/set DP message Type
//
//Description: For manager.
//

void ccDp :: setMessageType(string type_)
{
    if (type_ == getNotificationStr())
    {
        _messageType = toveinap_notification;
    }
    else
    {
        _messageType = toveinap_request;
    }
    
    return;
}

string ccDp :: getMessageType(void) const
{
    string result;
    
    if (_messageType == toveinap_notification)
    {
        result = getNotificationStr();
    }
    else
    {
        result = getRequestStr();
    }

    return result;
}

toveinap_MessageTypeType ccDp :: getInapMessageType(void) const
{
    return _messageType;
}


//
//Functions: iteration
//
//Description:
//   Iterator interface
//

void ccDp :: resetTriggerCount(void)
{
    _iter = _triggers.begin();
    _count = 0;
    return;
}

void ccDp :: nextTrigger(void)
{
    ++_iter;
    ++_count;
    return;
}

bool ccDp :: anyTriggersLeft(void)
{
    bool result = false;
    if (_count < _triggers.size())
    {
        result = true;
    }
    return result;
}


//
//Function: triggerCriteriaMet
//
//Description:
//    Check current triggers criteria.
//

bool ccDp :: triggerCriteriaMet(ccProtocol *protocol_) const
{
    bool result = false;
    result = (*_iter).checkCriteria(protocol_);
    return result;
}

//
//Function: fillRequest
//
//Description:
//    Fill initial message (to SCF) with tigger specific info.  
//

void ccDp :: fillTDPrequest(ccProtocol *protocol_,
                            toveinap_InitialDPArgType &initialDPArg_,
                            string &applicationContext_, 
                            string &address_)
{
    // Application context
    applicationContext_ = (*_iter).getApplicationContext();
    
    // Address
    address_ = (*_iter).getAddress();    

    // Service key
    initialDPArg_.serviceKey = (*_iter).getServiceKey();

    // Called party number
    string numberString = protocol_->getCalledPartyNumber();
    unsigned int size = numberString.size();
    toveinap_CalledPartyNumberTypeOpt calledPartyNumberOpt;
    toveinap_CalledPartyNumberType calledPartyNumber;
    if (size > 0)
    {
        unsigned int startPos = 0;
        
        // If number is over 10 chars long cut it to last 10 chars
        if (size > 10)
        {
            startPos = size - 10;
            size = 10;
        }
       
        calledPartyNumber.length(size);

        for (unsigned int i=0; i < size; i++)
        {
            calledPartyNumber[i] = numberString[startPos + i];
        }
        calledPartyNumberOpt.calledPartyNumber(calledPartyNumber);
    }
    initialDPArg_.calledPartyNumber = calledPartyNumberOpt;

    // Calling party number
    toveinap_CallingPartyNumberTypeOpt callingPartyNumberOpt;
    try
    {
        numberString = protocol_->getCallingPartyNumber();
        size = numberString.size();
        toveinap_CallingPartyNumberType callingPartyNumber;

        unsigned int startPos = 0;
         // If number is over 10 chars long cut it to last 10 chars
        if (size > 10)
        {
            startPos = size - 10;
            size = 10;
        }
      
        callingPartyNumber.length(size);

        for (unsigned int i=0; i < size; i++)
        {
            callingPartyNumber[i] = numberString[startPos + i];
        }
        callingPartyNumberOpt.callingPartyNumber(callingPartyNumber);
    }
    catch(pfNameUndefinedException &ex) 
    {
        // No callingParyNumber
         callingPartyNumberOpt._default();
    }

    initialDPArg_.callingPartyNumber = callingPartyNumberOpt;
    
    // CallingPartysCategory
    toveinap_CallingPartysCategoryTypeOpt callingPartysCategoryOpt;
    callingPartysCategoryOpt._default();
    initialDPArg_.callingPartysCategory = callingPartysCategoryOpt;

    // MiscCallInfo
    toveinap_MiscCallInfoType miscCallInfo;
    miscCallInfo.messageType = getInapMessageType();
    miscCallInfo.dpAssignment = (*_iter).getInapCategory(); 
    toveinap_MiscCallInfoTypeOpt miscCallInfoOpt;
    miscCallInfoOpt.miscCallInfo(miscCallInfo);
    initialDPArg_.miscCallInfo = miscCallInfoOpt;
   
    // Trigger type
    toveinap_TriggerTypeType triggerType; 
    triggerType = (*_iter).getInapType();
    toveinap_TriggerTypeTypeOpt triggerTypeOpt;
    triggerTypeOpt.triggerType(triggerType);
    initialDPArg_.triggerType = triggerTypeOpt;

    // EventTypeBCSM
    toveinap_EventTypeBCSMType eventTypeBCSM;
    eventTypeBCSM = getInapType();
    toveinap_EventTypeBCSMTypeOpt eventTypeBCSMOpt;
    eventTypeBCSMOpt.eventTypeBCSM(eventTypeBCSM);
    initialDPArg_.eventTypeBCSM = eventTypeBCSMOpt;
    
    return;
}

void ccDp :: fillEDPrequest(ccProtocol *protocol_,
                            toveinap_EventReportBCSMArgType &arg_)
{
    //arg_.callID = protocol_->getInapCallId();
    arg_.eventTypeBCSM = getInapType();
    //miscCallInfo.messageType is set at calling method
    arg_.miscCallInfo.dpAssignment = toveinap_individualLine;
    
    return;
}

//
//Functions: Get current triggers type/criteria
//
//Description:
//
//

toveinap_TriggerTypeType ccDp :: getCurrentTriggerInapType(void) const
{
    toveinap_TriggerTypeType result = (*_iter).getInapType();
    return result;
}


string ccDp :: getCurrentTriggerCriteria(void) const
{
    string result = (*_iter).getCriteria();
    return result;
}

//
//Functions: Get DP type
//
//Description:
//
//

toveinap_EventTypeBCSMType ccDp :: getInapType(void) const
{
    toveinap_EventTypeBCSMType result;

    if (_dpState != 0)
    {
        result  = _dpState->getInapType();
    }
    
    return result;
}

string ccDp :: getType(void) const
{
    string result;
    
    if (_dpState != 0)
    {
        result = _dpState->getType();
    }
    
    return result;
}

//
//Function: addTrigger
//
//Description:
//
//

void ccDp :: addTrigger(const ccIf_TriggerType &newTriggerParam_)
{
    _TDP = true;
    
    string typeStr(CORBA_string_dup(newTriggerParam_.type));
    string tmpCategory(CORBA_string_dup(newTriggerParam_.category));
    string tmpCriteria(CORBA_string_dup(newTriggerParam_.criteria));
    string tmpContext(CORBA_string_dup(newTriggerParam_.applicationContext));
    string tmpAddress(CORBA_string_dup(newTriggerParam_.address));

#if CC_DEBUG
    cout << " type=" << typeStr 
         << " category=" << tmpCategory 
         << " criteria=" << tmpCriteria 
         << " applicationContext=" << tmpContext
         << " address=" << tmpAddress
         << " serviceKey= " << newTriggerParam_.serviceKey
         << endl;
#endif    
    
    // What is the type of the trigger?
    if (typeStr == ccTriggerDigitString::getStaticType())
    {
        ccTriggerDigitString *triggerImpl = new ccTriggerDigitString;
        ccTrigger newTrigger(triggerImpl);
        
        newTrigger.setCriteria(tmpCriteria);
        newTrigger.setCategory(tmpCategory); 
        newTrigger.setServiceKey(newTriggerParam_.serviceKey);
        newTrigger.setApplicationContext(tmpContext);
        newTrigger.setAddress(tmpAddress);
        
        _triggers.push_back(newTrigger);
    }
    else if (typeStr == ccTriggerFreePhone::getStaticType())
    {
        ccTriggerFreePhone *triggerImpl = new ccTriggerFreePhone;
        ccTrigger newTrigger(triggerImpl);
        
        newTrigger.setCategory(tmpCategory);
        newTrigger.setServiceKey(newTriggerParam_.serviceKey);
        newTrigger.setApplicationContext(tmpContext);
        newTrigger.setAddress(tmpAddress);
        
        _triggers.push_back(newTrigger);
    }
    else
    {
        cerr << "Trigger " << typeStr << " not implemented" << endl;
        _TDP = false;
    }

    resetTriggerCount();
    return;
}

//
//Function: deleteTrigger
//
//Description:
//
//

void ccDp :: deleteTrigger(const ccIf_TriggerType &trigger_)
{
    string typeStr(CORBA_string_dup(trigger_.type));
    string criteriaStr(CORBA_string_dup(trigger_.criteria));

#if CC_DEBUG
cout << " Trigger Type: " << typeStr << "Criteria: " << criteriaStr << endl;
#endif 
    
    listIterType iter = _triggers.begin();

    // Trigger is indentified based on type and criteria.
    for (; iter != _triggers.end(); ++iter)
    {
        if ((*iter).getType() == typeStr)
        {
            if ((*iter).getCriteria() == criteriaStr)
            {
                _triggers.remove((*iter));
                //++TODO++ this may not work.
                //Iterator must be initialized if something
                //is removed.
                break;
            }
        }
    }

    resetTriggerCount();

    return;
}

//
//Functions: static methods
//
//Description:
//     Strings for manager UI.
//

string ccDp :: getNotificationStr(void)
{
    string result("notification");
    return result;
}

string ccDp :: getRequestStr(void)
{
    string result("request");
    return result;
}




