function application(S)
% ***	
% ***	 Copyright 2006, SUNY Buffalo. All rights reserved.
% ***
% ***    This program is distributed in the hope that it will be useful,
% ***    but WITHOUT ANY WARRANTY; without even the implied warranty of
% ***    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% ***
% ***

% Written by Muzammil Hussain, mh69@cse.buffalo.edu, Initially adapted from ISIS Prowler
% code
% 


% DO NOT edit simulator code (lines that begin with S;)


S; %%%%%%%%%%%%%%%%%%%   housekeeping  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
S;      persistent app_data 
S;      global ID t
S;      [t, event, ID, data]=get_event(S);
S;      [topology, mote_IDs]=prowler('GetTopologyInfo');
S;      ix=find(mote_IDs==ID);
S;      if ~strcmp(event, 'Init_Application') 
S;         try memory=app_data{ix}; catch memory=[]; end, 
S;      end
S; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                                          %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%         APPLICATION STARTS               %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%               HERE                       %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                                          %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv%

global fid;
global array_excited_nodes;

TRUE=1;
FALSE = 0;

%Message types
READ_REQ_MSG = 1;
READ_ANS_MSG = 2;
WRITE_ALL_REQ_MSG = 3;
WRITE_ACK_MSG = 4;
CONFLICT_MSG = 5;
CANCEL_WRITE_MSG = 6;
CANCEL_WRITE_ACK_MSG = 7;

MICA2_PACKET_LENGTH_BYTE = 36; % From BMAC paper

WT_MAX = sim_params('get','MAC_MIN_WAITING_TIME') + sim_params('get','MAC_RAND_WAITING_TIME');
BT_MAX = sim_params('get','MAC_MIN_BACKOFF_TIME') + sim_params('get','MAC_RAND_BACKOFF_TIME');

NO_OF_RETRANSMISSIONS = 12; %>=1 $$$$  if 1 then no retransmissions

%Spacing between message requests

WACK_DELTA = NO_OF_RETRANSMISSIONS*WT_MAX + (NO_OF_RETRANSMISSIONS-1)*BT_MAX + sim_params('get','MAC_PACKET_LENGTH');
READ_REQUEST_SPACING = WACK_DELTA;
CACK_DELTA = WACK_DELTA;

MAX_CANCEL_RETRIES = 3;
WRITE_COMMIT_DELTA = WACK_DELTA + CACK_DELTA*MAX_CANCEL_RETRIES;

SECOND_IN_BIT_TIME = 40000;
PERIOD_CLEANUP_INTERVAL = 2 * SECOND_IN_BIT_TIME;

MAX_NUM_TRANSACTIONS = 1;
% NUM_READ_NEIGHBOURS = 2;
% NUM_WRITE_NEIGHBOURS = 2;

% READ_TIME = READ_REQUEST_SPACING * (NUM_READ_NEIGHBOURS + 2);
% WRITECOMMIT_TIME = WRITE_COMMIT_DELTA * (NUM_WRITE_NEIGHBOURS + 2);
% MAX_TRANSACTION_TIME = READ_TIME + WRITECOMMIT_TIME;

var_name_list = 'a';
var_value_list = 1:length(var_name_list);
VAR_RANGE_LENGTH = length(var_name_list);

SEND_CONFLICT_MSG_PROP = 10;

switch event
case 'Init_Application'
    signal_strength=1;
    %multicast_read_nlist - Neighbour list from which reads have to be done
    
    %variables_to_read - Variable list corresponding to
    %multicast_read_nlist
    
    %multicast_write_nlist - Neighbour list on which writes have to be done
    
    %variables_to_write - Variable list corresponding to
    %multicast_write_nlist
    
    %updating_node - stores the destination ID of updating node to be used
    %when the write ack timer expires ( so that n number of written nodes
    %can send acks one after the other in a sequential manner)
    
    % answering_nodes_index - staructure for storing information of
    % read-answers
    
    %var_to_be_read - list of variables to send the read answers on the
    %expiry of the read answer timer
    
    %cur_TID - transaction ID to be used by the initaor of the transaction
    
    %cur_servicing_TID - transaction ID the node is currently servicing (
    %either a read request or write request)
    
    %snoop_read_table - snooping table for read requests
    %node var tid read_initiator timestamp
    
    %snoop_rwi_table - snooping table for recording RW-W incompatibilities
    %tid1 tid2 node var read_initiator timestamp
    
    %%%%%%%%%%%%%%   Memory should be initialized here  %%%%%%%%%%%%%%%%%
    memory=struct('signal_strength', signal_strength,'multicast_read_nlist',[],'variables_to_read',[],'multicast_write_nlist',[],'variables_to_write',[],'values_to_write',[],'answering_nodes_index',[],'write_acks',[],'var_list',[],'cack_var_ref_list',[],'read_req_ref_struct',[],'cancel_acks',[],'cur_TID',-1,'aborting_transaction_flag',-1,'snoop_read_table',[],'snoop_rwi_table',[],'snoop_commit_timer_queue',[],'read_ans_recvd',-1,'tran_count',-1,'num_tran_max',-1,'num_cancel_msg_resend',-1,'conft_msg_decongestion_struct',[]);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    

    
    array_excited_nodes = sim_params('get_app','ENA');
    
    %array_excited_nodes = [13];

    if ID == 1
        fid = sim_params('get_app','log_file_fid1');
    end
    
    if(isempty(array_excited_nodes)) error(['Error ! No nodes are excited!!!']); end
    
    % Initialize all nodes to have variables a to z
    % Assign values from  1 to 24 for each

    memory = SetUpVariables(memory,var_name_list,var_value_list*ID);
    Set_Periodic_Cleanup_Alarm_Timer(t + PERIOD_CLEANUP_INTERVAL);

    memory.cur_servicing_TID = -1;
    
    if(~isempty(find(array_excited_nodes == ID)))
        memory.num_tran_max = MAX_NUM_TRANSACTIONS;

        memory.tran_count = 1;
        %Initialzing the TID for the new transaction
        memory.cur_TID = str2num(strcat(num2str(ID),num2str(t)));
        disp1(sprintf('%d:%d: Starting new transaction %d with TID : %d',ID,t, memory.tran_count, memory.cur_TID)); 

        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
        fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'START');
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

        grid_size =  sim_params('get','GRID_SQUARE_SIZE_LENGTH');
        memory.neigh_list = GetNeighbours(ID, grid_size);
        memory = DecideReadWriteNeighbours(ID,memory);
        
        %In case it is a read-write thread structure
        if ~isempty(memory.multicast_read_nlist)
            %Send the read request
            memory=SendReadReq(ID,t,memory,READ_REQ_MSG,READ_REQUEST_SPACING,fid);
        else
            %Send the write request
            %Write values of the own same name variables to neighbours
            memory.values_to_write = [];
            for i = 1:length(memory.multicast_write_nlist)
                for j = 1:length(memory.var_list)
                    if memory.variables_to_write(i) == memory.var_list(j).name
                        memory.values_to_write(i) = memory.var_list(j).value;
                    end
                end
            end
            memory=SendWriteReq(ID,t,memory,WRITE_ALL_REQ_MSG,WACK_DELTA,fid);
        end
    end


case 'Packet_Sent'

