function [mmpc_u0, mmpc_mvseq, mmpc_xseq, mmpc_yseq, mmpc_state, mmpc_ts] = mmpcblock_MaskInitFcnResize(blk)
% MPC_BLOCK_RESIZE_MULTIPLE Modify the I/O structure depending on whether
% MDs, and time-varying LIMITS are present.

%   Author: A. Bemporad
%   Copyright 1986-2011 The MathWorks, Inc.

%% Obtain block parameters
% mpc controllers
names = strtrim(get_param(blk,'mpcobjs'));
if isempty(names)
    return
end
try
    % Load from workspace
    currmpcobjs = slResolve(names,blk);
catch ME
    throw(ME);
end
currmpcobjs = controllib.internal.util.hString2Char(currmpcobjs);
if iscell(currmpcobjs)
    if all(cellfun('isclass',currmpcobjs,'char'))
        % names is a cell array of strings, each represents a mpc variable
        IsObjectMPC = false;
    elseif all(cellfun('isclass',currmpcobjs,'mpc'))
        % names is a variable that represents a cell array of mpc objects
        IsObjectMPC = true;
    else
        ctrlMsgUtils.error('MPC:designtool:BadCellArrayController');
    end    
else
    ctrlMsgUtils.error('MPC:designtool:BadCellArrayController');
end    
% initial states
states = strtrim(get_param(blk,'x0s'));
try
    % Load from workspace
    currmpcx0s = slResolve(states,blk);
catch ME
    throw(ME);
end
currmpcx0s = controllib.internal.util.hString2Char(currmpcx0s);
if iscell(currmpcx0s)
    if all(cellfun('isclass',currmpcx0s,'char')) || all(cellfun('isempty',currmpcx0s))
        % names is a cell array of strings, each represents a state variable or []
        IsObjectState = false;
    elseif all(cellfun('isclass',currmpcx0s,'mpcstate'))
        % names is a variable that represents a cell array of mpcstate objects
        IsObjectState = true;
    else
        ctrlMsgUtils.error('MPC:designtool:BadCellArrayState');
    end    
else
    ctrlMsgUtils.error('MPC:designtool:BadCellArrayState');
end    
% others
currmpcnmv = eval(get_param(blk,'nmv'));
currmpcnmo = eval(get_param(blk,'nmo'));
currmpcnmd = eval(get_param(blk,'nmd'));
currmpcnts = eval(get_param(blk,'nts'));
currmpcstateest = get_param(blk,'state_inport_multiple');
currmpcdatatype = get_param(blk,'BlockDataType_multiple');
currmpcsampletimeinherited = get_param(blk,'SampleTimeInherited_multiple');

%% Obtain current availability of the optional in/out ports in the block
AvailableBlocks = get_param(blk,'Blocks');
type_in_block = ismember({'md','ext.mv','umin','umax','ymin','ymax','y.wt','u.wt','du.wt','ecr.wt','mv.target'},AvailableBlocks);
type_out_block = ismember({'cost','mv.seq','x.seq','y.seq','qp.status','est.state'},AvailableBlocks);

%% Obtain availability of the optional in/out ports from the block dialog
type_in_mask = [...
                strcmp(get_param(blk,'md_inport_multiple'),'on'), ...
                strcmp(get_param(blk,'mv_inport_multiple'),'on'),...
                strcmp(get_param(blk,'umin_inport_multiple'),'on'),...
                strcmp(get_param(blk,'umax_inport_multiple'),'on'),...
                strcmp(get_param(blk,'ymin_inport_multiple'),'on'),...
                strcmp(get_param(blk,'ymax_inport_multiple'),'on'),...
                strcmp(get_param(blk,'ywt_inport_multiple'),'on'),...
                strcmp(get_param(blk,'uwt_inport_multiple'),'on'),...
                strcmp(get_param(blk,'duwt_inport_multiple'),'on'),...
                strcmp(get_param(blk,'rhoeps_inport_multiple'),'on'),...
                strcmp(get_param(blk,'uref_inport_multiple'),'on'),...                
                ];
