#include <sys/param.h>
#include <rpc/rpc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/signal.h>

#include "extnDefn.h"
#include "msgq.h"

extern int      timerMsgQueueId;
extern int      msgQueueId;
extern int      monitorNode;
extern IntArr   pidArr;
int             timerPid = -1;  
int             retVal;
extern int      clntFlag ;


/* 

        register_timer_pid_7()
        -------------------------

                    Arguments:
                        id, process id of the timer process 

These functions are used to register the process id of the timer with
the local coordinator. 
*/                                    

#ifdef NEW_VER_RPC

void* register_timer_pid_7_svc( int* id, struct svc_req* junk)

#else

void* register_timer_pid_7( int* id)

#endif

{
   timerPid = *id;
   return;
}


/*

        broadcast_fail_7( )
        ---------------------

                    Arguments:
                         id, node id of the failed node;

               update last, if last node has failed;
               update MonitorNode, if the monitored node has failed.


This function is used to broadcast the fail intimation to all the other
machines.

*/

#ifdef NEW_VER_RPC

void* broadcast_fail_7_svc( int* id, struct svc_req* junk)

#else

void* broadcast_fail_7( int* id)

#endif

{
    int         i;
    CLIENT*     cl;
    TimerMesg   msg;
    FailureMesg failmsg;
    int         len;
    static struct timeval timeout = {0, 0};

    /* handle node failure */

    globNodeArr.NodeArr_val[*id].NodeId = -2;

    if( *id == globLastIndex - 1) {
        for( i = globLastIndex - 1; i >= 0; i--) {
            if (globNodeArr.NodeArr_val[i].NodeId >= 0)
                break;
        }

        if( i == globMyId) {
            globLastMe = true; 
        }
    }

    failmsg.msubtype = NODEFAILURE;
    failmsg.nodeId = *id;
    len = 2* sizeof(int);
    
    for( i = 0; i < pidArr.IntArr_len; i++) {
        if( pidArr.IntArr_val[i] != -1) {
            failmsg.mtype = pidArr.IntArr_val[i];

            if(msgsnd( msgQueueId, (char *)&failmsg.mtype, len, 0) != 0) {
                PrintInLogFile(" server can't send message queue 1 \n");
            }
        }
    }

    if( *id == monitorNode) {
        for( i = monitorNode ; i < globLastIndex; i++) {
            if( globNodeArr.NodeArr_val[ i].NodeId >= 0) {
                break;
            }
        }
        
        if( i == globLastIndex) {
            for( i = 0; i < monitorNode; i++) {
                if( globNodeArr.NodeArr_val[ i].NodeId >= 0) {
                    break;
                }
            }
        }

        if ( i != globMyId) {
            msg.mtype = timerPid;
            msg.nodeId = i;
            strncpy( msg.ipaddr, globNodeArr.NodeArr_val[i].IPaddress.String_val,
                globNodeArr.NodeArr_val[i].IPaddress.String_len);
            msg.ipaddr[globNodeArr.NodeArr_val[i].IPaddress.String_len] = '\0';
            len = sizeof(int) + globNodeArr.NodeArr_val[i].IPaddress.String_len
                + 1;
            monitorNode = i;
        }
        else {
            msg.mtype = timerPid;
            msg.nodeId = -1;
            strcpy(msg.ipaddr, "SINGLE_NODE");
            len = sizeof(int) + strlen(msg.ipaddr);
            monitorNode = -1;
        }
            
        if(msgsnd( timerMsgQueueId, (char *)&msg.mtype, len, 0) != 0) {
            PrintInLogFile(" server can't send message queue 1 \n");
        }
        kill( timerPid, SIGUSR1);
    }
}

/*

         node_failed_7( )
         -------------------

                    Arguments:
                        nodeId of the failed node;

               update last, if last node has failed;
               update MonitorNode, if the monitored node has failed.


 This function is used by timer process to intimate failure of the node
 it was monitoring to the coordinator.

 */

#ifdef NEW_VER_RPC

