%% Simulation: Work-conserving Service Disciplines
% by Sylvia Kouyoumdjieva & Ognjen Vukovic 
%            (c) 2011, LCN, KTH
% 
% Case study: Virtual clock service discipline
% Reference: Zhang, Hui, "Service Disciplines for Guaranteed Performance 
% Service in Packet-Switched Networks" (sec III - A, Fig. 9)
% 
% Usage: virtualClock()
% 
% Description: Switched network with four incoming flows (1 to 4) entering 
% the system at the corresponding switches. Each flow traverses three switches 
% before leaving the network (e.g. flow 1 is destined to switch 4, flow 2 - to 
% switch 1, etc). Flows generate packets with fixed interarrival time.
% Each switch schedules the incoming packets based on a 
% pre-defined  per flow virtual clock by the reservation policy. Packets
% with lower arrival rate are prioritized by the virtual clock. One should 
% observe the burstiness of the output traffic introduced by the virtual '
% clock scheduling policy.
% 
% Parameters: the packet interarrival time for each flow is ajusted from the
% user interface, within the range of 1 to 10. . Default arrival rates are lambda1 = 1/2 packets/slot,
% lambda2 = 1/3 packets/slot, lambda3 = 1/4 packets/slot and lambda4 =
% 1/6 packets/slot
%
% 


function [] = virtualClock()
    %ScreenSize is a four-element vector: [left, bottom, width, height]:
    scrsz = get(0,'ScreenSize');

    %Specifying the Figure Window Title
    %figure('Name','Simulation Plot Window','NumberTitle','off')
    %color = [[0 0 1]; [1 0 0]];
    % [1 1 0] y yellow
    % [1 0 1] m magenta
    % [0 1 1] c cyan
    % [1 0 0] r red
    % [0 1 0] g green
    % [0 0 1] b blue
    % [1 1 1] w white
    % [0 0 0] k black
    global setOfColors;
    global color;
    global pause_flag;
    global pause_resume_button;
    global lambda;
    global running_flag;
    global ptime;
    setOfColors = ['g'; 'r'; 'b'; 'y'; 'm'];
    color = ['g'; 'r'; 'b'; 'y'; 'm'];
    % 'g' if we mix more flows into 1

    ptime = 0.3;
    lambda = [2 3 4 6];

    iters = 200;
    
    idx = 1;
    pause_flag = 0; % if pause_flag = 1 then nothing happens
    running_flag = 1; % if running_flag = 1 then the simulation is on
    
%     global resume_pause_x;
%     global resume_pause_y;
%     global resume_pause_sizex;
%     global resume_pause_sizey;
%     resume_pause_sizex = 100;
%     resume_pause_sizey = 50;
%     resume_pause_x = 0;
%     resume_pause_y = scrsz(4)-resume_pause_sizey;
    % initialize the screen with the input sources, and display the
    % scheduled packets
    
    [input, output, lines, scheduler] = screen_setup(scrsz(3),scrsz(4), color, setOfColors);
    src = zeros(4, input.display);
    while idx < input.display
        [src] = arrival(lambda, src);
        [input, scheduler, lines, output] = update(input, scheduler, lines, output, src, color);        
        %[input, ~, output] = update(input, [], output, src, colors);
        idx = idx + 1;
    end
    
    idx = 1;
    % real job is done here
    %while idx < iters
    while running_flag == 1
        if (pause_flag == 0)
            idx;
            [scheduler] = schedule(scheduler, src, lines, color, lambda);
            [src] = arrival(lambda, src);
            [lines, scheduler, output] = transmission(scheduler, lines, output, src);
            [input, scheduler, lines, output] = update(input, scheduler, lines, output, src, color);
            %[input, ~, output] = update(input, [], output, src, colors);
            idx = idx + 1;
            pause(ptime);
        else
            pause(0.1);
        end;
    end

end

