function [organismSimulation]  = FBA_EB_applyRegulationAndBounds(tStep, iSim, organism, ...
                                                        organismMedia,simulationStimuli)
% Author: Elsa W. Birch, ewbirch@stanford.edu, Covert Lab - Stanford Bioengineering
% Date: 4/24/2011
% Version: associated with production of the figures for Birch et al. 2012
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
%
% Summary: Function to handle updating the state of FBA organism structure before a dynamic FBA step is completed. 
%		   Sets the regulatory state as informed by the previous itteration, as well as the current flux bounds 
%		   as determined by avalibility of resources in media and regulation booleans.
% 
%
% Inputs: organism - Organism definition, and simulation, structure
%		  tStep - timestep length, as a 1x1 matrix
%		  iSim - itteration number to denote the current state stored in organism, as a 1x1 integer
%		  organismMedia - The effective media avalible to this organism, provide limits of 
%						  nutritional resource and inform regulation. 
%						  Expected in the units of [].
%						  Note that in the case of multiple organism in the media this is the portion 
% 						  of the total media concentration that is avalible to this organism, as determinded 
%						  by whatever allocation method is being implemented. Take care for nonzero regulation thresholds.
%
% Outputs: organismSimulation - state structure for organism, updated with regulatory and flux bound constraints.
%
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
%
% Notes: 
%
%
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

% Update regulation
[organism.simulation.tfs(:,iSim), ...
 organism.simulation.genes(:,iSim), ...
 organism.simulation.geneProducts(:,iSim) ] = ...
    FBA_EB_setCurrentRegulation(tStep,iSim,organism,organismMedia,organism.model.stimuliValuesDefault);

% Set conditional flux bounds
fluxBoundsWithConditions = FBA_EB_setCurrentConditionalFluxBounds( organism.model.fluxBoundsDefault,...
    organism.model.fluxBoundsConditional ,organismMedia, organism.simulation.tfs(:, iSim) ,...
    organism.simulation.geneProducts(:, iSim), organism.model.stimuliValuesDefault, organism.simulation.fluxes(:,iSim) );

% Update flux bounds based on regulation                      
[fluxBoundsRegulation, rxnRegulation] = FBA_EB_setCurrentRegulationFluxBounds(organism.simulation.geneProducts(:,iSim),...
    organismMedia, fluxBoundsWithConditions , organism.model.rxnRegulationRulesEvalStrings);                 

% Update flux bounds based on nutrient avalibility  
fluxBoundsCurrent = FBA_EB_setCurrentExchangeFluxBounds(tStep, ...
                                organism.simulation.biomass(iSim-1), ...
                                organismMedia, ...
                                fluxBoundsRegulation, ...
                                organism.model.mediaExchangeRxnIdxList);


% Check consistancy of bounds, round to zero if conflict, and add warning
idxBoundsConflict = find(  (fluxBoundsCurrent(:,2) - fluxBoundsCurrent(:,1)) < 0 );
if ~isempty(idxBoundsConflict)
    % add warnigns for any changes that are being made to bounds
    for iWarn = 1 : length( idxBoundsConflict )
        warningToAdd = ['bounds changed at iter',num2str(iSim),', flux ',...
            organism.modelInfected.rxnList{idxBoundsConflict(iWarn)},...
            ': [',num2str(fluxBoundsCurrent(idxBoundsConflict(iWarn)),1),', ',...
            num2str(fluxBoundsCurrent(idxBoundsConflict(iWarn),2)),'] to [0, 0]' ];
        warningsStrings = [warningsStrings; {warningToAdd}];
    end % for iWarn
    % set conflicted bounds to zero
    fluxBoundsCurrent(idxBoundsConflict,1) = zeros( size(idxBoundsConflict));
    fluxBoundsCurrent(idxBoundsConflict,2) = zeros( size(idxBoundsConflict));
end %
                            
% Store for output
if organism.infectionFlag && ~isfield(organism.model,'nViralRxns')
    % This is the case when the method is being called for the uninfected model, but
    % simulation was initialized as infected. Required for calculating host supply before allocation to viral reactions.
    organism.simulation.fluxBoundsLower(1:length(fluxBoundsCurrent),iSim) = fluxBoundsCurrent(:,1);
    organism.simulation.fluxBoundsUpper(1:length(fluxBoundsCurrent),iSim) = fluxBoundsCurrent(:,2);
    organism.simulation.rxnRegulation(1:length(fluxBoundsCurrent),iSim) = rxnRegulation;
    organismSimulation = organism.simulation; % cannot pass structure ref as output?
else
    % most cases
    organism.simulation.fluxBoundsLower(:,iSim) = fluxBoundsCurrent(:,1);
    organism.simulation.fluxBoundsUpper(:,iSim) = fluxBoundsCurrent(:,2);
    organism.simulation.rxnRegulation(:,iSim) = rxnRegulation;
    organismSimulation = organism.simulation; % cannot pass structure ref as output?

end % infected but only host being treated (initialization)

end % function FBA_EB_applyRegulationAndBounds
