#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <rpc/rpc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include "extnDefn.h"
#include "LockList.h"
#include "LockReqList.h"
#include "../commonIncludes/msgq.h"

//#define PRINT

IntArr              pidArr;
extern int          clntFlag ;

LockArr             tmpLockArr;  
//LocalLockArr        *locksAvailable = NULL;  
LockRequest         lockRequest;
extern LockRequest  lockPerm;
extern LockList*    localLockList;
//LockReqList*        requestedList = NULL;
String              localStr;
extern int          msgQueueId;  
extern long         GetProgNum();
extern void         ExecuteFile();
extern MagicNumber* Calculate_cur_magicnum();

static struct timeval TIMEOUT = { 50, 0 };
int     retVal;
u_long  progNum;
u_long*  progNum1;

int PostFile( String filename, CLIENT* cl);

/*

    post_rib_inf_5()
    ------------------

            Arguments:
                RibInf, info of the RIB to be posted;

       post necessary files;
       invoke process_rib_inf() for starting remote server;

This function is provided to post the RibInf pertaining to an ARC function to
the remote server. If the remote machine has same file system as that of
its own, no files need to be transfered, otherwise source/ executable files
of the ARC function server and other necessary files are posted.

*/

#ifdef NEW_VER_RPC

u_long* post_rib_inf_5_svc(RibInf* ribInf, struct svc_req *junk2)

#else

u_long* post_rib_inf_5(RibInf* ribInf)

#endif

{
    CLIENT* cl;
    int     i;
    int     size;

    //PrintInResult("I am in postrib info................\n");
    if( ribInf->NodeId == globMyId) {
         //PrintInResult("I am executing locally ............\n");
         progNum = GetProgNum();
         PrintInLogFile( "PrgNo.:%x\tRibId :%d \n", progNum,ribInf->NodeId);
         ExecuteFile( ribInf);
         return &progNum;
    }

    if ((cl = clnt_create(globNodeArr.NodeArr_val[ribInf->NodeId].IPaddress.String_val,
                COORDINATOR, SERVER,"tcp")) == NULL) {

        clnt_pcreateerror(
            globNodeArr.NodeArr_val[ribInf->NodeId].Name.String_val );
        PrintInResult("Not able to create client handle for  %s",
                globNodeArr.NodeArr_val[ribInf->NodeId].IPaddress.String_val);

        clntFlag = 0;
    }

    //The client handle could not be created.
    if(!clntFlag) {
        clntFlag = 1;
        progNum = RPC_TIMED_OUT;
        return &progNum;
    }

    ribInf->Files.StrArr_len = 0;

    //If the sender machine has a file system, different from that 
    //of the destination machine.
    if(strcmp(globNodeArr.NodeArr_val[ ribInf->NodeId].FileSys.String_val,
            globNodeArr.NodeArr_val[globMyId].FileSys.String_val)) {

        //If the destination machine has a different architecture than 
        //the architecture of the sender machine.
        if( strcmp(globNodeArr.NodeArr_val[ribInf->NodeId].ArchType.String_val,
                globNodeArr.NodeArr_val[globMyId].ArchType.String_val)) {

            ribInf->Files.StrArr_len = 2;
            ribInf->Files.StrArr_val = (String *)
                            malloc(2 * sizeof(String));
            size = ribInf->FuncName.String_len;

            //ribInf->Files.StrArr_val[0].String_len = size + 7;   //Commented by Ameeeeeeeeet
            ribInf->Files.StrArr_val[0].String_len = size + 3;	//Added by Ameeeeeeeeet
            ribInf->Files.StrArr_val[0].String_val = (char *) malloc(
                ribInf->Files.StrArr_val[0].String_len * sizeof(char));

            //strcpy(ribInf->Files.StrArr_val[0].String_val, "src/"); //Commented by Ameeeeeeeeet
            strcpy(ribInf->Files.StrArr_val[0].String_val, ""); //Added by Ameeeeeeeeet
            strncat(ribInf->Files.StrArr_val[0].String_val,
                    ribInf->FuncName.String_val, size);
            strcat(ribInf->Files.StrArr_val[0].String_val, ".x");
            //ribInf->Files.StrArr_val[0].String_val[size + 6] = '\0'; //Commented by Ameeeeeeeeet
            ribInf->Files.StrArr_val[0].String_val[size + 2] = '\0';	//Added by Ameeeeeeeeet
            //ribInf->Files.StrArr_val[1].String_len = size + 12; //Commented by Ameeeeeeeeet
            ribInf->Files.StrArr_val[1].String_len = size + 8;  //Added by Ameeeeeeeeet
            ribInf->Files.StrArr_val[1].String_val = (char *) malloc(
                ribInf->Files.StrArr_val[1].String_len * sizeof(char));

            //strcpy(ribInf->Files.StrArr_val[1].String_val, "src/"); //Commented by Ameeeeeeeet
            strcpy(ribInf->Files.StrArr_val[1].String_val, ""); //Added by Ameeeeeeeet
            strncat(ribInf->Files.StrArr_val[1].String_val,  
                    ribInf->FuncName.String_val, size);
            strcat(ribInf->Files.StrArr_val[1].String_val, "_proc.c");
            //ribInf->Files.StrArr_val[0].String_val[size + 11] = '\0'; //Commented by Ameeeeeeeet
            ribInf->Files.StrArr_val[0].String_val[size + 7] = '\0'; //Added by Ameeeeeeeet
            //printf("File name ......   %s \n", 
                    //ribInf->Files.StrArr_val[1].String_val);
            //PrintInResult("File name ......   %s \n", 
                    //ribInf->Files.StrArr_val[1].String_val);
        }

            //If the destination machine has a same architecture as that  
            //of the sender machine.
        else {
            ribInf->Files.StrArr_len = 1;
            ribInf->Files.StrArr_val = (String *) malloc( sizeof(String));
            size =  ribInf->FuncName.String_len;

            ribInf->Files.StrArr_val[0].String_len = size + 12;
            ribInf->Files.StrArr_val[0].String_val = (char *) malloc( 
                ribInf->Files.StrArr_val[0].String_len * sizeof(char));

            strcpy(ribInf->Files.StrArr_val[0].String_val, "bin/"); 
            strncat(ribInf->Files.StrArr_val[0].String_val, 
                     ribInf->FuncName.String_val, size);
            strcat(ribInf->Files.StrArr_val[0].String_val, "_svc");
            ribInf->Files.StrArr_val[0].String_val[size + 11] = '\0';
            //printf("File name ......   %s \n", ribInf->Files.StrArr_val[0].String_val);
            //PrintInResult("File name ......   %s \n", ribInf->Files.StrArr_val[0].String_val);
        }
    }

    //PrintInResult("Before postfile ........\n");
    //PrintInResult("rib inf file length %d \n", ribInf->Files.StrArr_len);
    for( i = 0; i < ribInf->Files.StrArr_len; i++) {
        //PrintInResult("Files............. %d\n",ribInf->Files.StrArr_val[i]);
        //PrintInResult(" Dir Name ......... %s......\n",DIRNAME);

        if(PostFile( ribInf->Files.StrArr_val[i], cl) == RPC_TIMED_OUT) {
            progNum = RPC_TIMED_OUT;
            return &progNum;
        }
    }

    ribInf->NodeId = globMyId;

    //PrintInResult(" Before Process RIB .......\n");
    if (clnt_call(cl, PROCESS_RIB , xdr_RibInf,
               (char *)ribInf, xdr_u_long,
               (char *)&progNum, TIMEOUT) != RPC_SUCCESS) {

        PrintInResult("Node to which connection failed ....%s\n",
            globNodeArr.NodeArr_val[ribInf->NodeId].Name.String_val);
        clnt_perror(cl, globNodeArr.NodeArr_val[ribInf->NodeId].Name.String_val);
        progNum = RPC_TIMED_OUT;
        return &progNum;
    }
    return &progNum;
}