case 'Packet_Received'
    LED('red off');
    LED('green on');
    msg=data.data;
    switch msg.type
        case READ_REQ_MSG
            % Check if the receiving node should service a read request
            if ~(isempty(find(msg.read_nlist == ID)))
                index = find(msg.read_nlist == ID);
                %disp1(sprintf('%d:%d: Index in the read request : %d',ID,t,index));
                %disp1(sprintf('%d:%d: Servicing read request for transaction %d from node %d for variable %c',ID,t,msg.TID,msg.ID,msg.var_to_be_read(index)));
                new_i = length(memory.read_req_ref_struct) + 1;
                memory.read_req_ref_struct(new_i).requesting_node = msg.ID;
                memory.read_req_ref_struct(new_i).requesting_tid = msg.TID;
                memory.read_req_ref_struct(new_i).requested_variable = msg.var_to_be_read(index);
                memory.read_req_ref_struct(new_i).read_ans_exp_time = t + READ_REQUEST_SPACING*(index-1);
		        Set_Alarm_Send_Read_Request_Timer(t + READ_REQUEST_SPACING*(index-1));
            end

            %I am snooping he he he !!!
            %disp1(sprintf('%d:%d: SNOOPING ! read request for transaction %d from node %d : %d',ID,t,msg.TID,msg.ID));

            %Chk if there is a write on that variable for that node
            msg_varl_len = length(msg.var_to_be_read);

            %for each variable to be read in the list
            %read_nlist : array of integers
            %var_to_be_read : array of variable name characters
            memory=GotReadReqAddToReadTable(ID,t,memory,msg.TID,msg.ID,msg.read_nlist,msg.var_to_be_read);
                        
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case READ_REQ_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case READ_ANS_MSG
            % If the reply is indeed from one of the requested nodes
            % for that particular transaction
            %disp1(sprintf('%d:%d: Got Read answer!!!',ID,t));
            prev_read_answers_not_recvd = FALSE;
            
            if msg.dest_id == ID && ~(isempty(find(memory.multicast_read_nlist == msg.ID))) %&& msg.TID == memory.cur_TID
                index = find(memory.multicast_read_nlist == msg.ID);
                %disp1(sprintf('%d:%d: Received answer whose Index in the read request : %d',ID,t,index));
                % Check if it has come in the right order as specified in
                % the read request
                for i = 1:index-1    
                    if memory.answering_nodes_index(i).flag == inf
                        prev_read_answers_not_recvd = TRUE;
                    end
                end

                if memory.answering_nodes_index(index).flag ~= inf
                    error(['%d trying to overwrite' msg.ID])
                end

                % Record the answer
                disp1(sprintf('%d:%d Recording answer from node %d',ID,t,msg.ID));
                memory.answering_nodes_index(index).name = msg.variable_names;
                memory.answering_nodes_index(index).value = msg.variable_values;
                memory.answering_nodes_index(index).flag = 1;

                %In case all requested nodes have replied send the
                %writeall
                if index == length(memory.multicast_read_nlist) && (prev_read_answers_not_recvd == FALSE)
                    memory.read_ans_recvd = 1;
                    PrintMessage('WR ALL');
                    
                    read_answers = [];
                    for i = 1:length(memory.answering_nodes_index)
                        read_answers(i)= memory.answering_nodes_index(i).value;
                    end

                    result=ApplyTranformation(read_answers,'PRODUCT');
                    %Set each variable in the neighbor list to be
                    %written the same value
                    memory.values_to_write = [];
                    for i=1:length(memory.multicast_write_nlist)
                        memory.values_to_write(i) = result;
                    end

                    %Send the write req
                    memory=SendWriteReq(ID,t,memory,WRITE_ALL_REQ_MSG,WACK_DELTA,fid);
                end
            end

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case READ_ANS_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case WRITE_ALL_REQ_MSG
            if ~(isempty(find(msg.write_nlist == ID))) 
                index = find(msg.write_nlist == ID);

                for i=1:length(memory.var_list)
                    if memory.var_list(i).name == msg.variables_to_write(index)
                        memory.var_list(i).new_value = [memory.var_list(i).new_value msg.values_to_write(index)];
                        disp1(sprintf('%d:%d: Updating variable %c to new value %d supplied by %d for transaction %d',ID,t,memory.var_list(i).name,memory.var_list(i).new_value(end),msg.ID,msg.TID));

                        %Write to the designated variable
                        Set_Write_Commit_Timer(t + length(msg.write_nlist)*WRITE_COMMIT_DELTA);
                        memory.var_list(i).commit_time = [memory.var_list(i).commit_time (t + length(msg.write_nlist)*WRITE_COMMIT_DELTA)];
                        memory.var_list(i).updating_tid = [memory.var_list(i).updating_tid msg.TID];
                        memory.var_list(i).updating_node = [memory.var_list(i).updating_node msg.ID];

                        %memory.aborting_transaction_flag = FALSE;
                        
                        %Send the ACK in the order of position in the write list
                        index = find(msg.write_nlist == ID);    
                        Set_Alarm_Send_Write_All_Ack_Timer(t + WACK_DELTA*(index-1));   
			            memory.var_list(i).w_ack_send_time = [memory.var_list(i).w_ack_send_time t + WACK_DELTA*(index-1)];
                    
            			break;
                    end
                end
                % Even the servcing node also snoops at its own service
                %disp1(sprintf('%d: I am also snooping he he he !!!'));
            end

            % I am snooping he he he !!!!
            %disp1(sprintf('%d: SNOOPING ! write request for transaction %d from node %d : %d',ID,msg.TID,msg.ID));

            %Chk if there is a write on that variable for that node
            %msg_varl_len = length(msg.values_to_write);

            %for each variable to be read in the list
            memory=GotWriteReqCheckingForConflict(ID,t,memory,msg.TID,msg.ID,msg.write_nlist,msg.variables_to_write,WRITE_COMMIT_DELTA,WACK_DELTA,fid,SEND_CONFLICT_MSG_PROP);

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case WRITE_ALL_REQ_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case WRITE_ACK_MSG
            if msg.dest_id == ID
              if isempty(find(memory.multicast_write_nlist == msg.ID))
                error(['Recived ack from node %d who I did not asked to write' msg.ID])
              end

              index = find(memory.multicast_write_nlist == msg.ID);
              %disp1(sprintf('%d: Index in the write ack : %d',ID,index));

              %To ensure that the written nodes answer in the order
              %specified in the write-all message
              for i = 1:index-1    
                  if memory.write_acks(i) == inf
                     % disp1(sprintf('%d: Received out of turn write ack from %d when %d has not yet replied %d',ID,msg.ID,memory.multicast_write_nlist(i)));
                  %    error(['Out of turn read answer received from : ' msg.ID])
                  end
              end

              %Mark that the ack has been received from the node
              %(index)
              memory.write_acks(index) = 1;
              disp1(sprintf('%d:%d: Received ack from %d',ID,t,msg.ID));

              if index == length(memory.write_acks) && isempty(find(memory.write_acks == inf))
                PrintMessage('END'); 
                disp1(sprintf('%d:%d: Received acks from all',ID,t));
                %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
                fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'END');
                %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
                num_finished_nodes = sim_params('get_app','num_finished_nodes');
                num_finished_nodes = num_finished_nodes + 1;
                sim_params('set_app','num_finished_nodes',num_finished_nodes);
              end
            end

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case WRITE_ACK_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case CONFLICT_MSG
            %In case msg is for you, cancel the transaction
            if msg.initiator_node == ID 
                % Assert that the aborted transaction is my current
                % transaction

                if memory.aborting_transaction_flag ~= 1
                    if msg.TID ~= memory.cur_TID
                        error(['Conflicting transaction %d does not match my current transaction id %d' msg.TID,memory.cur_TID])
                    end

                    disp1(sprintf('%d:%d: Received CONFLICT msg',ID,t));

                    %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
                    fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'CONFLICT-CANCEL');
                    %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

                    disp1(sprintf('%d:%d: Aborting transaction %d : canceling writes ',ID,t, memory.cur_TID));
                    memory.aborting_transaction_flag = TRUE;
                    PrintMessage('CNCL REQ');
                    Send_Packet(radiostream(struct('ID',ID, 'type',CANCEL_WRITE_MSG,'aborted_tid',msg.TID,'multicast_nlist',memory.multicast_write_nlist),memory.signal_strength));        
                    Set_Alarm_Receive_Cancel_Ack_Timer(t + (length(memory.multicast_write_nlist) + 1)*CACK_DELTA);                    
                    
                    memory.cancel_acks = [];
                    for i=1:length(memory.multicast_write_nlist)
                        memory.cancel_acks = [memory.cancel_acks inf];
                    end
            
                    %Clean own snoop tables 
                    %disp1(sprintf('%d:%d: Cleaning, from the snoop tables, the aborting transaction %d ',ID,t, msg.TID));
                    memory=CleanupTidAfterConflict(ID, memory,memory.cur_TID);
                else
                    disp1(sprintf('%d:%d: Transaction abortion already in progress',ID,t));
                end
            else
            %Else if just a snooper clean snooping tables from the
            %aborted transaction
               % disp1(sprintf('%d:%d: Cleaning, from the snoop tables, the aborting transaction %d ',ID,t, msg.TID));
               
               %Check if another snooper has sent the conflcit msg before
               %me
               for i = 1:length(memory.conft_msg_decongestion_struct)
                if msg.TID == memory.conft_msg_decongestion_struct(i).tid
                    memory.conft_msg_decongestion_struct(i).cmsg_already_sent_flag = TRUE;
                end
               end
               
               memory=CleanupTidAfterConflict(ID, memory,msg.TID);
            end

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case CONFLICT_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case CANCEL_WRITE_MSG
            %Chk if the msg is intended for you
            if ~isempty(find(msg.multicast_nlist == ID))
                %Scan through the commit times 
                for i= 1:length(memory.var_list)
                    %Check if that particular variable is involved in the
                    %cancelled transaction
                    index1 = find(memory.var_list(i).updating_node == msg.ID);
                    if ~isempty(index1)
                        % Discard the new value and reset everything else
                        disp1(sprintf('%d:%d: Discarding new value for %c as commanded by %d',ID,t,memory.var_list(i).name,msg.ID));
                        
                        %% Assert that index is of length 1