type_out_mask = [...
                strcmp(get_param(blk,'return_cost_multiple'),'on'),...
                strcmp(get_param(blk,'return_mvseq_multiple'),'on'), ...
                strcmp(get_param(blk,'return_xseq_multiple'),'on'), ...
                strcmp(get_param(blk,'return_ovseq_multiple'),'on'), ...
                strcmp(get_param(blk,'return_qpstatus_multiple'),'on'), ...
                strcmp(get_param(blk,'return_state_multiple'),'on'), ...
                ];
                    
%% Update MO or X
maskdisplay=get_param(blk,'MaskDisplay');
CustomEstimation = strcmp(get_param(blk,'state_inport_multiple'),'on');
if CustomEstimation
    label = '''mo''';
    pos = strfind(maskdisplay, label);
    if ~isempty(pos)
        % Change mo inport to x inport
        maskdisplay = [maskdisplay(1:pos-1),'''x[k|k]''',maskdisplay(pos+length(label):end)];
    end
else
    label = '''x[k|k]''';
    pos = strfind(maskdisplay, label);
    if ~isempty(pos)
        % Change x inport to mo inport
        maskdisplay = [maskdisplay(1:pos-1),'''mo''',maskdisplay(pos+length(label):end)];
    end
end

%% Reset mask display to two inports (MO, REF) and one outport (MV)
aux='port_label(''input'', 3, ''ref'')';
pos=strfind(maskdisplay,aux)+length(aux);
maskdisplay=maskdisplay(1:pos-1);
nextInport = 4;
nextOutport = 2;

%% Update MD
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,1,'md',nextInport,3,maskdisplay);

%% Update EXT.MV
if type_in_mask(2)
    if ~type_in_block(2)
        % add inport
        delete_line(blk,'u[k-1]/1','Goto 4/1');
        add_block([blk '/ref'],[blk '/ext.mv']);
        add_line(blk,'ext.mv/1','Goto 4/1');
        set_param([blk '/ext.mv'],'position',[870   595   890   615],'orientation','left','port',int2str(nextInport));
    end
    set_param([blk '/ext.mv'],'icondisplay','port number');
    maskdisplay=[maskdisplay newline 'port_label(''input'', ' num2str(nextInport) ', ''ext.mv'')'];
    nextInport = nextInport + 1;
else
    if type_in_block(2)
        % remove inport
        if ismember('ext.mv',AvailableBlocks)
            delete_line(blk,'ext.mv/1','Goto 4/1');
            delete_block([blk '/ext.mv']);
            add_line(blk,'u[k-1]/1','Goto 4/1','autorouting','on');
        end
    end
end

%% Update LIMITS
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,3,'umin',nextInport,5,maskdisplay);
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,4,'umax',nextInport,6,maskdisplay);
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,5,'ymin',nextInport,7,maskdisplay);
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,6,'ymax',nextInport,8,maskdisplay);

%% Update YWT
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,7,'y.wt',nextInport,10,maskdisplay);

%% Update UWT
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,8,'u.wt',nextInport,11,maskdisplay);

%% Update DUWT
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,9,'du.wt',nextInport,12,maskdisplay);

%% Update RHOEPS
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,10,'ecr.wt',nextInport,13,maskdisplay);

%% Update UREF
[maskdisplay, nextInport] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,11,'mv.target',nextInport,14,maskdisplay);

%% Update COST
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,1,'cost',nextOutport,maskdisplay);

%% Update MV SEQUENCE
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,2,'mv.seq',nextOutport,maskdisplay);

%% Update X SEQUENCE
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,3,'x.seq',nextOutport,maskdisplay);

%% Update Y SEQUENCE
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,4,'y.seq',nextOutport,maskdisplay);

%% Update QPSTATUS
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,5,'qp.status',nextOutport,maskdisplay);

