/*
 * mms_receiver_sates.def - states for MMS message receiver session state machines
 *
 * Macro calls to generate rows of the state table. See the documentation for
 * guidance how to use and update these.
 *
 * Note that `NULL' state is renamed to `NULL_SESSION' because NULL is
 * reserved by C.
 *
 * Marcel Jansen
 */

STATE_NAME(NULL_STATE)
STATE_NAME(BEARER_WAITING)
STATE_NAME(CONNECTING)
STATE_NAME(WAITING)
STATE_NAME(ACKNOWLEDGING)
STATE_NAME(NOTIFYRESPONSE)

ROW(NULL_STATE,
	S_Unit_Push_Ind,
	/* no bearer */ ! checkInterface(interface),
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(NULL_STATE,
	S_Unit_Push_Ind,
	/* bearer */ checkInterface(interface) && /* use WSP */ wapIpAddress != NULL,
	{
        /* need to create an address tuple */
        sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)


ROW(NULL_STATE,
	S_Unit_Push_Ind,
	/* bearer */ checkInterface(interface) && /* use HTTP */ wapIpAddress == NULL,
	{
        httpGet(sm->notification->u.NotificationInd.content_location, sm);
	},
	WAITING)


ROW(BEARER_WAITING,
	Bearer_Event,
	/* use WSP */ wapIpAddress != NULL,
	{
        /* need to create an address tuple, might rely (for purpose of DNS) on
           bearer capacity */
        sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)

ROW(BEARER_WAITING,
	Bearer_Event,
	/* use HTTP */ wapIpAddress == NULL,
	{
        httpGet(sm->notification->u.NotificationInd.content_location, sm);
	},
	WAITING)


ROW(BEARER_WAITING,
	TimerTO_A_bearer,
	1,
	{   
        long d;

        /* Make sure that any ongoing bearer service startups are
           cancelled */
        stopbearerservice();

        /* give the bearer service a bit longer to get going */
        d = e->delay;
        d = d * 2 < MAX_BEARER_DELAY ? d * 2 : MAX_BEARER_DELAY;
        
        /* TODO may need a delay here */
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, d);
	},
	BEARER_WAITING)


ROW(CONNECTING,
	S_Connect_Cnf,
	1,
	{
        wspGet(sm->notification->u.NotificationInd.content_location, sm);
	},
	WAITING)

ROW(CONNECTING,
	S_Disconnect_Ind,
	/* no bearer */ ! checkInterface(interface),
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(CONNECTING,
	S_Disconnect_Ind,
	/* bearer */ checkInterface(interface),
	{
        if (sm->addrtuple == NULL)
            sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)

ROW(CONNECTING,
	Bearer_Lost_Event,
	1,
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)



ROW(WAITING,
	S_Disconnect_Ind,
	/* no bearer */ ! checkInterface(interface),
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(WAITING,
	S_Disconnect_Ind,
	/* bearer */ checkInterface(interface),
	{
        if (sm->addrtuple == NULL)
            sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)

ROW(WAITING,
	S_MethodInvoke_Cnf,
	1,
	{
        /* ignore */
	},
	WAITING)

ROW(WAITING,
	S_MethodResult_Ind,
	pdu->type == RetrieveConf && pdu->u.RetrieveConf.x_mms_transaction_id != NULL,
	{
        if (sm->retrieveconf != NULL) 
            mms_pdu_destroy(sm->retrieveconf);
        sm->retrieveconf = pdu;

        notifyClient(e->status, pdu, sm);
        sendWspAcknowledgement(pdu->u.RetrieveConf.x_mms_transaction_id, sm);
	},
	ACKNOWLEDGING)

ROW(WAITING,
	S_MethodResult_Ind,
	pdu->type == RetrieveConf && pdu->u.RetrieveConf.x_mms_transaction_id == NULL /* ack not needed needed */,
	{
        if (sm->retrieveconf != NULL) 
            mms_pdu_destroy(sm->retrieveconf);
        sm->retrieveconf = pdu;
        
        sm->retrieveconf = pdu;
        notifyClient(e->status, pdu, sm);
        sendWspNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
	},
	NOTIFYRESPONSE)

ROW(WAITING,
    HTTP_Request_Completed_Event,
    http_status_class(e->status) == HTTP_STATUS_SUCCESSFUL && pdu->u.RetrieveConf.x_mms_transaction_id != NULL,
    {
        if (sm->retrieveconf != NULL) 
            mms_pdu_destroy(sm->retrieveconf);
        sm->retrieveconf = pdu;

        notifyClient(e->status, pdu, sm);
        sendHttpAcknowledgement(pdu->u.RetrieveConf.x_mms_transaction_id, sm);
    },
	ACKNOWLEDGING)

ROW(WAITING,
    HTTP_Request_Completed_Event,
    http_status_class(e->status) == HTTP_STATUS_SUCCESSFUL && pdu->u.RetrieveConf.x_mms_transaction_id == NULL,
    {
        if (sm->retrieveconf != NULL) 
            mms_pdu_destroy(sm->retrieveconf);
        sm->retrieveconf = pdu;

        notifyClient(e->status, pdu, sm);
        sendHttpNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
    },
	NOTIFYRESPONSE)



ROW(WAITING,
	S_MethodAbort_Ind,
	1,
	{
        /* method aborted, try again */
        /* TODO may need to be a bit more sophisticated than a simple retry */
        wspGet(sm->notification->u.NotificationInd.content_location, sm);
	},
	WAITING)


ROW(WAITING,
	HTTP_Request_Completed_Event,
	http_status_class(e->status) != HTTP_STATUS_SUCCESSFUL,
	{
        /* method aborted, try again */
        /* TODO may need to be a bit more sophisticated than a simple retry */
        httpGet(sm->notification->u.NotificationInd.content_location, sm);
	},
	WAITING)


ROW(WAITING,
	Bearer_Lost_Event,
	1,
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)


ROW(ACKNOWLEDGING,
	S_Disconnect_Ind,
	/* no bearer */ ! checkInterface(interface),
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(ACKNOWLEDGING,
	S_Disconnect_Ind,
	/* bearer */ checkInterface(interface),
	{
        if (sm->addrtuple == NULL)
            sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)

ROW(ACKNOWLEDGING,
	S_MethodInvoke_Cnf,
	1,
	{
        sendWspNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
	},
	NOTIFYRESPONSE)

ROW(ACKNOWLEDGING,
	S_MethodResult_Ind,
	1,
	{
        /* ignore */
	},
	ACKNOWLEDGING)

ROW(ACKNOWLEDGING,
	S_MethodAbort_Ind,
	1,
	{
        sendWspAcknowledgement(sm->retrieveconf->u.RetrieveConf.x_mms_transaction_id, sm);
	},
	ACKNOWLEDGING)

ROW(ACKNOWLEDGING,
	Bearer_Lost_Event,
	1,
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(ACKNOWLEDGING,
	HTTP_Request_Completed_Event,
	http_status_class(e->status) == HTTP_STATUS_SUCCESSFUL,
	{
        sendHttpNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
	},
	NOTIFYRESPONSE)


ROW(ACKNOWLEDGING,
	HTTP_Request_Completed_Event,
	http_status_class(e->status) == HTTP_STATUS_SUCCESSFUL,
	{
        sendHttpAcknowledgement(sm->retrieveconf->u.RetrieveConf.x_mms_transaction_id, sm);
	},
	NOTIFYRESPONSE)


ROW(NOTIFYRESPONSE,
	S_Disconnect_Ind,
	/* no bearer */ ! checkInterface(interface),
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(NOTIFYRESPONSE,
	S_Disconnect_Ind,
	/* bearer */ checkInterface(interface),
	{
        if (sm->addrtuple == NULL)
            sm->addrtuple = getRequestTuple(interface);

        /* send connect request */
        sendWSPConnectRequest(sm->addrtuple, sm->machine_id);
	},
	CONNECTING)

ROW(NOTIFYRESPONSE,
	S_MethodInvoke_Cnf,
	1,
	{
        sendWSPDisconnectRequest(sm->machine_id);
	},
	NULL_STATE)

ROW(NOTIFYRESPONSE,
	S_MethodResult_Ind,
	1,
	{
        sendWSPDisconnectRequest(sm->machine_id);
	},
	NULL_STATE)


ROW(NOTIFYRESPONSE,
	S_MethodAbort_Ind,
	1,
	{
        sendWspNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
	},
	NOTIFYRESPONSE)

ROW(NOTIFYRESPONSE,
	Bearer_Lost_Event,
	1,
	{
        startbearerservice();
        start_timerTO_A_bearer(sm->timer, sm->machine_id, default_bearerinit_delay);
	},
	BEARER_WAITING)

ROW(NOTIFYRESPONSE,
	HTTP_Request_Completed_Event,
	http_status_class(e->status) == HTTP_STATUS_SUCCESSFUL,
	{
        /* done */
	},
	NULL_STATE)


ROW(NOTIFYRESPONSE,
	HTTP_Request_Completed_Event,
	http_status_class(e->status) != HTTP_STATUS_SUCCESSFUL,
	{
        sendHttpNotifyResponse(sm->notification->u.NotificationInd.x_mms_transaction_id, 129 /* = Retrieved */, sm);
	},
	NOTIFYRESPONSE)





#undef ROW
#undef STATE_NAME