%                         if length(index) ~= 1
%                            error(['Error length of index is not 1'])
%                         end
                        
                        memory.var_list(i).new_value(index1) = inf;
                        memory.var_list(i).updating_tid(index1) = -1;
                    end
                end

                index2 = find(msg.multicast_nlist == ID);
                %disp1(sprintf('%d:%d: Index in the write cancel request : %d',ID,t,index));
                Set_Alarm_Send_Cancel_Ack_Timer(t + CACK_DELTA*(index2-1));  

                %Add information to the cack_var_ref_list
                new_i = length(memory.cack_var_ref_list) + 1;
                memory.cack_var_ref_list(new_i).requesting_node = msg.ID;
                memory.cack_var_ref_list(new_i).aborted_tid = msg.aborted_tid;
                memory.cack_var_ref_list(new_i).c_ack_send_time = t + CACK_DELTA*(index2-1);
            end

            memory=CleanupTidAfterConflict(ID, memory,msg.aborted_tid);

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case CANCEL_WRITE_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        case CANCEL_WRITE_ACK_MSG
            if msg.dest_id == ID
              if isempty(find(memory.multicast_write_nlist == msg.ID))
                error(['Recived cancel ack from node %d who I did not asked to write' msg.ID])
              end

              index = find(memory.multicast_write_nlist == msg.ID);
           %   disp1(sprintf('%d:%d: Index in the cancel ack : %d',ID,t,index));

              %To ensure that the written nodes answer in the order
              %specified in the write-all message
              for i = 1:index-1    
                  if memory.cancel_acks(i) == inf
                      disp1(sprintf('%d:%d: Received out of turn cancel ack from %d when %d has not yet replied %d',ID,t,msg.ID,memory.multicast_write_nlist(i)));
                     % error(['Out of turn read answer received from : ' msg.ID])
                  end
              end

              %Mark that the ack has been received from the node
              %(index)
              memory.cancel_acks(index) = 1;
              disp1(sprintf('%d:%d: Received cancel ack from %d',ID,t,msg.ID));
            end
            
            %Check if I can use this ACK to cancel my transaction
            for i= 1:length(memory.var_list)
                %Check if that particular variable is involved in the
                %cancelled transaction
                index1 = find(memory.var_list(i).updating_node == msg.dest_id); %Assumming that the tid is tied to one ID
                if ~isempty(index1)
                    %Invalidate updates but do not send CACK
                    memory.var_list(i).new_value(index1) = inf;
                    memory.var_list(i).updating_tid(index1) = -1;
                end
            end
            
            %Remove from snoop tables
            memory=CleanupTidAfterConflict(ID, memory,msg.aborted_tid);
            
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%case CANCEL_WRITE_ACK_MSG%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
        otherwise
            error(['Bad msg type received: ' msg.type])
    end
case 'Collided_Packet_Received'
    disp1(sprintf('%d:%d: Received collided packet !!',ID,t));
    LED('red on');
    LED('green off')
    
case 'Send_Read_Answer_Timer_Expired'
    % Send the values of the variables as ordered in memory.read_requested_variables
    disp1(sprintf('%d:%d: Read Answer Timer Expired !!!',ID,t));
    
    index = -1;
    for i = 1:length(memory.read_req_ref_struct)
        if memory.read_req_ref_struct(i).read_ans_exp_time == t
            index = i;
            break;
        end
    end
    
    found = FALSE;
    for i=1:length(memory.var_list)
        if memory.var_list(i).name == memory.read_req_ref_struct(index).requested_variable
            disp1(sprintf('%d:%d: Reading variable %c which gives value %d',ID,t,memory.var_list(i).name,memory.var_list(i).value));
            PrintMessage('R ANS');
            Send_Packet(radiostream(struct('ID',ID, 'type',READ_ANS_MSG,'dest_id',memory.read_req_ref_struct(index).requesting_node,'TID',memory.read_req_ref_struct(index).requesting_tid,'variable_names',memory.var_list(i).name,'variable_values',memory.var_list(i).value),memory.signal_strength));
            disp1(sprintf('%d:%d: Sending answer to %d for transaction %d',ID,t,memory.read_req_ref_struct(index).requesting_node,memory.read_req_ref_struct(index).requesting_tid));
            found = TRUE;
            %Remove the head
            memory.read_req_ref_struct(index) = [];
            break;
        end
    end
        
    if found == FALSE
        error(['Error ! Read request variable does not exist in node'])
    end

    
case 'Receive_Read_Answers_Timer_Expired'
    if memory.read_ans_recvd == 0
        disp1(sprintf('%d:%d: Read Request timing out !!!',ID,t));
        disp1(sprintf('%d:%d: Canceling transaction %d !!!',ID,t,memory.cur_TID));
        
        PrintMessage('CNCL R');

        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
        fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'TIMEOUT-CANCEL');
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%        

        memory.cur_TID = str2num(strcat(num2str(ID),num2str(t)));
        disp1(sprintf('%d:%d: Starting %d new transaction with TID : %d',ID,t, memory.tran_count, memory.cur_TID));
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
        fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'START');
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

        memory=SendReadReq(ID,t,memory,READ_REQ_MSG,READ_REQUEST_SPACING,fid);
    end
%     else
%         disp1(sprintf('%d:%d: Ignoring Read Answer Timer',ID,t));
%     end
        
    
case 'Write_Commit_Timer_Expired'
    %  disp1(sprintf('%d: Write Commit Timer Expired at %d',ID,t));
    % Commit the the values of variable written into the sandbox
    for i = 1:length(memory.var_list)
        % Check if the variable is to be commited at time t and commit
        % in case it should be commited at time t 
        if memory.var_list(i).commit_time(1) <= t
           if memory.var_list(i).new_value(1) ~= inf
               %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
               fprintf(fid, '%d:%d:%s\n',memory.var_list(i).updating_tid(1),t,'COMMIT');
               %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
               disp1(sprintf('%d:%d: Commiting %d in variable %c at time %d for transaction %d',ID,t,memory.var_list(i).new_value(1),memory.var_list(i).name,t,memory.var_list(i).updating_tid(1)));
               memory.var_list(i).value = memory.var_list(i).new_value(1);
           else
               disp1(sprintf('%d:%d: Ignoring the write commit timer as the write has been cancelled',ID,t));
           end

           %Remove the  head entry
           memory.var_list(i).new_value(1) = [];
           memory.var_list(i).updating_tid(1) = [];
           memory.var_list(i).commit_time(1) = [];
           memory.var_list(i).updating_node(1) = [];
           memory.var_list(i).w_ack_send_time(1) = [];
        else
            disp1(sprintf('%d:%d: %c commit time %d current time %d',ID,t, memory.var_list(i).name,memory.var_list(i).commit_time(1), t));
        end
    end