%% Update Estimated State
[maskdisplay, nextOutport] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,6,'est.state',nextOutport,maskdisplay);

%% Update Mask Display
set_param(blk,'MaskDisplay',maskdisplay);

%% Obtain MPC1 position
position = get_param([blk '/MPC1'],'Position');

%% Now set correct dimensions for zero signals
% if any MPC controller is defined in the MMPC block, try to get it from
% base workspace. If failed, use defaults.  If no controller is defined,
% use defaults.
[Successful, nu, ny, nmd, mmpc_ts, p, nx, nxQP] = mpc_getdimensions_multiple(blk, currmpcobjs{1});
if ~Successful
    nu = currmpcnmv;
    ny = currmpcnmo;
    nmd = currmpcnmd;
    mmpc_ts = currmpcnts;
end
DataType = get_param(blk,'BlockDataType_multiple');
mmpc_u0 = zeros(nu,1,DataType);
mmpc_mvseq = zeros(p+1,nu,DataType);
mmpc_xseq = zeros(p+1,nxQP,DataType);
mmpc_yseq = zeros(p+1,ny,DataType);
mmpc_state = zeros(nx,1,DataType);
if strcmp(get_param(blk,'SampleTimeInherited_multiple'),'on')
    mmpc_ts = -1;
end
AvailableBlocks = get_param(blk,'Blocks');
if ismember('md_zero',AvailableBlocks)
    set_param([blk '/md_zero'],'Value',sprintf('zeros(%d,1)',max(nmd,1)));
end
if ismember('umin_zero',AvailableBlocks)
    set_param([blk '/umin_zero'],'Value',sprintf('zeros(%d,1)',nu));
end
if ismember('umax_zero',AvailableBlocks)
    set_param([blk '/umax_zero'],'Value',sprintf('zeros(%d,1)',nu));
end
if ismember('ymin_zero',AvailableBlocks)
    set_param([blk '/ymin_zero'],'Value',sprintf('zeros(%d,1)',ny));
end
if ismember('ymax_zero',AvailableBlocks)
    set_param([blk '/ymax_zero'],'Value',sprintf('zeros(%d,1)',ny));
end
if ismember('y.wt_zero',AvailableBlocks)
    set_param([blk '/y.wt_zero'],'Value',sprintf('zeros(%d,1)',ny));
end
if ismember('u.wt_zero',AvailableBlocks)
    set_param([blk '/u.wt_zero'],'Value',sprintf('zeros(%d,1)',nu));
end
if ismember('du.wt_zero',AvailableBlocks)
    set_param([blk '/du.wt_zero'],'Value',sprintf('zeros(%d,1)',nu));
end
if ismember('ecr.wt_zero',AvailableBlocks)
    set_param([blk '/ecr.wt_zero'],'Value',sprintf('zeros(%d,1)',1));
end
if ismember('mv.target_zero',AvailableBlocks)
    set_param([blk '/mv.target_zero'],'Value',sprintf('zeros(%d,1)',nu));
end

%% Add or remove MPC blocks if the number of MPC controllers is changed
% Required number of MPC blocks from mask parameter
N = length(currmpcobjs);
% Current number of MPC blocks in the block
oldN = str2double(get_param([blk '/mv_switch'],'Inputs'))-1; % the last input the 
% detect whether a MPC block should be added or deleted
dN = N-oldN; 
% Because of the Add/Delete buttons, dN = N-oldN is either 0, 1 or -1. But
% the code below works for any dN.
if dN>0
    %% add MPC controllers
    addMPCBlock(blk, N, oldN, position)
elseif dN<0
    %% remove MPC controllers
    theMPC = str2double(get_param(blk,'theMPC'));
    if theMPC>0
        % delete from delete button
        % Delete MPC controllers indexed by 'theMPC'
        deleteMPCBlock(blk, theMPC, N, oldN, position);
    else
        % delete blocks from canceling dialog
        for ct = N:-1:N+dN+1
            deleteMPCBlock(blk, ct, N, oldN, position);
        end
    end
