%% Simulatore di task
clear all; close all; clc;
%% Parametri e variabili globali:
global Ts...        %tempo di campionamento
       X...         %vettore degli agenti
       pool...      %vettore dei task
       V...         %matrice di copertura
       t...         %istante corrente
       Tdrop...     %Tempo di drop
       alpha...     %Peso della priorita' intrinseca dei task
       newOccurrence; %...  %variabile booleana che indica un nuovo arrivo o una terminazione dei task
       %mov;        %File video

%Dichiarazione struttura dei task:
pool = struct(  'ID',{},...     % taskID
                'Tocc',{},...   % istante di prima occorrenza del task
                'type',{},...   % tipo di task {op,trk,str,pat}
                'loc',{},...    % agente o area di localizzazione
                'Tserv',{},...  % tempo dsi servizio residuo
                'pr',{},...     % priorita' intrinseca normalizzata {.25,.5,.75,1}
                'list',{},...   % lista ID degli agenti compatibili col task
                'a',{},...      % ID agente che sta eseguendo il task (0=nessuno)
                'TservIn',{},...% tempo di servizio totale
                'Tdrop',{}...  % droptime
              );
%Dichiarazione struttura degli agenti:
X = struct( 'ID',{},...     % camID
            'tsk',{},...    % copia del task in esecuzione
            'v',{},...      % elenco delle aree coperte
            'list',{},...   % lista ID dei task compatibili
            'score',{},...  % punteggi dei task compatibili
            'index',{},...  % posizione nel pool dei task compatibili
            'uCounter',{}...% unassigned counter (contatore del numero di cicli in cui l'agente resta idle)
           );
%Parametri temporali per la simulazione (tempo di campionamento,
% T di fine sim, vettore dei tempi):
Ts = 1; Tend = 20; time = 0:Ts:Tend;

N = 8; %numero di agenti
M = 9; %numero di aree
%Matrice di copertura:
V = [1 1 0 0 0 0 0 0 0;
     1 0 1 0 0 0 0 0 0;
     0 1 0 1 0 1 0 0 0;
     0 1 0 0 1 0 1 0 0;
     0 0 1 0 1 0 0 1 0;
     0 0 1 1 0 0 0 0 1;
     0 0 0 1 0 1 0 0 1;
     0 0 0 0 1 0 1 1 0];

%% parametri di vita e generazione dei task:
Mt.op = 2; Mt.trk = 2; Mt.str = 2;   % tempi medi di interarrivo
St.op = 3; St.trk = 3; St.str = 3;   % tempi medi di servizio
% indice di carico approssimato del sistema:
C = St.op/Mt.op/N + (St.trk/Mt.trk + St.str/Mt.str)/mean(sum(V,2))/M*mean(sum(V,1));

R = generateTask(Mt,St,N,M,Tend);   %genera una nuova realizzazione dei task
load TaskRealization.mat Mt St R;   %carica l'ultima realizzazione generata dei task

Tdrop = 12;    %tempo di drop
alpha = .8;    %peso priorita' intrinseca dei task

%% inizializzazione agenti:
for n = 1 : N
    X(n).ID = n;
    X(n).tsk = [];
    X(n).v = find(V(n,:));
    X(n).list = [];
    X(n).score = [];
    X(n).index = [];
    X(n).uCounter = 0;
end
%% inizializzazione patroling:
%genera un task di patroling per ogni area:
for m = 1 : M
    pool(m) = newTask(0,inf,'pat',m);
end

%% simulazione:
newOccurrence = true;   %flag che memorizza un nuovo arrivo di task (anche completamento)
for t = time
	%resetta newOccurrence se t>0:
    if t==0, newOccurrence = true; else newOccurrence = false; end
    %vettori delle occorrenze dei task:
    event.op = find(R.op(:,1)>(t-Ts) & R.op(:,1)<=t);
    event.trk = find(R.trk(:,1)>(t-Ts) & R.trk(:,1)<=t);
    event.str = find(R.str(:,1)>(t-Ts) & R.str(:,1)<=t);
    % aggiornamento del pool con i nuovi task:
    if ~isempty(event.op)
        for j = 1 : length(event.op)
            pool(end+1) = newTask(t,R.op(event.op(j),2),'op',R.op(event.op(j),3));
            message('New Task:'); message(pool(end));
            newOccurrence = true;
        end
    end
    if ~isempty(event.trk)
        for j = 1 : length(event.trk)
            pool(end+1) = newTask(t,R.trk(event.trk(j),2),'trk',R.trk(event.trk(j),3));
            message('New Task:'); message(pool(end));
            newOccurrence = true;
        end
    end
    if ~isempty(event.str)
        for j = 1 : length(event.str)
            pool(end+1) = newTask(t,R.str(event.str(j),2),'str',R.str(event.str(j),3));
            message('New Task:'); message(pool(end));
            newOccurrence = true;
        end
    end
    
    timeManagement; %effettua aggiornamento tempo di servizio e eventuale drop
    
    if newOccurrence    % se sono arrivati nuovi task
        
%%% ALGORITMO DI ASSEGNAZIONE: ===========================================
        % esegui riassegnazione:
        taskSelection;              % SMTI REVISED
%         taskSelectionGreedy;        % GREEDY ALGORITHM
%         taskSelectionPureRandom;    % NEARLY BRUTE FORCE
%         taskSelectionRandom;        % RANDOMIZED SMTI REVISED
%         centralAssignmentABC;       % ASSEGNAZIONE CENTRALIZZATA
%%% =====================================================================
        
        taskViewer;     % aggiorna interfaccia grafica
    end
    
    % verifica presenza di agenti IDLE:
    if sum([pool.a]>0) < N,
        message(['Agenti IDLE!']);
        message([pool.a]);
    end
end

% mov = close(mov); %chiude file avi