case 'Receive_Write_All_Ack_Timer_Expired'
    %Check if it has received acks from all the members in the
    %multicast_write_nlist (by searching for a ack not yet come)
    if ~(isempty(find(memory.write_acks == inf))) 
     %   disp1(sprintf('%d:%d: Receive write ack timer expired !!!',ID,t));
        %Cancel the entire transaction as at least one node has not acked
        %the write_all message
        if memory.aborting_transaction_flag == FALSE
            disp1(sprintf('%d:%d: Write Ack Timer Expired !!! Canceling transaction %d !',ID,t,memory.cur_TID));
            memory.aborting_transaction_flag = TRUE;
            memory.num_cancel_msg_resend = memory.num_cancel_msg_resend + 1;
            PrintMessage('CNCL');
            Send_Packet(radiostream(struct('ID',ID, 'type',CANCEL_WRITE_MSG,'aborted_tid',memory.cur_TID,'multicast_nlist',memory.multicast_write_nlist),memory.signal_strength));        
            memory.aborting_transaction_flag = TRUE;
            
            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
            fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'TIMEOUT-CANCEL');
            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
            
            memory.cancel_acks = [];
            for i=1:length(memory.multicast_write_nlist)
                memory.cancel_acks = [memory.cancel_acks inf];
            end

            Set_Alarm_Receive_Cancel_Ack_Timer(t + (length(memory.multicast_write_nlist) + 1)*CACK_DELTA);
            
            % Clean up in self snoop tables
            memory=CleanupTidAfterConflict(ID, memory,memory.cur_TID);
        else
            disp1(sprintf('%d:%d: Transaction abortion already in progress',ID,t));
        end
    else
        disp1(sprintf('%d: Transaction %d completes at time %d',ID,memory.cur_TID,t));
        %start new transaction thread 
        if memory.tran_count < memory.num_tran_max
            memory.tran_count = memory.tran_count + 1;

            %Initialzing the TID for the new transaction
            memory.cur_TID = str2num(strcat(num2str(ID),num2str(t)));
            disp1(sprintf('%d:%d: Starting %d new transaction with TID : %d',ID,t, memory.tran_count, memory.cur_TID));
            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
            fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'START');
            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
            memory = DecideReadWriteNeighbours(ID,memory);
            %In case it is a read-write thread structure
            if ~isempty(memory.multicast_read_nlist)
                %Send the read request
                memory=SendReadReq(ID,t,memory,READ_REQ_MSG,READ_REQUEST_SPACING,fid);
            else
                %Write values of the own same name variables to neighbours
                values_to_write = [];
                for i = 1:length(memory.multicast_write_nlist)
                    for j = 1:length(memory.var_list)
                        if memory.variables_to_write(i) == memory.var_list(j).name
                            memory.values_to_write(i) = memory.var_list(j).value;
                        end
                    end
                end                
                %Send the write request
                memory=SendWriteReq(ID,t,memory,WRITE_ALL_REQ_MSG,WACK_DELTA,fid);
            end
        end        
        
    end
    %Else ignore the timer

case 'Send_Write_All_Ack_Timer_Expired'
    disp1(sprintf('%d:%d: Send write ack timer expired !!!',ID,t));
    for i = 1:length(memory.var_list)
        index = find(memory.var_list(i).w_ack_send_time == t);

        if ~isempty(index)
            PrintMessage('W ACK');
            disp1(sprintf('%d:%d: Sending write ack to %d',ID,t,memory.var_list(i).updating_node(index)));
            Send_Packet(radiostream(struct('ID',ID, 'type',WRITE_ACK_MSG,'dest_id',memory.var_list(i).updating_node(index)),memory.signal_strength));    
            break;
        end
    end
    
case 'Send_Cancel_Ack_Timer_Expired'
    for i = 1:length(memory.cack_var_ref_list)
        if(memory.cack_var_ref_list(i).c_ack_send_time == t)
            PrintMessage('CACK');
            disp1(sprintf('%d:%d: Sending cancel ack to %d',ID,t,memory.cack_var_ref_list(i).requesting_node));
            Send_Packet(radiostream(struct('ID',ID, 'type',CANCEL_WRITE_ACK_MSG,'dest_id',memory.cack_var_ref_list(i).requesting_node,'aborted_tid',memory.cack_var_ref_list(i).aborted_tid),memory.signal_strength));             
            break;
        end
    end
    memory.cack_var_ref_list(i) = [];
    
    
case 'Receive_Cancel_Ack_Timer_Expired'
    %Check if it has received cancel acks from all the members in the
    %multicast_write_nlist (by searching for a cancel ack not yet come)
    if memory.num_cancel_msg_resend < MAX_CANCEL_RETRIES && ~(isempty(find(memory.cancel_acks == inf)))
        disp1(sprintf('%d:%d: Receive cancel ack timer expired !!!',ID,t));
        %Resend the cancel message again when at least one node has not acked
        %the cancel message
        memory.num_cancel_msg_resend = memory.num_cancel_msg_resend + 1;
        disp1(sprintf('%d:%d: Resending the cancel message !!!',ID,t));
        PrintMessage('CNCL');
        Send_Packet(radiostream(struct('ID',ID, 'type',CANCEL_WRITE_MSG,'aborted_tid',memory.cur_TID,'multicast_nlist',memory.multicast_write_nlist),memory.signal_strength));        
        Set_Alarm_Receive_Cancel_Ack_Timer(t + (length(memory.multicast_write_nlist) + 1)*CACK_DELTA);
        
        memory.cancel_acks = [];
        for i=1:length(memory.multicast_write_nlist)
            memory.cancel_acks = [memory.cancel_acks inf];
        end        
    else
        %Start the congestion control timer of 0,1,2
        r= rand023();
        disp1(sprintf('%d:%d: Postponing transaction by %d times',ID,t,r));

        rtime = READ_REQUEST_SPACING * (length(memory.multicast_read_nlist) + 2);
        wctime = WRITE_COMMIT_DELTA * (length(memory.multicast_write_nlist) + 2);
        max_transaction_time = rtime + wctime;
        Set_Congestion_Transaction_Backoff_Timer(t + (r*max_transaction_time));        
    end
    %Else ignore the timer

case 'Congestion_Transaction_Backoff_Timer_Expired'
        %start new transaction thread 
        disp1(sprintf('%d:%d: Starting back after backoff',ID,t));
        %Initialzing the TID for the new transaction
        memory.cur_TID = str2num(strcat(num2str(ID),num2str(t)));
        disp1(sprintf('%d:%d: Starting new transaction %d with TID : %d to do the same',ID,t, memory.tran_count, memory.cur_TID));
        
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
        fprintf(fid, '%d:%d:%s\n', memory.cur_TID,t,'START');
        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
        
        %In case it is a read-write thread structure
        if ~isempty(memory.multicast_read_nlist)
            %Send the read request
            memory=SendReadReq(ID,t,memory,READ_REQ_MSG,READ_REQUEST_SPACING,fid);
        else
            %Send the write request
            %Write values of the own same name variables to neighbours
            values_to_write = [];
            for i = 1:length(memory.multicast_write_nlist)
                for j = 1:length(memory.var_list)
                    if memory.variables_to_write(i) == memory.var_list(j).name
                        memory.values_to_write(i) = memory.var_list(j).value;
                    end
                end
            end

            %Send the write request
            memory=SendWriteReq(ID,t,memory,WRITE_ALL_REQ_MSG,WACK_DELTA,fid);
        end