end
%% always update internal wiring of optional outputs (using try-catch)
update_mvseq(blk, N);
update_xseq(blk, N);
update_ovseq(blk, N);
update_eststate(blk, N);

%% Update mask parameters for each MPC block based on mmpc values
% we only loop through minimum of N, length of mpcobjs and length of x0s to
% avoid set_param failure (which does not generate hard error).  In normal
% cases these values are the same.  When 'add' button is clicked, N is
% updated first, then mocobjs, then x0s so at different moments the values
% are different.  In the end they will be the same after all the set_param
% references are executed in the 'add' button callback.
for ct = 1:min(min(N,length(currmpcobjs)),length(currmpcx0s))
    mpcblk = [blk '/MPC' num2str(ct)];
    if IsObjectMPC
        mpcname = [names '{' num2str(ct) '}'];
    else
        mpcname = currmpcobjs{ct};
    end
    if IsObjectState
        statename = [states '{' num2str(ct) '}'];
    else
        if isempty(currmpcx0s{ct})
            statename = '[]';
        else
            statename = currmpcx0s{ct};
        end
    end
    set_param(mpcblk,'mpcobj',mpcname,...
                     'x0',statename,...
                     'state_inport',currmpcstateest,...
                     'BlockDataType',currmpcdatatype,...
                     'n_mv',num2str(currmpcnmv),...
                     'n_mo',num2str(currmpcnmo),...
                     'n_md',num2str(currmpcnmd),...
                     'n_ts',num2str(currmpcnts),...
                     'SampleTimeInherited',currmpcsampletimeinherited);
end
%% End of main function

function delete_inport(blk,name,outport)
inportblk = [blk '/' name];
constantblk = [blk '/' name '_zero']; 
delete_line(blk,[name '/1'],outport);
position = get_param(inportblk,'position');
delete_block(inportblk);
add_block('built-in/Constant',constantblk);
add_line(blk,[name '_zero/1'],outport);
set_param(constantblk,'position',position,'orientation','left','OutDataTypeStr','BlockDataType_multiple');

function add_inport(blk,name,port,outport)
inportblk = [blk '/' name];
constantblk = [blk '/' name '_zero']; 
delete_line(blk,[name '_zero/1'],outport);
position = get_param(constantblk,'position');
delete_block(constantblk);
add_block([blk '/ref'],inportblk);
add_line(blk,[name '/1'],outport);
set_param(inportblk,'position',position,'orientation','left','port',num2str(port));

