function trial_data_output = Model(parameter,load,model)

%    This file is part of Model.
%
%    Model is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    Model 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.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with Model.  If not, see <http://www.gnu.org/licenses/>.

%% This function controls the encoding, storage, and retrieval of
% information.

% Setting up the presented items. Items are in degree values.
if parameter.fixed_item_space == 0
    %random item space
    % presented_items = randi(parameter.sensory_space,[1 load]);
    
    presented_items = zeros(1,load);
    
    for i = 1:load  
        
        possible_items = Shuffle(parameter.item_feature_range{load,i});
 %       presented_items(i) = possible_items(1);
    end
    
   presented_items = possible_items(1:load);
    
elseif parameter.fixed_item_space
    % Dissimilar item space
    
    % Pick a starting place
    starting_color = randi(parameter.sensory_space);
    
    % If this is change detection, we want to make to go ahead and choose
    % items that may or may not appear in the probe display
    if parameter.change_detection
        load_size = load + parameter.changed_items(load == parameter.setsize);
    else
        load_size = load;
    end
    
    for i = 1:load_size
        
        % If fixed items are determined by load_size
        if parameter.fixed_item_distance == 0
            presented_items(i) = (starting_color)+(parameter.sensory_space/load_size)*(i-1);
            
            % If this is a binding experiment, we want the items to be
            % categorically discrete
            if parameter.binding_experiment
                presented_items(i) = (parameter.sensory_space/parameter.type_size)*i;
            else
                % Adding a little noise
                presented_items(i) = randi(11)-6;
                
                % We don't want a negative degree value
                if presented_items(i) < 0
                    presented_items(i) = presented_items(i) + parameter.sensory_space;
                end
            end
        else % If fixed items are pre-determined
            degree_increment = (parameter.sensory_space/parameter.fixed_item_distance);
            
            if degree_increment == 1
                degree_increment = 0;
                
            end
            
            presented_items(i) = degree_increment*(i-1)+starting_color;
        end
        
        % Preventing presented items from exceeding 360
        if(presented_items(i) > parameter.sensory_space)
            presented_items(i) =   presented_items(i) - parameter.sensory_space;
        end
        
    end
    
    presented_items = Shuffle(presented_items);
    
end

% if load > 2
%     if length(unique(presented_items))~=length(presented_items)
%         keyboard
%     end
% end

% presented_items = 0;
% a = Shuffle([1:10]);
% presented_items = a(1:load)*36;

if parameter.allow_repeats
    for stim = 1:load
        presented_items(stim) = randi(10)*36;
    end
end

% This is specifically for Figures 10 and 14
if mean(parameter.magnet_tokens) ~= 0
    
    
    presented_items(1) = randi(36)+144;
    
    for i = 1:length(parameter.magnet_tokens)
        presented_items(i+1) = presented_items(1)+parameter.magnet_tokens(i);
    end
    
    % presented_items = Shuffle(presented_items);
    
end


type_resolution = ceil(parameter.sensory_space/parameter.type_size);

%Converting a stimulus value into type nodes. This equation is formalized
%in appendix
for i = 1:load
    
    type_space_location = presented_items(i) / type_resolution;
    
    
    type_node_1(i) = floor(type_space_location)+1;
    type_node_2(i) = ceil(type_space_location)+1;
    
    type_node_1_activition(i) = 1-(type_space_location -  floor(type_space_location));
    type_node_2_activition(i) = (type_space_location -  floor(type_space_location));
    
    if presented_items(i) == 360
        
        type_node_1(i) = 1;
        type_node_2(i) = 1;
        
    elseif presented_items(i) > (parameter.sensory_space - (parameter.sensory_space/parameter.type_size))
        
        type_node_1(i) = max(parameter.type_size);
        type_node_2(i) = 1;
        
    end
    
end


%% Setting up connections between the different layers
%model = Setupconn(parameter);

% Selects a capacity for this particular trial if there are no jumps
if parameter.capacitytop >0;
    
    %model.capacity = randi(parameter.capacity);
    
    capacity = Shuffle(parameter.capacitybottom:parameter.capacitytop);
    model.capacity = capacity(1);
    
    % To simulate Figures 10 and 14, we want each item to be encoded
    if mean(parameter.magnet_tokens) ~= 0
        model.capacity = length(parameter.magnet_tokens)+1;
    end
else
    model.capacity = parameter.token;
end

model.tokenhits = zeros(load,1);

whichtoken = 0;

%% Encoding phase

% The model will simply encodes each item equally until the amount of items exceeds the token
% capacity defined above.
if parameter.jumps ~= 0
    
    totaljumps = randi(parameter.jumps);
    
    for i = 1:(totaljumps*2)
        jumplist(i) = mod(i,load)+1;
    end
    
    jumplist = Shuffle(jumplist);
    
    for jumpcount = 1:totaljumps
        
        %      token = randi(load);
        token = jumplist(jumpcount);
        
        whichtoken(jumpcount) = token;
        
        model.tokenhits(token) =   model.tokenhits(token) + 1;
        
        type_input = zeros(1,parameter.type_size);
        
        type_input(type_node_1(token)) = type_node_1_activition(token);
        
        if type_node_1 ~= type_node_2
            type_input(type_node_2(token)) = type_node_2_activition(token);
        end
        
        type_2_input = zeros(parameter.type_2_size,1);
        type_2_input(token) = 1;
        
        
        % This function stores the activation in the Binding pool
        model = Storage(model,type_input,parameter,token,type_2_input);
        
    end