case 'Snoop_Commit_Timer_Expired'
    disp1(sprintf('%d:%d: Snoop Commit Timer has expired for write of %d !',ID,t, memory.snoop_commit_timer_queue(1).tid));
    %Repeat this procedure to take care to conflicting reads after a write
    %has come
    
    % In case the timer is for a aborted TID ignore it.
    if memory.snoop_commit_timer_queue(1).tid ~= inf
    
        % For each write in the writeall request check if rw-w conflict can be framed
        for i = 1:length(memory.snoop_commit_timer_queue(1).node_being_written_list)
            %In case the write conflicts with the read
            for j = 1: length(memory.snoop_read_table)
                if memory.snoop_read_table(j).node == memory.snoop_commit_timer_queue(1).node_being_written_list(i) && memory.snoop_read_table(j).var == memory.snoop_commit_timer_queue(1).var_being_written_list(i) && ChkDuplRWIEntry(ID,memory,memory.snoop_read_table(j).node,memory.snoop_read_table(j).var,memory.snoop_read_table(j).tid,memory.snoop_commit_timer_queue(1).tid) == FALSE
                    disp1(sprintf('%d:%d: READ AFTER WRITE ! RW incompatibility found between %d and %d for variable %c at node %d',ID,t, memory.snoop_read_table(j).tid, memory.snoop_commit_timer_queue(1).tid,memory.snoop_commit_timer_queue(1).var_being_written_list(i),memory.snoop_commit_timer_queue(1).node_being_written_list(i)));
                    % Add all other entries in the write msg as rw-w in the
                    % snoop_rwi_table
                     for k = 1:length(memory.snoop_commit_timer_queue(1).node_being_written_list)
                         %Skip in case k = i
                         if k == i
                             continue;
                         end

                         %Insert in the end.
                         new_z = length(memory.snoop_rwi_table) + 1;
                         memory.snoop_rwi_table(new_z).tid1 = memory.snoop_read_table(j).tid;
                         memory.snoop_rwi_table(new_z).tid2 = memory.snoop_commit_timer_queue(1).tid;
                         memory.snoop_rwi_table(new_z).node = memory.snoop_commit_timer_queue(1).node_being_written_list(k);
                         memory.snoop_rwi_table(new_z).var = memory.snoop_commit_timer_queue(1).var_being_written_list(k);
                         memory.snoop_rwi_table(new_z).read_initiator = memory.snoop_read_table(j).initiator_node;
                         memory.snoop_rwi_table(new_z).timestamp = t;
                        
                         %Display snoop tables
                       %  DisplaySnoopReadTable(ID,memory);
                      %   DisplaySnoopRWITable(ID,memory);
                     end
                end
            end
        end

        % Clear all read request and rwi table entries bearing that TID 
        % check only for tid1 in case of rwi table
        memory = CleanupTidAfterCommit(ID,memory,memory.snoop_commit_timer_queue(1).tid);

    else
        disp1(sprintf('%d:%d: Ignoring snoop commit timer expiry for aborted transaction %d',ID,t, memory.snoop_commit_timer_queue(1).tid));
    end %memory.snoop_commit_timer_queue(1).tid ~= inf
    
    % Pop off the tid from the commit timer queue
    memory.snoop_commit_timer_queue(1) = [];
    
    %Display snoop tables
 %   DisplaySnoopReadTable(ID,memory);
 %   DisplaySnoopRWITable(ID,memory);
case 'Send_Conflict_Msg_Timer_Expired'
    %Scan the structure to chk if I have to send it
    if memory.conft_msg_decongestion_struct(1).cmsg_already_sent_flag == FALSE
        disp1(sprintf('%d:%d: Sending CONFLCT message before any other snooper does for tid %d',ID,t,memory.conft_msg_decongestion_struct(1).tid));
        PrintMessage('CNFLT');
        Send_Packet(radiostream(struct('ID',ID, 'type',CONFLICT_MSG,'TID',memory.conft_msg_decongestion_struct(1).tid,'initiator_node',memory.conft_msg_decongestion_struct(1).initiator_node),memory.signal_strength));        
    else
        disp1(sprintf('%d:%d: Ignoring to send CONFLCT message for tid %d',ID,t,memory.conft_msg_decongestion_struct(1).tid));
    end

    memory.conft_msg_decongestion_struct(1) = [];
    
case 'Periodic_Cleanup_Timer_Expired'
    
%     disp1(sprintf('%d:%d: Periodic Snoop Table Cleanup Timer Expired',ID));
%     disp1(sprintf('%d:%d: Cleaning entries 2 or more minutes older',ID));
    
    %since this is a dynamically reducing array : 
    %* scan array for value, 
    %* if found delete from array, 
    %   scan all over again with the new reduced array

    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(memory.snoop_read_table)
            if memory.snoop_read_table(i).timestamp <= (t - PERIOD_CLEANUP_INTERVAL)
                memory.snoop_read_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end

    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(memory.snoop_rwi_table)
            if memory.snoop_rwi_table(i).timestamp <= (t - PERIOD_CLEANUP_INTERVAL)
                memory.snoop_rwi_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end
    
    %Display snoop tables
%     DisplaySnoopReadTable(ID,memory);
%     DisplaySnoopRWITable(ID,memory);

    % Restart the cleanup timer
    Set_Periodic_Cleanup_Alarm_Timer(t + PERIOD_CLEANUP_INTERVAL);
    
case 'GuiInfoRequest'
    if ~isempty(memory)
        disp1(sprintf('Memory Dump of mote ID# %d:\n',ID)); disp1(memory)
    else
        disp1(sprintf('No memory dump available for node %d.\n',ID)); 
    end
    
case 'Application_Stopped'
   % this event is called when simulation is stopped/suspended 
   
case 'Application_Finished'
   % this event is called when simulation is finished 
    
otherwise
    error(['Bad event name for application: ' event])
end

%^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                                          %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%         APPLICATION ENDS                 %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%               HERE                       %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                                          %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
    S; %%%%%%%%%%%%%%%%%%%%%% housekeeping %%%%%%%%%%%%%%%%%%%%%%%%%%%
S;        app_data{ix}=memory;
S; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%        COMMANDS           %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function b=Send_Packet(data);
global ID t
radio=prowler('GetRadioName');
b=feval(radio, 'Send_Packet', ID, data, t);

function b=Set_Alarm_Send_Read_Request_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Send_Read_Answer_Timer_Expired', ID));

function b=Set_Alarm_Receive_Read_Answers_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Receive_Read_Answers_Timer_Expired', ID));

function b=Set_Receive_Write_All_Ack_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Receive_Write_All_Ack_Timer_Expired', ID));

function b=Set_Alarm_Send_Write_All_Ack_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Send_Write_All_Ack_Timer_Expired', ID));

function b=Set_Alarm_Send_Cancel_Ack_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Send_Cancel_Ack_Timer_Expired', ID));

function b=Set_Alarm_Receive_Cancel_Ack_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Receive_Cancel_Ack_Timer_Expired', ID));

function b=Set_Write_Commit_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Write_Commit_Timer_Expired', ID));

function b=Set_Misc_Alarm_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Misc_Alarm_Expired', ID));

function b=Set_Snoop_Commit_Alarm_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Snoop_Commit_Timer_Expired', ID));

function b=Set_Snoop_Extended_Commit_Alarm_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Snoop_Extended_Commit_Timer_Expired', ID));

function b=Set_Periodic_Cleanup_Alarm_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Periodic_Cleanup_Timer_Expired', ID));

function b=Set_Send_Conflict_Msg_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Send_Conflict_Msg_Timer_Expired', ID));

function b=Set_Congestion_Transaction_Backoff_Timer(alarm_time);
global ID
prowler('InsertEvents2Q', make_event(alarm_time, 'Congestion_Transaction_Backoff_Timer_Expired', ID));


function PrintMessage(msg)
global ID
prowler('TextMessage', ID, msg)

function LED(msg)
global ID
prowler('LED', ID, msg)