function [maskdisplay, port] = update_inport(blk,AvailableBlocks,type_in_mask,type_in_block,index,name,port,outport,maskdisplay)
if type_in_mask(index)
    if ~type_in_block(index)
        add_inport(blk,name,port,['Goto ' num2str(outport) '/1']);
    end
    set_param([blk '/' name],'icondisplay','port number');    
    maskdisplay=[maskdisplay newline 'port_label(''input'', ' num2str(port) ', ''' name ''')'];
    port = port + 1;
else
    if type_in_block(index)
        if ismember(name,AvailableBlocks)
            delete_inport(blk,name,['Goto ' num2str(outport) '/1']);
        end
    end
end

function delete_outport(blk,name,inport)
outportblk = [blk '/' name];
terminatorblk = [blk '/' name '_terminator']; 
delete_line(blk,inport,[name '/1']);
position = get_param(outportblk,'position');
delete_block(outportblk);
add_block('built-in/Terminator',terminatorblk);
add_line(blk,inport,[name '_terminator/1']);
set_param(terminatorblk,'position',position,'Orientation','left');

function add_outport(blk,name,port,inport)
outportblk = [blk '/' name];
terminatorblk = [blk '/' name '_terminator']; 
delete_line(blk,inport,[name '_terminator/1']);
position = get_param(terminatorblk,'position');
delete_block(terminatorblk);
add_block([blk '/mv'],outportblk);
add_line(blk,inport,[name '/1']);
set_param(outportblk,'position',position,'orientation','left','port',int2str(port));

function [maskdisplay, port] = update_outport(blk,AvailableBlocks,type_out_mask,type_out_block,index,name,port,maskdisplay)
if type_out_mask(index)
    if ~type_out_block(index)
        add_outport(blk,name,port,[name '_switch/1']);
    end
    set_param([blk '/' name],'icondisplay','port number');    
    maskdisplay=[maskdisplay newline 'port_label(''output'', ' num2str(port) ', ''' name ''')'];
    port = port + 1;
else
    if type_out_block(index)
        if ismember(name,AvailableBlocks)
            delete_outport(blk,name,[name '_switch/1']);
        end
    end
end

function update_eststate(blk, oldN)
if strcmp(get_param(blk,'return_state_multiple'),'on')
    % if estimated states outport enabled, replace constant with mpc signal
    for ct=1:oldN
        try %#ok<*TRYNC>
            delete_line(blk,'est.state_zero/1',['est.state_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,['MPC' num2str(ct) '/7'],['est.state_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
else
    % if estimated states outport disabled, replace mpc signal with constant
    for ct=1:oldN
        try
            delete_line(blk,['MPC' num2str(ct) '/7'],['est.state_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,'est.state_zero/1',['est.state_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
end

function update_mvseq(blk, oldN)
if strcmp(get_param(blk,'return_mvseq_multiple'),'on')
    % if mv.seq outport enabled, replace constant with mpc signal
    for ct=1:oldN
        try
            delete_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,['MPC' num2str(ct) '/3'],['mv.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
else
    % if mv.seq outport disabled, replace mpc signal with constant
    for ct=1:oldN
        try
            delete_line(blk,['MPC' num2str(ct) '/3'],['mv.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
end

function update_xseq(blk, oldN)
if strcmp(get_param(blk,'return_xseq_multiple'),'on')
    % if x.seq outport enabled, replace constant with mpc signal
    for ct=1:oldN
        try
            delete_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,['MPC' num2str(ct) '/4'],['x.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
else
    % if x.seq outport disabled, replace mpc signal with constant
    for ct=1:oldN
        try
            delete_line(blk,['MPC' num2str(ct) '/4'],['x.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
end

function update_ovseq(blk, oldN)
if strcmp(get_param(blk,'return_ovseq_multiple'),'on')
    % if y.seq outport enabled, replace constant with mpc signal
    for ct=1:oldN
        try
            delete_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,['MPC' num2str(ct) '/5'],['y.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
else
    % if y.seq outport disabled, replace mpc signal with constant
    for ct=1:oldN
        try
            delete_line(blk,['MPC' num2str(ct) '/5'],['y.seq_switch/',num2str(ct+1)]);
        end
        try
            add_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(ct+1)],'autorouting','on');
        end
    end
end

%---------------
function addMPCBlock(blk, N, oldN, position)
% delete the default signal from the old last data port
delete_line(blk,'u[k-1]/1',['mv_switch/' num2str(oldN+2)]);
delete_line(blk,'cost_zero/1',['cost_switch/' num2str(oldN+2)]);
delete_line(blk,'mv.seq_zero/1',['mv.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'x.seq_zero/1',['x.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'y.seq_zero/1',['y.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'qp.status_zero/1',['qp.status_switch/' num2str(oldN+2)]);
delete_line(blk,'est.state_zero/1',['est.state_switch/' num2str(oldN+2)]);
delete_line(blk,'u0_zero/1',['u0_switch/' num2str(oldN+2)]);
% change number of inputs
set_param([blk '/mv_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/cost_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/mv.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/x.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/y.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/qp.status_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/est.state_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/u0_switch'],'Inputs',num2str(N+1)); % N>1
% add the default signal to the new last data port
add_line(blk,'u[k-1]/1',['mv_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'cost_zero/1',['cost_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'mv.seq_zero/1',['mv.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'x.seq_zero/1',['x.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'y.seq_zero/1',['y.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'qp.status_zero/1',['qp.status_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'est.state_zero/1',['est.state_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'u0_zero/1',['u0_switch/' num2str(N+2)],'autorouting','on');
% Create dN new MPC controllers
for i=oldN+1:N
    % Copy MPC block MPC1 into a new one
    MPCname = sprintf('MPC%d',i);
    add_block([blk '/MPC1'],[blk '/' MPCname]);
    set_param([blk '/' MPCname],'Position',position+10*(i-1),'enable_value',num2str(i),'mpcobj','');
    % Connect from MPC block
    % 1
    add_line(blk,[MPCname '/1'],['mv_switch/',num2str(i+1)],'autorouting','on');
    % 2
    add_line(blk,[MPCname '/2'],['cost_switch/',num2str(i+1)],'autorouting','on');
    % 3: special treatment for mv.seq
    % add terminator block
    add_block([blk '/mv.seq_MPC1'],[blk '/mv.seq_' MPCname]);
    add_line(blk,[MPCname '/3'],['mv.seq_' MPCname '/1'],'autorouting','on');
    % connect mpc or constant to switch
    if strcmp(get_param(blk,'return_mvseq_multiple'),'on')
        add_line(blk,[MPCname '/3'],['mv.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 4: special treatment for x.seq
    % add terminator block
    add_block([blk '/x.seq_MPC1'],[blk '/x.seq_' MPCname]);
    add_line(blk,[MPCname '/4'],['x.seq_' MPCname '/1'],'autorouting','on');
    % connect mpc or constant to switch
    if strcmp(get_param(blk,'return_xseq_multiple'),'on')
        add_line(blk,[MPCname '/4'],['x.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 5: special treatment for y.seq
    % add terminator block
    add_block([blk '/y.seq_MPC1'],[blk '/y.seq_' MPCname]);
    add_line(blk,[MPCname '/5'],['y.seq_' MPCname '/1'],'autorouting','on');
    % connect mpc or constant to switch
    if strcmp(get_param(blk,'return_ovseq_multiple'),'on')
        add_line(blk,[MPCname '/5'],['y.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 6
    add_line(blk,[MPCname '/6'],['qp.status_switch/',num2str(i+1)],'autorouting','on');
    % 7: special treatment for est.state
    % add terminator block
    add_block([blk '/est.state_MPC1'],[blk '/est.state_' MPCname]);
    add_line(blk,[MPCname '/7'],['est.state_' MPCname '/1'],'autorouting','on');
    % connect mpc or constant to switch
    if strcmp(get_param(blk,'return_state_multiple'),'on')
        add_line(blk,[MPCname '/7'],['est.state_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'est.state_zero/1',['est.state_switch/',num2str(i+1)],'autorouting','on');
    end
    % 8
    add_line(blk,[MPCname '/8'],['u0_switch/',num2str(i+1)],'autorouting','on');
    % Connect to MPC block
    for j=1:14
        add_line(blk,sprintf('From %d/1',j),[MPCname sprintf('/%d',j)],'autorouting','on');
    end
end

function deleteMPCBlock(blk, theMPC, N, oldN, position)
% which block to delete
MPCname = sprintf('MPC%d',theMPC);
% delete connections to MPC block
for j=1:14
    delete_line(blk,sprintf('From %d/1',j),[MPCname sprintf('/%d',j)]);
end
% Delete connections from MPC block
% 1
delete_line(blk,[MPCname '/1'],['mv_switch/' num2str(theMPC+1)]);
% 2
delete_line(blk,[MPCname '/2'],['cost_switch/' num2str(theMPC+1)]);
% 3: special treatment for mv.seq
% delete terminator block
delete_line(blk,[MPCname '/3'],['mv.seq_' MPCname '/1']);
delete_block([blk '/mv.seq_' MPCname]);
% delete line from either mpc or constant
if strcmp(get_param(blk,'return_mvseq_multiple'),'on')
    delete_line(blk,[MPCname '/3'],['mv.seq_switch/',num2str(theMPC+1)]);
else
    delete_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(theMPC+1)]);
end
% 4: special treatment for x.seq
% delete terminator block
delete_line(blk,[MPCname '/4'],['x.seq_' MPCname '/1']);
delete_block([blk '/x.seq_' MPCname]);
% delete line from either mpc or constant
if strcmp(get_param(blk,'return_xseq_multiple'),'on')
    delete_line(blk,[MPCname '/4'],['x.seq_switch/',num2str(theMPC+1)]);
else
    delete_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(theMPC+1)]);
end
% 5: special treatment for y.seq
% delete terminator block
delete_line(blk,[MPCname '/5'],['y.seq_' MPCname '/1']);
delete_block([blk '/y.seq_' MPCname]);
% delete line from either mpc or constant
if strcmp(get_param(blk,'return_ovseq_multiple'),'on')
    delete_line(blk,[MPCname '/5'],['y.seq_switch/',num2str(theMPC+1)]);
else
    delete_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(theMPC+1)]);
end
% 6
delete_line(blk,[MPCname '/6'],['qp.status_switch/' num2str(theMPC+1)]);
% 7: special treatment for est.state
% delete terminator block
delete_line(blk,[MPCname '/7'],['est.state_' MPCname '/1']);
delete_block([blk '/est.state_' MPCname]);
% delete line from either mpc or constant
if strcmp(get_param(blk,'return_state_multiple'),'on')
    delete_line(blk,[MPCname '/7'],['est.state_switch/',num2str(theMPC+1)]);
else
    delete_line(blk,'est.state_zero/1',['est.state_switch/',num2str(theMPC+1)]);
end
% 8
delete_line(blk,[MPCname '/8'],['u0_switch/' num2str(theMPC+1)]);
% Delete MPC block
delete_block([blk '/' MPCname]);
% Rename other MPC blocks from theMPC+1 to the last one and remove
% connection to switches
for i = theMPC+1:oldN
    % block to be renamed
    MPCname = sprintf('MPC%d',i); 
    % 1
    delete_line(blk,[MPCname '/1'],['mv_switch/' num2str(i+1)]);
    % 2
    delete_line(blk,[MPCname '/2'],['cost_switch/' num2str(i+1)]);
    % 3: delete line from either mpc or constant to mv.seq switch
    if strcmp(get_param(blk,'return_mvseq_multiple'),'on')
        delete_line(blk,[MPCname '/3'],['mv.seq_switch/',num2str(i+1)]);
    else
        delete_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(i+1)]);
    end
    % 4: delete line from either mpc or constant to x.seq switch
    if strcmp(get_param(blk,'return_xseq_multiple'),'on')
        delete_line(blk,[MPCname '/4'],['x.seq_switch/',num2str(i+1)]);
    else
        delete_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(i+1)]);
    end
    % 5: delete line from either mpc or constant to y.seq switch
    if strcmp(get_param(blk,'return_ovseq_multiple'),'on')
        delete_line(blk,[MPCname '/5'],['y.seq_switch/',num2str(i+1)]);
    else
        delete_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(i+1)]);
    end
    % 6
    delete_line(blk,[MPCname '/6'],['qp.status_switch/' num2str(i+1)]);
    % 7: delete line from either mpc or constant to est.state switch
    if strcmp(get_param(blk,'return_state_multiple'),'on')
        delete_line(blk,[MPCname '/7'],['est.state_switch/',num2str(i+1)]);
    else
        delete_line(blk,'est.state_zero/1',['est.state_switch/',num2str(i+1)]);
    end
    % 8
    delete_line(blk,[MPCname '/8'],['u0_switch/' num2str(i+1)]);
    % name
    newMPCname = sprintf('MPC%d',i-1); % new name
    set_param([blk '/' MPCname],'Name',newMPCname);
    % rename mv.seq terminator block
    set_param([blk '/mv.seq_' MPCname],'Name',['mv.seq_' newMPCname]);
    % rename x.seq terminator block
    set_param([blk '/x.seq_' MPCname],'Name',['x.seq_' newMPCname]);
    % rename mv.seq terminator block
    set_param([blk '/y.seq_' MPCname],'Name',['y.seq_' newMPCname]);
    % rename est.state terminator block
    set_param([blk '/est.state_' MPCname],'Name',['est.state_' newMPCname]);
end
% delete the default signal from the old last data port
delete_line(blk,'u[k-1]/1',['mv_switch/' num2str(oldN+2)]);
delete_line(blk,'cost_zero/1',['cost_switch/' num2str(oldN+2)]);
delete_line(blk,'mv.seq_zero/1',['mv.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'x.seq_zero/1',['x.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'y.seq_zero/1',['y.seq_switch/' num2str(oldN+2)]);
delete_line(blk,'qp.status_zero/1',['qp.status_switch/' num2str(oldN+2)]);
delete_line(blk,'est.state_zero/1',['est.state_switch/' num2str(oldN+2)]);
delete_line(blk,'u0_zero/1',['u0_switch/' num2str(oldN+2)]);
% change number of inputs
set_param([blk '/mv_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/cost_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/mv.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/x.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/y.seq_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/qp.status_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/est.state_switch'],'Inputs',num2str(N+1)); % N>1
set_param([blk '/u0_switch'],'Inputs',num2str(N+1)); % N>1
% add the default signal to the new last data port
add_line(blk,'u[k-1]/1',['mv_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'cost_zero/1',['cost_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'mv.seq_zero/1',['mv.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'x.seq_zero/1',['x.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'y.seq_zero/1',['y.seq_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'qp.status_zero/1',['qp.status_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'est.state_zero/1',['est.state_switch/' num2str(N+2)],'autorouting','on');
add_line(blk,'u0_zero/1',['u0_switch/' num2str(N+2)],'autorouting','on');
% Reconnect remaining MPC blocks from theMPC+1 to the last one. 
% Parameter 'enable_value' is updated by the mask function
for i = theMPC:N
    % block to be reconnected
    MPCname = sprintf('MPC%d',i); 
    % 1
    add_line(blk,[MPCname '/1'],['mv_switch/' num2str(i+1)],'autorouting','on');
    % 2 
    add_line(blk,[MPCname '/2'],['cost_switch/',num2str(i+1)],'autorouting','on');
    % 3: add line from either mpc or constant to switch
    if strcmp(get_param(blk,'return_mvseq_multiple'),'on')
        add_line(blk,[MPCname '/3'],['mv.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'mv.seq_zero/1',['mv.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 4: add line from either mpc or constant to switch
    if strcmp(get_param(blk,'return_xseq_multiple'),'on')
        add_line(blk,[MPCname '/4'],['x.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'x.seq_zero/1',['x.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 5: add line from either mpc or constant to switch
    if strcmp(get_param(blk,'return_ovseq_multiple'),'on')
        add_line(blk,[MPCname '/5'],['y.seq_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'y.seq_zero/1',['y.seq_switch/',num2str(i+1)],'autorouting','on');
    end
    % 6
    add_line(blk,[MPCname '/6'],['qp.status_switch/',num2str(i+1)],'autorouting','on');
    % 7: add line from either mpc or constant to switch
    if strcmp(get_param(blk,'return_state_multiple'),'on')
        add_line(blk,[MPCname '/7'],['est.state_switch/',num2str(i+1)],'autorouting','on');
    else
        add_line(blk,'est.state_zero/1',['est.state_switch/',num2str(i+1)],'autorouting','on');
    end
    % 8
    add_line(blk,[MPCname '/8'],['u0_switch/',num2str(i+1)],'autorouting','on');
end
% Adjust enable_value and position of all MPC blocks in diagram
for i=1:N
    MPCname=sprintf('MPC%d',i);
    set_param([blk '/' MPCname],'enable_value',num2str(i),'Position',position+10*(i-1));
end