/*
        PostFile()
        ----------

                Arguments:
                     String, name of the file to be posted;

This function posts a file to the remote server.

*/

int PostFile( String fileName, CLIENT* cl) {
    FILE    *fptr;
    char    tp[250];
    int     len;
    int     i;
    struct stat ret;

    //PrintInResult("Entering Post File.........\n");
    strcpy(tp, DIRNAME);
    strncat(tp, fileName.String_val, fileName.String_len);
    strcat( tp, "\0");
    //PrintInResult(".........File......... %s ...\n", tp);

    if ((fptr = fopen(tp, "r")) == NULL) {
        error("can't open local file: %s \n", tp);
    }

    if (clnt_call(cl, INIT_FILE_PTR, xdr_String,
            (char *)&fileName, xdr_int, 
            (char *)&retVal, TIMEOUT) != RPC_SUCCESS) {
        //error("can't open remote file: %s \n", tp);     //Commented by Ameeeeeeeeeeet
        error("can't open remote file: %s \n", fileName);

        return RPC_TIMED_OUT;
    }
    stat( tp, &ret);
    len = ret.st_size;
    localStr.String_len = len;
    localStr.String_val = (char *) malloc( len * sizeof(char));
    fread( localStr.String_val, localStr.String_len, 1, fptr);
    //printf("  ..%s..    \n",localStr.String_val);
    //PrintInResult("  ..%s..    \n",localStr.String_val);
    if (clnt_call(cl, PUT_IN_FILE, xdr_String,
            (char *)&localStr, xdr_int, 
            (char *)&retVal, TIMEOUT) != RPC_SUCCESS) {
        error("can't write remote file: %s \n", fileName.String_val);
        return RPC_TIMED_OUT;
    }

    fclose(fptr);

    if (clnt_call(cl, CLOSE_FILE, xdr_String,
                     (char *)&fileName, xdr_int, 
                     (char *)&retVal, TIMEOUT) != RPC_SUCCESS) {
        error("can't close remote file: %s \n", fileName.String_val);
        return RPC_TIMED_OUT;
    }
    PrintInLogFile(" Closing ... \n");
    free(localStr.String_val); 
    return 0;
}