function [input, output, lines, scheduler] = screen_setup(height, width, color, setOfColors)
    
    input.display = 20;
    output.display = input.display;
    lines.display = 30;
    
    %% GRAPHICAL PARAMETERS
    xymargin = 10;
    pkt_width = 6;
	pkt_height = 18;
    switch_high = 50;
    switch_color = 'black';
    switch_xymargin = xymargin + input.display*pkt_width;
    %inputoutput_xymargin = switch_high./20;
    inputoutput_xymargin = (switch_high - pkt_height)/2;

    %scheduler.vclock = zeros(1, input.display);
    
    %% PANEL
    fig(1) = figure(1);
    set(fig(1), 'Position', [0 0 height width]);
    axes('Position',[0 0 1 1]);
    daspect([1,1,1]);
    axis off;

    %% SWITCHES
%     switches(1).x = switch_xymargin;
%     switches(1).y = switch_xymargin+switch_high*3;
%     switches(2).x = switch_xymargin+switch_high*3;
%     switches(2).y = switch_xymargin+switch_high*6;
%     switches(3).x = switch_xymargin+switch_high*6;
%     switches(3).y = switch_xymargin+switch_high*3;
%     switches(4).x = switch_xymargin+switch_high*3;
%     switches(4).y = switch_xymargin;
	switches(1).x = switch_xymargin;
	switches(1).y = switch_xymargin;
    switches(2).x = switch_xymargin;
    switches(2).y = switch_xymargin+switch_high*5;
    switches(3).x = switch_xymargin+switch_high*5;
    switches(3).y = switch_xymargin+switch_high*5;
    switches(4).x = switch_xymargin+switch_high*5;
    switches(4).y = switch_xymargin;
    switches(1).rct = rectangle('Position',[switches(1).x, switches(1).y, switch_high, switch_high]);
    switches(2).rct = rectangle('Position',[switches(2).x, switches(2).y, switch_high, switch_high]);
    switches(3).rct = rectangle('Position',[switches(3).x, switches(3).y, switch_high, switch_high]);
    switches(4).rct = rectangle('Position',[switches(4).x, switches(4).y, switch_high, switch_high]);
    set(switches(1).rct, 'FaceColor', switch_color);
    set(switches(1).rct, 'EdgeColor', 'black');
    text(switches(1).x + switch_high./2, switches(1).y + switch_high./2, 'Switch 1', 'Color', 'white', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
    set(switches(2).rct, 'FaceColor', switch_color);
    set(switches(2).rct, 'EdgeColor', 'black');
    text(switches(2).x + switch_high./2, switches(2).y + switch_high./2, 'Switch 2', 'Color', 'white', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
    set(switches(3).rct, 'FaceColor', switch_color);
    set(switches(3).rct, 'EdgeColor', 'black');
    text(switches(3).x + switch_high./2, switches(3).y + switch_high./2, 'Switch 3', 'Color', 'white', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
    set(switches(4).rct, 'FaceColor', switch_color);
    set(switches(4).rct, 'EdgeColor', 'black');
    text(switches(4).x + switch_high./2, switches(4).y + switch_high./2, 'Switch 4', 'Color', 'white', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
    
    %% LINKS BETWEEN SWITCHES
    %link from switch 1 to switch 2
    link(1).x1 = switches(1).x + switch_high./2;
    link(1).y1 = switches(1).y + switch_high;
    link(1).x2 = switches(2).x + switch_high./2;
    link(1).y2 = switches(2).y ;
    %link from switch 2 to switch 3
    link(2).x1 = switches(2).x + switch_high;
    link(2).y1 = switches(2).y + switch_high./2;
    link(2).x2 = switches(3).x;
    link(2).y2 = switches(3).y + switch_high./2;
    %link from switch 3 to switch 4
    link(3).x1 = switches(3).x + switch_high./2;
    link(3).y1 = switches(3).y;
    link(3).x2 = switches(4).x + switch_high./2;
    link(3).y2 = switches(4).y + switch_high;
    %link from switch 4 to switch 1
    link(4).x1 = switches(4).x;
    link(4).y1 = switches(4).y + switch_high./2;
    link(4).x2 = switches(1).x + switch_high;
    link(4).y2 = switches(1).y + switch_high./2;
    
%     link(1).x2 = switches(2).x;
%     link(1).y2 = switches(2).y + switch_high./2;
%     link(2).x2 = switches(3).x + switch_high./2;
%     link(2).y2 = switches(3).y + switch_high;
%     link(3).x2 = switches(4).x + switch_high;
%     link(3).y2 = switches(4).y + switch_high./2;
%     link(4).x2 = switches(1).x + switch_high./2;
%     link(4).y2 = switches(1).y;

    line([link(1).x1 link(1).x2],[link(1).y1 link(1).y2],'LineStyle','-','Color','k');
    line([link(2).x1 link(2).x2],[link(2).y1 link(2).y2],'LineStyle','-','Color','k');
    line([link(3).x1 link(3).x2],[link(3).y1 link(3).y2],'LineStyle','-','Color','k');
    line([link(4).x1 link(4).x2],[link(4).y1 link(4).y2],'LineStyle','-','Color','k');
    
    %% INPUT FLOWS
    % input flow 1-4
    text(switches(1).x + inputoutput_xymargin, switches(1).y - input.display*pkt_width / 2, 'Flow 1', 'Color', 'black', 'HorizontalAlignment', 'right', 'VerticalAlignment', 'middle');
    for i=1:input.display;
        %input.gui(1,i) = rectangle('Position', [xymargin + (i-1)*pkt_width, switches(1).y + switch_high - inputoutput_xymargin - pkt_height, pkt_width, pkt_height]);
        input.gui(1,i) = rectangle('Position', [switches(1).x + inputoutput_xymargin, switches(1).y - input.display*pkt_width + (i-1)*pkt_width, pkt_height, pkt_width]);
        set(input.gui(1,i), 'FaceColor', 'white');
        set(input.gui(1,i), 'EdgeColor', 'black');
    end;
    % input flow 2-1
    text(xymargin + (input.display-1)*pkt_width/2 , switches(2).y + inputoutput_xymargin, 'Flow 2', 'Color', 'black', 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top');
    for i=1:input.display;
        %input.gui(2,i) = rectangle('Position', [switches(2).x + switch_high - inputoutput_xymargin - pkt_height, switches(2).y + switch_high + (input.display-1)*pkt_width - (i-1)*pkt_width, pkt_height, pkt_width]);
        input.gui(2,i) = rectangle('Position', [xymargin + (i-1)*pkt_width, switches(2).y + inputoutput_xymargin, pkt_width, pkt_height]);
        set(input.gui(2,i), 'FaceColor', 'white');
        set(input.gui(2,i), 'EdgeColor', 'black');
    end;
    % input flow 3-2
    text(switches(3).x + inputoutput_xymargin , switches(3).y + switch_high + (input.display-1)*pkt_width/2, 'Flow 3', 'Color', 'black', 'HorizontalAlignment', 'right', 'VerticalAlignment', 'middle');
    for i=1:input.display;
        %input.gui(3,i) = rectangle('Position', [switches(3).x + switch_high + (input.display-1)*pkt_width - (i-1)*pkt_width, switches(3).y + inputoutput_xymargin, pkt_width, pkt_height]);
        input.gui(3,i) = rectangle('Position', [switches(3).x + inputoutput_xymargin, switches(3).y + switch_high + (input.display-1)*pkt_width - (i-1)*pkt_width, pkt_height, pkt_width]);
        set(input.gui(3,i), 'FaceColor', 'white');
        set(input.gui(3,i), 'EdgeColor', 'black');
    end;
    % input flow 4-3
    text(switches(4).x + switch_high + + (input.display-1)*pkt_width/2 , switches(4).y + inputoutput_xymargin, 'Flow 4', 'Color', 'black', 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top');
    for i=1:input.display;
        %input.gui(4,i) = rectangle('Position', [switches(4).x + inputoutput_xymargin, switches(4).y - input.display*pkt_width + (i-1)*pkt_width, pkt_height, pkt_width]);
        input.gui(4,i) = rectangle('Position', [switches(4).x + switch_high + (input.display-1)*pkt_width - (i-1)*pkt_width, switches(4).y + inputoutput_xymargin, pkt_width, pkt_height]);
        set(input.gui(4,i), 'FaceColor', 'white');
        set(input.gui(4,i), 'EdgeColor', 'black');
    end;
    
    %% OUTPUT FLOWS
    % output flow 2-1
    for i=1:output.display;
        output.gui(1,i) = rectangle('Position', [switches(1).x - (i-1)*pkt_width - pkt_width, switches(1).y + inputoutput_xymargin, pkt_width, pkt_height]);
        set(output.gui(1,i), 'FaceColor', 'white');
        set(output.gui(1,i), 'EdgeColor', 'black');
        output.flow(1,i) = 0;
    end;
    % output flow 3-2
    for i=1:output.display;
        output.gui(2,i) = rectangle('Position', [switches(2).x + inputoutput_xymargin, switches(2).y + switch_high + (i-1)*pkt_width , pkt_height, pkt_width]);
        set(output.gui(2,i), 'FaceColor', 'white');
        set(output.gui(2,i), 'EdgeColor', 'black');
        output.flow(2,i) = 0;
    end;
     % output flow 4-3
    for i=1:output.display;
        %output.gui(3,i) = rectangle('Position', [switches(3).x + switch_high + (i-1)*pkt_width, switches(3).y + switch_high - inputoutput_xymargin - pkt_height, pkt_width, pkt_height]);
        output.gui(3,i) = rectangle('Position', [switches(3).x + switch_high + (i-1)*pkt_width, switches(3).y + inputoutput_xymargin, pkt_width, pkt_height]);
        set(output.gui(3,i), 'FaceColor', 'white');
        set(output.gui(3,i), 'EdgeColor', 'black');
        output.flow(3,i) = 0;
    end;
    % output flow 1-4
    for i=1:output.display;
        %output.gui(4,i) = rectangle('Position', [switches(4).x + switch_high - inputoutput_xymargin - pkt_height, switches(4).y - (i-1)*pkt_width - pkt_width, pkt_height, pkt_width]);
        output.gui(4,i) = rectangle('Position', [switches(4).x + inputoutput_xymargin, switches(4).y - (i-1)*pkt_width - pkt_width, pkt_height, pkt_width]);
        set(output.gui(4,i), 'FaceColor', 'white');
        set(output.gui(4,i), 'EdgeColor', 'black');
        output.flow(4,i) = 0;
    end;
    
    %% LINE FLOWS
    % line flow 1-2
    for i=1:lines.display;
        lines.length(1) = switches(2).y - switches(1).y - switch_high;
        lines.gui(1,i) = rectangle('Position', [link(1).x1 - pkt_height, link(1).y1 + (lines.length(1) - lines.display*pkt_width)./2 + (i-1)*pkt_width, pkt_height, pkt_width]);
        set(lines.gui(1,i), 'FaceColor', 'white');
        set(lines.gui(1,i), 'EdgeColor', 'black');
        lines.flow(1,i) = 0;
    end;
    % line flow 2-3
    for i=1:lines.display;
        lines.length(2) = switches(3).x - switches(2).x - switch_high;
        lines.gui(2,i) = rectangle('Position', [link(2).x1 + (lines.length(2) - lines.display*pkt_width)./2 + (i-1)*pkt_width , link(2).y1, pkt_width , pkt_height]);
        set(lines.gui(2,i), 'FaceColor', 'white');
        set(lines.gui(2,i), 'EdgeColor', 'black');
        lines.flow(2,i) = 0;
    end;
    % line flow 3-4
    for i=1:lines.display;
        lines.length(3) = switches(3).y - switches(4).y - switch_high;
        lines.gui(3,i) = rectangle('Position', [link(3).x1, link(3).y1 - (lines.length(3) - lines.display*pkt_width)./2 - (i-1)*pkt_width, pkt_height, pkt_width]);
        set(lines.gui(3,i), 'FaceColor', 'white');
        set(lines.gui(3,i), 'EdgeColor', 'black');
        lines.flow(3,i) = 0;
    end;
    % line flow 4-1
    for i=1:lines.display;
        lines.length(4) = switches(4).x - switches(1).x - switch_high;
        lines.gui(4,i) = rectangle('Position', [link(4).x1 - (lines.length(4) - lines.display*pkt_width)./2 - (i-1)*pkt_width - pkt_width, link(4).y1 - pkt_height, pkt_width , pkt_height]);
        set(lines.gui(4,i), 'FaceColor', 'white');
        set(lines.gui(4,i), 'EdgeColor', 'black');
        lines.flow(4,i) = 0;
    end;
    
    %axis([0 100 0 100]) 
    % axis([xmin xmax ymin ymax]) 
    % sets the limits for the x- and y-axis of the current axes.
    
    % rectangle('Position',[x,y,w,h]) 
    % draws the rectangle from the point x,y and having a width of w and a height of h. 
    % Specify values in axes data units.
    % to display a rectangle in the specified proportions, 
    % you need to set the axes data aspect ratio so that one unit is 
    % of equal length along both the x and y axes. 
    % You can do this with the command axis equal or daspect([1,1,1]).
    
    %subplot('Position', [0.0, 0.0, 1, 1]);
    % subplot('Position',[left bottom width height]) 
    % creates an axes at the position specified by a four-element vector. 
    % left, bottom, width, and height are in normalized coordinates in the range from 0.0 to 1.0
    %axis off;
    
    
    % scheduler
               
    scheduler.display = 10;
    scheduler.occupied = zeros(1,4);
    scheduler.flow = zeros(4, scheduler.display);
    
    scheduler.outputdisplay = 10;
    scheduler.outputoccupied = zeros(1,4);
    scheduler.outputflow = zeros(4, scheduler.outputdisplay);
    
    lines.occupied = zeros(1,4);
    
    % buttons
%   resume_pause_x = switches(1).x + switch_high + (switches(4).x - switches(1).x - switch_high)./2 - resume_pause_sizex./2;
%   resume_pause_y = switches(1).y + switch_high + (switches(2).y - switches(1).y - switch_high)./2 - resume_pause_sizey./2;
%     resume_pause_x2 = resume_pause_x1 + resume_pause_sizex;
%     resume_pause_y2 = resume_pause_y1 + resume_pause_sizey;
    global pause_resume_button;
    stop_button = uicontrol('Style', 'pushbutton', 'String', 'Stop', 'FontSize',16,'Position', [0 0 200 50],'Callback', 'running_flag_function'); 
    pause_resume_button = uicontrol('Style', 'pushbutton', 'String', 'Pause', 'FontSize',16,'Position', [0 50 200 50],'Callback', 'pause_flag_function'); 

    global ptime;
    tmp = 1 - (ptime-0.01);
    uicontrol('Style', 'slider', 'Min',0.01, 'Max',1.00, 'Value',tmp,'Position',[0 105 200 20],'Callback', @selcbkspeed);
    uicontrol('Style','text','Position',[0 125 200 30],'String','Simulation speed', 'FontSize',12)
    
%     h = uibuttongroup('visible','off','Position',[0 .17 .11 .14]);
%     % Create three radio buttons in the button group.
%     u0 = uicontrol('Style','Radio','String','Distinguish all flows','pos',[5 125 200 30],'parent',h,'HandleVisibility','off', 'FontSize',12);
%     u1 = uicontrol('Style','Radio','String','Distinguish flow 1->4','pos',[5 95 200 30],'parent',h,'HandleVisibility','off', 'FontSize',12);
%     u2 = uicontrol('Style','Radio','String','Distinguish flow 2->1','pos',[5 65 200 30],'parent',h,'HandleVisibility','off', 'FontSize',12);
%     u3 = uicontrol('Style','Radio','String','Distinguish flow 3->2','pos',[5 35 200 30],'parent',h,'HandleVisibility','off', 'FontSize',12);
%     u4 = uicontrol('Style','Radio','String','Distinguish flow 4->3','pos',[5 5 200 30],'parent',h,'HandleVisibility','off', 'FontSize',12);
%     % Initialize some button group properties. 
%     set(h,'SelectionChangeFcn',@selcbkradio);
%     set(h,'SelectedObject',u0);  % No selection
%     set(h,'Visible','on');
    
    uicontrol('Style','popup', 'String','Distinguish all flows|Distinguish flow 1->4|Distinguish flow 2->1|Distinguish flow 3->2|Distinguish flow 4->3','Position', [0 150 200 40], 'Callback', @selcbkpopup, 'FontSize',12);
    
    global lambda;
    
    uicontrol('Style', 'slider','Min',1,'Max',10,'Value',lambda(1),'Position', [0 350 200 20],'Callback', {@selcbkslide,1});
    uicontrol('Style','text','Position',[0 370 200 30],'String','Interarrival time for flow 1-4', 'FontSize',12)
    uicontrol('Style', 'slider','Min',1,'Max',10,'Value',lambda(2),'Position', [0 300 200 20],'Callback', {@selcbkslide,2});
    uicontrol('Style','text','Position',[0 320 200 30],'String','Interarrival time for flow 2-1', 'FontSize',12)
    uicontrol('Style', 'slider','Min',1,'Max',10,'Value',lambda(3),'Position', [0 250 200 20],'Callback', {@selcbkslide,3});
    uicontrol('Style','text','Position',[0 270 200 30],'String','Interarrival time for flow 3-2', 'FontSize',12)
    uicontrol('Style', 'slider','Min',1,'Max',10,'Value',lambda(4),'Position', [0 200 200 20],'Callback', {@selcbkslide,4});
    uicontrol('Style','text','Position',[0 220 200 30],'String','Interarrival time for flow 4-3', 'FontSize',12)
end

function selcbkslide(hObj,eventdata,id)
    global lambda;
    % when user moves the slider control
    lambda(id) = round(get(hObj,'Value'));
    %get(hObj,'Value')
end

function selcbkspeed(hObj,eventdata)
    global ptime;
    % when user moves the slider control
    ptime = get(hObj,'Max') - (get(hObj,'Value') - get(hObj,'Min'));
    %get(hObj,'Value')
end

function [] = selcbkradio(source,eventdata)
    global color;
    global setOfColors;
    %disp(source);
    %disp([eventdata.EventName,'  ', get(eventdata.OldValue,'String'),'  ', get(eventdata.NewValue,'String')]);
    %disp(get(get(source,'SelectedObject'),'String'));
    if (strcmp(get(eventdata.NewValue,'String'),'Distinguish all flows')==1)
        color = setOfColors;
    end;
    if (strcmp(get(eventdata.NewValue,'String'),'Distinguish flow 1->4')==1)
        color = setOfColors;
        color(3) = color(1);
        color(4) = color(1);
        color(5) = color(1);
    end;
    if (strcmp(get(eventdata.NewValue,'String'),'Distinguish flow 2->1')==1)
        color = setOfColors;
        color(2) = color(1);
        color(4) = color(1);
        color(5) = color(1);
    end;
    if (strcmp(get(eventdata.NewValue,'String'),'Distinguish flow 3->2')==1)
        color = setOfColors;
        color(2) = color(1);
        color(3) = color(1);
        color(5) = color(1);
    end;
    if (strcmp(get(eventdata.NewValue,'String'),'Distinguish flow 4->3')==1)
        color = setOfColors;
        color(2) = color(1);
        color(3) = color(1);
        color(4) = color(1);
    end;
end

function selcbkpopup(hObj,event)
    % Called when user activates popup menu 
    global color;
    global setOfColors;
    val = get(hObj,'Value');
    if val ==1
        color = setOfColors;
    elseif val == 2
        color = setOfColors;
        color(3) = color(1);
        color(4) = color(1);
        color(5) = color(1);
    elseif val == 3
        color = setOfColors;
        color(2) = color(1);
        color(4) = color(1);
        color(5) = color(1);
    elseif val == 4
        color = setOfColors;
        color(2) = color(1);
        color(3) = color(1);
        color(5) = color(1);
    elseif val == 5
        color = setOfColors;
        color(2) = color(1);
        color(3) = color(1);
        color(4) = color(1);
    end
end

function [] = running_flag_function()
    global running_flag;
	running_flag = 0;
end

function [] = pause_flag_function()
    global pause_flag;
	pause_flag = 1;
    global pause_resume_button;
    set(pause_resume_button, 'String', 'Resume','Callback', 'resume_flag_function');
    %uicontrol('Style', 'pushbutton', 'String', 'Resume', 'FontSize',16,'Position', [0 0 125 50],'Callback', 'resume_flag_function'); 
end
function [] = resume_flag_function()
    global pause_flag;
	pause_flag = 0;
    global pause_resume_button;
    set(pause_resume_button, 'String', 'Pause','Callback', 'pause_flag_function');
    %uicontrol('Style', 'pushbutton', 'String', 'Pause', 'FontSize',16,'Position', [0 0 125 50],'Callback', 'pause_flag_function'); 
end

function src = arrival(lambda, src)
    % for each flow
    for idx = 1:length(lambda)
        tmp = find(src(idx,:) > 0);
        if (~isempty(tmp)) % move one step forward in time, 
                            % generate a packet when needed
            diff = length(src(idx,:)) - tmp(end) + 1;
            if (rem(diff, lambda(idx)) == 0) % && src(idx,end) ~= 1)
                src(idx,:) = [src(idx, 2:end), 1];
            else              
                src(idx,:) = [src(idx, 2:end), 0];
            end
        else % we are in the very initial stage
            for i = 1:length(src(idx, :))
                if (rem(i, lambda(idx)) == 0)
                    src(idx,i) = 1;
                end;
            end;
        end;
    end;
end

function [input, scheduler, lines, output] = update(input, scheduler, lines, output, src, colors)
    [num_src, len_src]= size(src);
    % update incoming flows
    for idx = 1:num_src
        for i=0:length(input.gui(idx,:))-1  
            if src(idx, i+1) == 1
                set(input.gui(idx, length(input.gui(idx,:)) - i), 'FaceColor', [colors(idx+1,:)]);
            else
                set(input.gui(idx, length(input.gui(idx,:)) - i), 'FaceColor', 'white');
            end
        end  
    end
    
    % update scheduler view
%     for i = 1:length(scheduler.gui) - 1 
%         if (scheduler.flow(i) == 0)
%             set(scheduler.gui(i), 'FaceColor', 'white');
%         else
%             set(scheduler.gui(i), 'FaceColor', [color(scheduler.flow(i),:)]);
%         end
%     end
    
    % update transmission view
    for idx = 1:num_src
        for i = 1:length(lines.gui(idx,:))
            if (lines.flow(idx, i) == 0)
                set(lines.gui(idx,i), 'FaceColor', 'white');
            else
                set(lines.gui(idx,i), 'FaceColor', [colors(lines.flow(idx,i)+1)]);
            end
        end
    end
    
	for idx = 1:num_src
        for i = 1:length(output.gui(idx,:))
            if (output.flow(idx, i) == 0)
                set(output.gui(idx,i), 'FaceColor', 'white');
            else
                set(output.gui(idx,i), 'FaceColor', [colors(output.flow(idx,i)+1,:)]);
            end
        end
    end
end

function [scheduler] = schedule(scheduler, src, lines, color, lambda)
    [num_src, len_src]= size(src);
    
    for idx = 1:num_src
        % for every scheduler
        % find line ID that enters the scheduler(idx):
        if idx - 1 == 0
            lines_idx = size(lines.flow,1);
        else
            lines_idx = idx - 1;
        end;
        % find the flow ID that is sent to you
        myflow_idx = rem(idx,4) + 1;
        
        if (lines.flow(lines_idx,end) ~= 0)
            % an arrival from the line flow
            if (lines.flow(lines_idx,end) == myflow_idx)
                % if idx is the destination
                if (scheduler.outputoccupied(idx) < scheduler.outputdisplay)
                    scheduler.outputflow(idx, scheduler.outputdisplay - scheduler.outputoccupied(idx)) = myflow_idx;
                    scheduler.outputoccupied(idx) = scheduler.outputoccupied(idx) + 1;
                end;
                if (src(idx, end) == 1)
                    % parallel arrival from the source
                    if (scheduler.occupied(idx) < scheduler.display)
                        scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = idx;
                        scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                    end;
                end;
            else
                % idx is not the destination
                if (scheduler.occupied(idx) < scheduler.display)
                    % if there is still place in the buffer
                    if ((src(idx, end) == 1))
                        %parallel arrivals
                        if (lambda(idx)>lambda(lines.flow(lines_idx,end)))
                        	% first goes the packet from the source
                            scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = idx;
                            scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                            if (scheduler.occupied(idx) < scheduler.display) 
                                % if there is still place in the buffer, add the
                                % packet from the line flow
                                scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = lines.flow(lines_idx,end);
                                scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                            end;
                        else
                            % first goes the packet from the line flow
                            scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = lines.flow(lines_idx,end);
                            scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                            if (scheduler.occupied(idx) < scheduler.display) 
                                % if there is still place in the buffer, add the
                                % packet from the source
                                scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = idx;
                                scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                            end;
                        end;
                    else
                        %not parallel arrivals
                        scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = lines.flow(lines_idx,end);
                        scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                    end;
                end;
            end;
        else
            if (src(idx, end) == 1)
                % an arrival from the source
                if (scheduler.occupied(idx) < scheduler.display)
                    % if there is still place in the buffer
                    scheduler.flow(idx, scheduler.display - scheduler.occupied(idx)) = idx;
                    scheduler.occupied(idx) = scheduler.occupied(idx) + 1;
                end;
            end;
        end
   	end
end

function [lines, scheduler, output] = transmission(scheduler, lines, output, src)

    [num_src, len_src]= size(src);

    for idx = 1:num_src
        if (scheduler.outputoccupied(idx) > 0)
            output.flow(idx, :) = [scheduler.outputflow(idx,end) output.flow(idx,1:end-1)];
            scheduler.outputflow(idx,:) = [0 scheduler.outputflow(idx, 1:end-1)];
            scheduler.outputoccupied(idx) = scheduler.outputoccupied(idx) - 1;  
        else
            output.flow(idx, :) = [0 output.flow(idx, 1:end-1)];
        end
        
        if (scheduler.occupied(idx) > 0)          
            lines.flow(idx,:) = [scheduler.flow(idx,end) lines.flow(idx,1:end-1)];
            lines.occupied(idx) = lines.occupied(idx) + 1;        
            scheduler.flow(idx,:) = [0 scheduler.flow(idx, 1:end-1)];
            scheduler.occupied(idx) = scheduler.occupied(idx) - 1;  
            
        else 
            lines.flow(idx, :) = [0 lines.flow(idx, 1:end-1)];
            
        end
    
    end  
end