function DrawLine(command, varargin)
switch lower(command)
case 'line'
    prowler('DrawLine', varargin{:})
case 'arrow'
    prowler('DrawArrow', varargin{:})
case 'delete'
    prowler('DrawDelete', varargin{:})
otherwise
    error('Bad command for DrawLine.')
end

function array =GetRandomArray(n,max)
    count = 1;
    array = [];
    while(count<n+1)
      x = ceil(max*rand);
      if isempty(find(array == x))
        array(count) = x;
        count = count + 1;
      end
    end
    
%x is the number of randomly chosen nodes needed
%N is the side of the N*N grid
%For example (5,5) would return an array of 5 randomly chosen nodes from a
%square grid of 25 nodes
function array = GetNeighbours(x,N)
    array = [];
    left = x - N;
    right = x + N;
    % Add the left neighbour if possible
    if(left >= 1)
        array = [array left];
    end
    % Add the right neighbour if possible
    if(right <= N*N)
        array = [array right];
    end
    
    %Add the northern/sourthern neighbour
    if( mod(x, N) == 0)
        array = [array x-1]; % Add southern neighbour if x is topmost
    elseif(mod(x, N) == 1)
        array = [array x+1];
    else
        array = [array x-1 x+1];
    end
    
    if(left >= 1)
        %Add the northern/sourthern neighbour of left
        if( mod(left, N) == 0)
            array = [array left-1]; % Add southern neighbour if x is topmost
        elseif(mod(left,N) == 1)
            array = [array left+1];
        else
            array = [array left-1 left+1];
        end
    end 
    
    if(right <= N*N)
        %Add the northern/sourthern neighbour of right
        if( mod(right,N) == 0)
            array = [array right-1]; % Add southern neighbour if x is topmost
        elseif(mod(right,N) == 1)
            array = [array right+1];
        else
            array = [array right-1 right+1];
        end
    end     
    array = sort(array);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function mem=SetUpVariables(mem,name_list,value_list)
    len = length(name_list);
    for i = 1 : len
        mem.var_list(i).name = name_list(i);
        mem.var_list(i).value = value_list(i);
        mem.var_list(i).new_value = [];
        mem.var_list(i).commit_time = [];
        mem.var_list(i).w_ack_send_time = [];
        mem.var_list(i).updating_tid = [];
        mem.var_list(i).updating_node = [];
        
    end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Function to chk for r-w incompatibilties when a read request comes
function mem=GotReadReqAddToReadTable(ID,t,mem,ntid,node_id,nodes_being_read,vars_to_be_read)
  
    for i=1:length(nodes_being_read)
        %disp1(sprintf('%d:%d: Adding read request from %d of TID %d to snoop table',ID,t,node_id,ntid));
        new_i = length(mem.snoop_read_table) + 1;
        mem.snoop_read_table(new_i).node = nodes_being_read(i);
        mem.snoop_read_table(new_i).var = vars_to_be_read(i);
        mem.snoop_read_table(new_i).tid = ntid;
        mem.snoop_read_table(new_i).initiator_node = node_id;
        mem.snoop_read_table(new_i).timestamp = t;
    end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideReadWriteNeighbours(ID,memory)

    %Decide the read neighbours
    memory = DecideReadNeighbours(ID,memory);
    
    %Decide the write neighbours
    memory = DecideWriteNeighbours(ID,memory);
    while(length(memory.multicast_write_nlist) == 0)
        memory = DecideWriteNeighbours(ID,memory);
    end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideReadNeighbours(ID,memory)
    read_trans_matrix = zeros(1,length(memory.neigh_list));
    
    %Decide the read neighbours
    for i=1:length(read_trans_matrix)
        %Randomly choose the read neigbours with 1 being they are in the
        %list
        read_trans_matrix(i) = round(rand);
        if (read_trans_matrix(i) == 1)
            memory.variables_to_read = [memory.variables_to_read 'a'];
        end
    end
    memory.multicast_read_nlist = memory.neigh_list(find(read_trans_matrix == 1));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideWriteNeighbours(ID,memory)
    write_trans_matrix = zeros(1,length(memory.neigh_list));
    
    %Decide the write neighbours
    for i=1:length(write_trans_matrix)
        %Randomly choose the write neigbours with 1 being they are in the
        %list
        write_trans_matrix(i) = round(rand);        
        if (write_trans_matrix(i) == 1)
            memory.variables_to_write = [memory.variables_to_write 'a'];
        end
    end
    memory.multicast_write_nlist = memory.neigh_list(find(write_trans_matrix == 1));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Function to chk for r-w incompatibilties when a write request comes
function mem=GotWriteReqCheckingForConflict(ID,t,mem,ntid,node_id,node_being_written_list,var_being_written_list,WRITE_COMMIT_DELTA,WACK_DELTA,fid,SEND_CONFLICT_MSG_PROP)
    CONFLICT_MSG = 5;
    found = 0;
    FALSE = 0;
    TRUE = 1;

    % Check for rw rw conflicts
    conflict_found = 0;
    tids_to_be_removed = [];
    for i = 1: length(mem.snoop_rwi_table)
        if mem.snoop_rwi_table(i).tid1 == ntid
            % Scan the read table for a second read request by tid2
            for j = 1: length(mem.snoop_read_table)
                if mem.snoop_read_table(j).tid == mem.snoop_rwi_table(i).tid2
                    for k = 1:length(node_being_written_list)
                        if mem.snoop_read_table(j).node == node_being_written_list(k) && mem.snoop_read_table(j).var == var_being_written_list(k)
                            disp1(sprintf('%d:%d: RW RW CONFLICT detected between %d and %d Aborting %d at node %d',ID,t, mem.snoop_rwi_table(i).tid1, mem.snoop_rwi_table(i).tid2, mem.snoop_rwi_table(i).tid1, mem.snoop_rwi_table(i).read_initiator));

                            if isempty(find(tids_to_be_removed == mem.snoop_rwi_table(i).tid1))
                                %Send conflict message 
                                conflict_found=1;

                                %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
                                fprintf(fid, '%d:%d:%s\n', mem.snoop_rwi_table(i).tid1,t,'RW-CONFLICT-DETECT');
                                %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

                                %%% Update the Conflict msg decongestion struct
                                new_i = length(mem.conft_msg_decongestion_struct) + 1;
                                mem.conft_msg_decongestion_struct(new_i).tid = mem.snoop_rwi_table(i).tid1;
                                mem.conft_msg_decongestion_struct(new_i).initiator_node = mem.snoop_rwi_table(i).read_initiator;
                                mem.conft_msg_decongestion_struct(new_i).cmsg_already_sent_flag = FALSE;

                                %Check and send at the expiry of timer
                                Set_Send_Conflict_Msg_Timer(t + (ceil(rand*SEND_CONFLICT_MSG_PROP)*(WACK_DELTA/2)));

                                disp1(sprintf('%d:%d: Sending CONFLICT msg',ID,t));
                                %                         PrintMessage('CNFLT');
                                %                         Send_Packet(radiostream(struct('ID',ID, 'type',CONFLICT_MSG,'TID',mem.snoop_rwi_table(i).tid1,'initiator_node',mem.snoop_rwi_table(i).read_initiator),mem.signal_strength));
                                %Cleanup aborted TID

                                % All aborted TIDS should be removed at one time
                                tids_to_be_removed = [tids_to_be_removed mem.snoop_rwi_table(i).tid1];
                            else
                              disp1(sprintf('%d%d: Ignoring tid %d as it has been previously cancelled',ID,t,mem.snoop_rwi_table(i).tid1));
                            end
                        end
					end
                end
            end
        end
    end

    if conflict_found == 1
        for i = 1:length(tids_to_be_removed)
            mem=CleanupTidAfterConflict(ID, mem,tids_to_be_removed(i));
        end
        return;
    end    
    
    %Assert if node_being_written_list and var_being_written_list have the
    %same length
    % 1: Check if there is a conflcit from the rwi table
    conflict_found = 0;
    tids_to_be_removed = [];
    for i = 1: length(mem.snoop_rwi_table)
        %disp1(sprintf('%d In write conflict detector %d %d',ID,i,length(mem.snoop_rwi_table)));
        if mem.snoop_rwi_table(i).tid1 == ntid 
            %Search with the entire writeall msg for a conflicting node-var
            %pair
         %   disp1(sprintf('%d In write conflict detector',ID));
            for j = 1:length(node_being_written_list)
                if mem.snoop_rwi_table(i).node == node_being_written_list(j) && mem.snoop_rwi_table(i).var == var_being_written_list(j)
                    disp1(sprintf('%d:%d: CONFLICT detected between %d and %d Aborting %d at node %d',ID,t, mem.snoop_rwi_table(i).tid1, mem.snoop_rwi_table(i).tid2, mem.snoop_rwi_table(i).tid1, mem.snoop_rwi_table(i).read_initiator));
                    
                    if isempty(find(tids_to_be_removed == mem.snoop_rwi_table(i).tid1))
                        %Send conflict message 
                        conflict_found=1;

                        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
                        fprintf(fid, '%d:%d:%s\n', mem.snoop_rwi_table(i).tid1,t,'WW-CONFLICT-DETECT');
                        %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

                        %%% Update the Conflict msg decongestion struct
                        new_i = length(mem.conft_msg_decongestion_struct) + 1;
                        mem.conft_msg_decongestion_struct(new_i).tid = mem.snoop_rwi_table(i).tid1;
                        mem.conft_msg_decongestion_struct(new_i).initiator_node = mem.snoop_rwi_table(i).read_initiator;
                        mem.conft_msg_decongestion_struct(new_i).cmsg_already_sent_flag = FALSE;
                        
                        %Check and send at the expiry of timer
                        Set_Send_Conflict_Msg_Timer(t + (ceil(rand*SEND_CONFLICT_MSG_PROP)*(WACK_DELTA/2)));
                        
                        disp1(sprintf('%d:%d: Sending CONFLICT msg',ID,t));
