#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"

static struct timeval TIMEOUT = { 50, 0 };

int             retVal;
extern int      clntFlag ;
extern int      timerMsgQueueId; 
extern int      msgQueueId; 
extern int      monitorNode;
extern int      timerPid;
extern IntArr   pidArr;


/*

   leave_system_2()
   --------------------
    To be invoked if a node wants to leave the system;
    The request is broadcast to all;

*/    
                    
#ifdef NEW_VER_RPC

void*
leave_system_2_svc(void* junk, struct svc_req *junk1)

#else
    
void*
leave_system_2(void* junk)

#endif
{
    static struct timeval timeout = {25, 0};
    CLIENT* cl;
    int i;

    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, UNSUBSCRIBE,"tcp")) == NULL)
        {
                clnt_pcreateerror(
                   globNodeArr.NodeArr_val[i].IPaddress.String_val );
                clntFlag = 0;
            /*
                exit( CLIENT_CONNECTION_FAIL );
            HandleNodeFailure( i);
            */
        }

        if(!clntFlag)
        {
            clntFlag = 1;
            continue;
        }

        if (clnt_call(cl,BROADCAST_LEAVE,xdr_int, &(globMyId), 
                    xdr_void, NULL, timeout) != RPC_SUCCESS)
        {
                clnt_perror(cl, globNodeArr.NodeArr_val[i].IPaddress.String_val);
                retVal = CLIENT_CONNECTION_FAIL;
                return &retVal;
        }
    }
}

/*

    broadcast_leave_2()
    ---------------------

                Arguments :
                      id of the leaving node;

            Mark deleted from NodeArr;
            update last node id, if leaving node was the last one;
            update MonitorNode, if a  node was monitoring the leaving 
            node;

    This function is used to broadcast the leave request to all the 
    other machines.

 */

#ifdef NEW_VER_RPC

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

#else
    
void*
broadcast_leave_2(int* id)

#endif

{
     int            i;
     CLIENT*        cl;
     int            len;
     TimerMesg      msg;
     FailureMesg    failmsg;

     static struct timeval timeout = {0, 0};

    /* id node has failed : handle */

    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 < 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");
        }
        kill( timerPid, SIGUSR1);
    }
}