else
    for stimulicount = 1:load
        if model.capacity >= stimulicount
            
            token = stimulicount;
            model.tokenhits(token) =   model.tokenhits(token) + 1;
            
            type_input = zeros(1,parameter.type_size);
            
            type_input(type_node_1(token)) = type_node_1_activition(token);
            
            if type_node_1(token) ~= type_node_2(token)
                type_input(type_node_2(token)) = type_node_2_activition(token);
            end
            
            type_2_input = zeros(parameter.type_2_size,1);
            type_2_input(stimulicount) = 1;
            
            
            % This function stores the activation in the Binding pool
            model = Storage(model,type_input,parameter,stimulicount,type_2_input);
        end
    end
end

if parameter.cue_items == 1
    for stimulicount = parameter.cue_whichitem
        
        token = stimulicount;
        model.tokenhits(token) = model.tokenhits(token) + 1;
        
        type_input = zeros(1,parameter.type_size);
        
        type_input(type_node_1(token)) = type_node_1_activition(token);
        
        if type_node_1 ~= type_node_2
            type_input(type_node_2(token)) = type_node_2_activition(token);
        end
        
        type_2_input = zeros(parameter.type_2_size,1);
        type_2_input(stimulicount) = 1;
        
        
        % This function stores the activation in the Binding pool
        model = Storage(model,type_input,parameter,stimulicount,type_2_input);
        
    end
end

if parameter.directed_forgetting == 1
    
    type_2_activation = 2;   %which type node from Type2 will be active
    type_2_input = zeros(parameter.type_2_size,1);    %now create a vector
    type_2_input(type_2_activation) = 1;  %set the appropriate type node active
    
    retrieved_token_representation = Retrieve_token(model,parameter,0,type_2_input);
    
    [x retrieved_token] = max(retrieved_token_representation);

    token_weights = model.token_weight(retrieved_token,:);
    location_weights = model.type_2_weight(2,:);

    conjoined_weights = token_weights.*location_weights;
    
    %    model.bpnodes(find(connected_weights==1)) = model.bpnodes(find(connected_weights==1))/2;
    model.bpnodes(find(conjoined_weights==1)) = 0;
    
end

if parameter.normalize_bp == 1
    if sum(model.bpnodes) > 0
        model.bpnodes = model.bpnodes ./ sum(model.bpnodes);
    end
end

if sum(isnan(model.bpnodes)) > 0
    keyboard
end


%% Retrieval
% sprintf('**   %d,  ',model.tokenhits)
% parameter.guessing_threshold = 1.14 - .013 * load;  %ratio
for token = 1:load
    
    type_2_activation = token;   %which type node from Type2 will be active
    type_2_input = zeros(parameter.type_2_size,1);    %now create a vector
    type_2_input(type_2_activation) = 1;  %set the appropriate type node active
    
    if parameter.type_layer_2_status == 0
        trial_data(1,token).retrieved_token_representation = zeros(1,parameter.token);
        trial_data(1,token).retrieved_token_representation(token) = 1;
    else
        trial_data(1,token).retrieved_token_representation = Retrieve_token(model,parameter,0,type_2_input);
    end
    
    rep = trial_data(1,token).retrieved_token_representation(1:load);%./(tokenmeans(model.tokenhits+1)) %make a copy of the representation
    
    % which token is the highest and what is its value
    [x trial_data(1,token).retrieved_token] = max(rep);
    rep(trial_data(1,token).retrieved_token) = 0;
    
    nextbiggest = max(rep);
    
    
    % Does the token retrieval exceed the threshold?
    if x - nextbiggest  >= parameter.token_individuation_threshold
        % Yep. No guessing.
        trial_data(1,token).not_guess = 1;
        
        if parameter.no_type_cue == 1
            trial_data(1,token).retrieved_token = token;
        end
        
    else
        
        % Nope. Guessing.
        trial_data(1,token).not_guess = 0;
        trial_data(1,token).retrieved_token = 0;
        
    end
    
    trial_data(1,token).token = token;
    items = 1:load;
    trial_data(1,token).nontoken = items(items ~= token);
    trial_data(1,token).type_layer = 1:parameter.type_size;
    
    % Retrieving a type layer from the retrieved token
    trial_data(1,token).representation(:,1) = Retrieve(model,parameter,trial_data(1,token).retrieved_token,token);
    
    %     [a max_type] = max(trial_data(1,token).representation);
    %
    %     if load < 2 && max_type ~= type_node_1
    %        keyboard
    %     end
    
    
    
    %     presented_items(token)/36
    %     trial_data(1,token).representation(:,1)
    
    % Converting the retrieved activation to a single analog value.
    trial_data_output(1,token) = VectorMean(trial_data(1,token),parameter,presented_items,token);
    
    
end



end