%                         PrintMessage('CNFLT');
%                         Send_Packet(radiostream(struct('ID',ID, 'type',CONFLICT_MSG,'TID',mem.snoop_rwi_table(i).tid1,'initiator_node',mem.snoop_rwi_table(i).read_initiator),mem.signal_strength));
                        %Cleanup aborted TID

                        % All aborted TIDS should be removed at one time
                        tids_to_be_removed = [tids_to_be_removed mem.snoop_rwi_table(i).tid1];
                    else
                        disp1(sprintf('%d%d: Ignoring tid %d as it has been previously cancelled',ID,t,mem.snoop_rwi_table(i).tid1));
                    end
                end
            end
        end
    end

    if conflict_found == 1
        for i = 1:length(tids_to_be_removed)
            mem=CleanupTidAfterConflict(ID, mem,tids_to_be_removed(i));
        end
        return;
    end
    
    %Check if a conflciting write request comes when a write request
    %is waiting for the commit timer
    tids_to_be_removed = [];
    for i = 1:length(mem.snoop_rwi_table)
        % When the head is takes the role of t' : search for possible t
        % in the snoop commit timer queue
        %For each node-var pair in the write request chk if it conlficts
        for j = 1:length(node_being_written_list)
            if (mem.snoop_rwi_table(i).tid1 == ntid) && (mem.snoop_rwi_table(i).node == node_being_written_list(j)) && (mem.snoop_rwi_table(i).var == var_being_written_list(j))
                %Search the snoop commit timer queue for write of t'
                for k = 1:length(mem.snoop_commit_timer_queue)
                    %This is the case when the write of t comes immediately
                    %after the write of t' .
                    if (mem.snoop_commit_timer_queue(k).tid == mem.snoop_rwi_table(i).tid2) && (~isempty(mem.snoop_commit_timer_queue(k).node_being_written_list == mem.snoop_rwi_table(i).node)) && (~isempty(mem.snoop_commit_timer_queue(k).var_being_written_list == mem.snoop_rwi_table(i).var))
                        disp1(sprintf('%d:%d: WRITE AFTER WRITE CAUSING CONFLICT! CONFLICT found between %d and %d canceling %d',ID,t, mem.snoop_rwi_table(i).tid1, mem.snoop_rwi_table(i).tid2,mem.snoop_rwi_table(i).tid1));

                        if isempty(find(tids_to_be_removed == mem.snoop_rwi_table(i).tid1))
                            tids_to_be_removed = [tids_to_be_removed mem.snoop_rwi_table(i).tid1];
                            
                            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 
                            fprintf(fid, '%d:%d:%s\n', mem.snoop_rwi_table(i).tid1,t,'WW-CONFLICT-DETECT');
                            %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$% 

                        %%% Update the Conflict msg decongestion struct
                        new_i = length(memory.conft_msg_decongestion_struct) + 1;
                        memory.conft_msg_decongestion_struct(new_i).tid = mem.snoop_rwi_table(i).tid1;
                        memory.conft_msg_decongestion_struct(new_i).initiator_node = mem.snoop_rwi_table(i).read_initiator;
                        memory.conft_msg_decongestion_struct(new_i).cmsg_already_sent_flag = FALSE;
                        
                        %Check and send at the expiry of timer
                        Set_Send_Conflict_Msg_Timer(t + (ceil(rand*SEND_CONFLICT_MSG_PROP)*(WACK_DELTA/2)));                            
                            disp1(sprintf('%d:%d: Sending CONFLICT msg',ID,t));
%                             PrintMessage('CNFLT');
%                             Send_Packet(radiostream(struct('ID',ID, 'type',CONFLICT_MSG,'TID',mem.snoop_rwi_table(i).tid1,'initiator_node',mem.snoop_rwi_table(i).read_initiator),mem.signal_strength));

                            %Cleanup the aborted tid
                            memory=CleanupTidAfterConflict(ID, mem,mem.snoop_rwi_table(i).tid1);

                            conflict_found = 1;
                        else
                            disp1(sprintf('%d%d: Ignoring tid %d as it has been previously cancelled',ID,t,mem.snoop_rwi_table(i).tid1));
                        end
                     end
                end
            end
        end
    end

    if conflict_found == 1
        for i = 1:length(tids_to_be_removed)
            mem=CleanupTidAfterConflict(ID, mem,tids_to_be_removed(i));
        end
        return;
    end
    
    %In case the write did not cause a conflict earlier, continue...
    if conflict_found == 0
        % 1: For each write in the writeall request check if rw-w conflict can be framed
        for i = 1:length(node_being_written_list)
            %In case the write conflicts with the read
            for j = 1: length(mem.snoop_read_table)
                if (mem.snoop_read_table(j).node == node_being_written_list(i)) && (mem.snoop_read_table(j).var == var_being_written_list(i)) && (mem.snoop_read_table(j).tid ~= ntid)
                    disp1(sprintf('%d:%d: RW incompatibility found between %d and %d for variable %c at node %d',ID,t, mem.snoop_read_table(j).tid, ntid,var_being_written_list(i),node_being_written_list(i)));
                    % Add all other entries in the write msg as rw-w in the
                    % snoop_rwi_table
                     for k = 1:length(node_being_written_list)
                         %Skip in case k = i
                         if k == i
                             continue;
                         end

                         %Insert in the end.
                         new_z = length(mem.snoop_rwi_table) + 1;
                         mem.snoop_rwi_table(new_z).tid1 = mem.snoop_read_table(j).tid;
                         mem.snoop_rwi_table(new_z).tid2 = ntid;
                         mem.snoop_rwi_table(new_z).node = node_being_written_list(k);
                         mem.snoop_rwi_table(new_z).var = var_being_written_list(k);
                         mem.snoop_rwi_table(new_z).read_initiator = mem.snoop_read_table(j).initiator_node;
                         mem.snoop_rwi_table(new_z).timestamp = t;
                     end
                end
            end
        end

        %Start SNOOP_COMMIT_TIMER
        new_i = length(mem.snoop_commit_timer_queue) + 1;
        mem.snoop_commit_timer_queue(new_i).tid = ntid;
        mem.snoop_commit_timer_queue(new_i).node_being_written_list = node_being_written_list;
        mem.snoop_commit_timer_queue(new_i).var_being_written_list = var_being_written_list;
        Set_Snoop_Commit_Alarm_Timer(t + (length(node_being_written_list)*WRITE_COMMIT_DELTA));
    end
    
    %Display snoop tables