void*
node_failed_7_svc( int* nodeId, struct svc_req* junk)

#else

void*
node_failed_7( int* nodeId)

#endif

{
    int         i;
    CLIENT*     cl;
    TimerMesg   msg;
    FailureMesg failmsg;
    int         len;
    static struct timeval timeout = {0, 0};
    
    globNodeArr.NodeArr_val[*nodeId].NodeId = -2;

    if( *nodeId == globLastIndex - 1) {
        for( i = globLastIndex - 1; i >= 0; i--) {
            if (globNodeArr.NodeArr_val[i].NodeId >= 0)
                break;
        }

        if( i == globMyId) {
            globLastMe = true; 
        }
    }

#ifdef PRINT

    PrintInLogFile( " globLastMe = %d ", globMyId);

#endif

    for(i = 0; i < globLastIndex; i++) {
        if ((globNodeArr.NodeArr_val[i].NodeId == globMyId)
            || ( globNodeArr.NodeArr_val[i].NodeId == -1 )
            || ( globNodeArr.NodeArr_val[i].NodeId == -2 )) {

            continue;
        }
    
        if ((cl = clnt_create( globNodeArr.NodeArr_val[i].IPaddress.String_val,
                        COORDINATOR, NODE_FAILURE,"tcp")) == NULL)
        {
            clnt_pcreateerror( globNodeArr.NodeArr_val[i].IPaddress.String_val );
            clntFlag = 0;
            /*
            exit( CLIENT_CONNECTION_FAIL );
            HandleNodeFailure( i);
            */
        }
        
        if(!clntFlag) {
            clntFlag = 1;
            continue;
        }
        clnt_call(cl,BROADCAST_FAIL,xdr_int, &(*nodeId),
                    xdr_void, NULL, timeout); 
    }


    failmsg.msubtype = NODEFAILURE;
    failmsg.nodeId = *nodeId;
    len = 2* sizeof(int);
    
    for( i = 0; i < pidArr.IntArr_len; i++) {
        if( pidArr.IntArr_val[i] != -1) {
            failmsg.mtype = pidArr.IntArr_val[i];
        PrintInLogFile(" sending  failure mesg %d %d %D \n", failmsg.mtype,
                failmsg.msubtype, failmsg.nodeId);

            if(msgsnd( msgQueueId, (char *)&failmsg.mtype, len, 0) != 0) {
                PrintInLogFile(" server can't send message queue 1 \n");
            }
        }
    }
    
    if( *nodeId == monitorNode) {
        for( i = monitorNode + 1; i < globLastIndex; i++) {
            if( globNodeArr.NodeArr_val[ i].NodeId >= 0) {
                break;
            }
        }
        
        if( i == globLastIndex) {
            for( i = 0; i < globMyId; i++) {
                if( globNodeArr.NodeArr_val[ i].NodeId >= 0) {
                    break;
                }
            }
        }

        if ( i != globMyId) {
            msg.mtype = timerPid;
            msg.nodeId = i;
            strncpy( msg.ipaddr, globNodeArr.NodeArr_val[i].IPaddress.String_val,
                globNodeArr.NodeArr_val[i].IPaddress.String_len);
            msg.ipaddr[globNodeArr.NodeArr_val[i].IPaddress.String_len] = '\0';
            len = sizeof(int) + globNodeArr.NodeArr_val[i].IPaddress.String_len
                + 1;
            monitorNode = i;
        }
        else {
            msg.mtype = timerPid;
            msg.nodeId = -1;
            strcpy(msg.ipaddr, "SINGLE_NODE");
            len = sizeof(int) + strlen(msg.ipaddr);
            monitorNode = -1;
        }
            
        if(msgsnd( timerMsgQueueId, (char *)&msg.mtype, len, 0) != 0) {
            PrintInLogFile(" server can't send message queue 1 \n");
        }
        
#ifdef PRINT

PrintInLogFile(" new node to be monitiored %d \n", msg.nodeId);

#endif

        kill( timerPid, SIGUSR1);
    }
}