%     DisplaySnoopReadTable(ID,mem);
%     DisplaySnoopRWITable(ID,mem);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function mem=CleanupTidAfterConflict(ID,mem,tid)
FALSE = 0;
TRUE = 1;

    %since this is a dynamically reducing array : 
    %scan array for value, 
    %if found delete from array, 
    %   scan all over againwith the new reduced array
    
    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(mem.snoop_read_table)
            if mem.snoop_read_table(i).tid == tid 
                mem.snoop_read_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end

        %since this is a dynamically reducing array
    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(mem.snoop_rwi_table)
            if mem.snoop_rwi_table(i).tid1 == tid || mem.snoop_rwi_table(i).tid2 == tid
                mem.snoop_rwi_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end

    %Disable snoop commit timer
    for i = 1: length(mem.snoop_commit_timer_queue)
        if mem.snoop_commit_timer_queue(i).tid == tid
            mem.snoop_commit_timer_queue(i).tid = inf;
            break;
        end
    end
%     %Display snoop tables
%     DisplaySnoopReadTable(ID,mem);
%     DisplaySnoopRWITable(ID,mem);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function bresult=ChkDuplRWIEntry(ID,memory,node,var,tid1,tid2)
    bresult =0;
    for i = 1:length(memory.snoop_rwi_table)
        if memory.snoop_rwi_table(i).tid1 == tid1 && memory.snoop_rwi_table(i).tid2 == tid2
          %  disp1(sprintf('%d:%d: Duplicate RWI entry avaoided when snoop timer expires',ID,t));
            bresult = 1;
        end
    end

function mem=CleanupTidAfterCommit(ID,mem,tid)
FALSE = 0;
TRUE = 1;

    %since this is a dynamically reducing array : 
    %scan array for value, 
    %if found delete from array, 
    %   scan all over againwith the new reduced array
    
    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(mem.snoop_read_table)
            if mem.snoop_read_table(i).tid == tid 
                mem.snoop_read_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end

        %since this is a dynamically reducing array
    found_flag = -1; % Initial value
    while found_flag ~= FALSE
        found_flag = FALSE;
        i = 1;
        while i <= length(mem.snoop_rwi_table)
            if mem.snoop_rwi_table(i).tid1 == tid %|| mem.snoop_rwi_table(i).tid2 == tid
                mem.snoop_rwi_table(i) = [];
                found_flag = TRUE;
                break;
            end
            i = i + 1;
        end
    end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function DisplaySnoopReadTable(ID,mem)
    disp1(sprintf('\n%d: #################################################',ID));
    disp1(sprintf('%d: Read Snoop table contents : ',ID));
    for i = 1:length(mem.snoop_read_table)
        disp1(sprintf(' -> Node %d Var %c TID %d',mem.snoop_read_table(i).node,mem.snoop_read_table(i).var,mem.snoop_read_table(i).tid));
        %mem.snoop_read_table(i);
    end
    disp1(sprintf('%d: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$',ID));    
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideReadWriteNeighbours(ID,memory)

    %Decide the read neighbours
    memory = DecideReadNeighbours(ID,memory);
    
    %Decide the write neighbours
    memory = DecideWriteNeighbours(ID,memory);
    while(length(memory.multicast_write_nlist) == 0)
        memory = DecideWriteNeighbours(ID,memory);
    end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideReadNeighbours(ID,memory)
    read_trans_matrix = zeros(1,length(memory.neigh_list));
    
    %Decide the read neighbours
    for i=1:length(read_trans_matrix)
        %Randomly choose the read neigbours with 1 being they are in the
        %list
        read_trans_matrix(i) = round(rand);
        if (read_trans_matrix(i) == 1)
            memory.variables_to_read = [memory.variables_to_read 'a'];
        end
    end
    memory.multicast_read_nlist = memory.neigh_list(find(read_trans_matrix == 1));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function memory = DecideWriteNeighbours(ID,memory)
    write_trans_matrix = zeros(1,length(memory.neigh_list));
    
    %Decide the write neighbours
    for i=1:length(write_trans_matrix)
        %Randomly choose the write neigbours with 1 being they are in the
        %list
        write_trans_matrix(i) = round(rand);        
        if (write_trans_matrix(i) == 1)
            memory.variables_to_write = [memory.variables_to_write 'a'];
        end
    end
    memory.multicast_write_nlist = memory.neigh_list(find(write_trans_matrix == 1));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function result=ApplyTranformation(list,oper_type)
    switch oper_type
        case 'PRODUCT'
            result = prod(list);
        case 'SUM'
            result = sum(list);
        case 'MAX'
            result = max(list);
    end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
function memory = SendReadReq(ID,t,memory,READ_REQ_MSG,READ_REQUEST_SPACING,fid)
    disp1(sprintf('%d: Sending read request',ID));
    PrintMessage('R REQ');
    Send_Packet(radiostream(struct('ID',ID, 'type',READ_REQ_MSG,'TID',memory.cur_TID,'read_nlist',memory.multicast_read_nlist,'var_to_be_read',memory.variables_to_read),memory.signal_strength));

    memory.read_ans_recvd = 0;
    %Start a timer for the sender to wait for all the ACKS
    Set_Alarm_Receive_Read_Answers_Timer(t+ (length(memory.multicast_read_nlist)+ 1)*READ_REQUEST_SPACING);

    %Initialize the answer array
    memory.answering_nodes_index = [];
    for i=1:length(memory.multicast_read_nlist)
        memory.answering_nodes_index(i).flag = inf;
        memory.answering_nodes_index(i).name = '';
        memory.answering_nodes_index(i).value = inf;
    end
    
    %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
    for i=1:length(memory.multicast_read_nlist)
        fprintf(fid, '%d:%d:%s:%d:%c\n', memory.cur_TID,t,'READ',memory.multicast_read_nlist(i),memory.variables_to_read(i));
    end
    %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   
function memory = SendWriteReq(ID,t,memory,WRITE_ALL_REQ_MSG,WACK_DELTA,fid)
    PrintMessage('W ALL');
    disp1(sprintf('%d: Sending write req',ID));
    
    %Initialize the write ack receive array
    memory.write_acks = [];
    for i=1:length(memory.multicast_write_nlist)
        memory.write_acks = [memory.write_acks inf];
    end

   memory.aborting_transaction_flag = 0; 
   memory.num_cancel_msg_resend = 0;
   
   %Sending the write-all message to subset of neighbors
   Send_Packet(radiostream(struct('ID',ID, 'type',WRITE_ALL_REQ_MSG,'TID',memory.cur_TID,'write_nlist',memory.multicast_write_nlist,'variables_to_write',memory.variables_to_write,'values_to_write',memory.values_to_write),memory.signal_strength));

   %Start a timer for the sender to wait for all the ACKS
   Set_Receive_Write_All_Ack_Timer(t+ (length(memory.multicast_write_nlist + 1)*WACK_DELTA));

   %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
    write_string = [];
    for i=1:length(memory.multicast_write_nlist)
        write_string = strcat(write_string,sprintf('::%d:%c',memory.multicast_write_nlist(i),memory.variables_to_write(i)));
    end
    fprintf(fid, '%d:%d:%s:%s\n', memory.cur_TID,t,'WRITE',write_string);
    %$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%
   
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   
function disp1(string)
    %disp(string);

function r=rand023()
    ran = rand;
    if ran <= 0.333
        r=0;
    elseif ran >0.333 && ran <=0.667
        r=2;
    else
        r=3;
    end
          
