function buildLibrary(varargin)
% Function to update the library with all the methods functions.
%  $Id: buildLibrary.m,v 1.12 2009/01/22 21:40:14 nicola Exp $

%   clear all
  bdclose('all');
  disp('=====================================================')
  disp('Updating the LTPDA Library...');

% Retrieve the list of all functions and methods:
ltpda_versions

% This creates a variable named 'versions', so structured:
% | 1.filename | 2.functionName | 3.version | 4.date | 5.hour | 6.author | 7.folder | 8.hash | 9.category | 10.class |
% [The 'class' is set to None if it's not a method]

  origSize = size(versions,1); %#ok<NODEF>
  disp(['The overall number of LTPDA functions is ',num2str(origSize),'.'])


% =========================================================================
%%              Remove functions not meant for the library:
% =========================================================================

   % Remove all test functions:
     for i=origSize:-1:1
         if numel(versions{i,2})>4 && strcmpi(versions{i,2}(1:5),'test_')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' test functions ignored'])
     origSize = newSize;

   % Remove all Internal functions:
     for i=origSize:-1:1
         if numel(versions{i,9})>7 && strcmpi(versions{i,9}(1:8),'Internal')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' Internal functions ignored'])
     origSize = newSize;

   % Remove all private functions:
     for i=origSize:-1:1
         x = numel(versions{i,10});
         if x>8 && strcmpi(versions{i,10}(x-7:x),'/private')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' private functions ignored'])
     origSize = newSize;

   % Remove all remaining examples:
     for i=origSize:-1:1
         x = numel(versions{i,7});
         if x>10 && strcmpi(versions{i,7}(x-9:x),'/examples/')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' examples ignored'])
     origSize = newSize;

   % Remove templates:
     for i=origSize:-1:1
         funcName = versions{i,2};
         x = numel(funcName);
         if x>9 && strcmpi(funcName(x-8:x),'_template')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' templates ignored'])
     origSize = newSize;

   % Remove all uncategorized functions:
     for i=origSize:-1:1
         if isempty(versions{i,9})
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' uncategorized functions ignored'])
     origSize = newSize;

   % Remove all functions with category 'GUI function':
     for i=origSize:-1:1
         if strcmpi(versions{i,9},'GUI function')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' GUI functions ignored'])
     origSize = newSize;

   % Remove all functions with no class:
     for i=origSize:-1:1
         if strcmp(versions{i,10},'None')
             versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' functions with class ''None'' ignored'])
     origSize = newSize;
     
   % Remove all functions with non user classes:
     for i=origSize:-1:1
         if numel(versions{i,10})>5 && strncmpi(versions{i,10},'ltpda_',6)
            versions(i,:)=[];
         elseif numel(versions{i,10})>3 && strncmpi(versions{i,10},'data',4)
            versions(i,:)=[];
         end
     end
     newSize = size(versions,1);
     disp(['--- ',num2str(origSize-newSize),' functions with class ''ltpda_***'' ignored'])
     origSize = newSize;
% =========================================================================
%%                    Prepare the library for update:
% =========================================================================

    disp(['The number of LTPDA functions for the library is ',num2str(origSize),'.'])
       numbFunctions = 0;
       funcCategories = {};
       for i=1:origSize
           if numel(versions{i,10})>3 && strcmpi(versions{i,10}(1:4),'None')
               numbFunctions = numbFunctions +1;
               if ~ismember(versions{i,9},funcCategories)
                   funcCategories = [funcCategories,versions{i,9}];
               end
           end
       end
     % These are the root level subsystems:
       funcCategories = [funcCategories,'Methods'];
    disp([num2str(numbFunctions),' are functions, ',num2str(origSize-numbFunctions),' are methods.'])
    disp('=====================================================')
   
    load_system libraryBase.mdl
    open ltpda_library.mdl
    set(get_param(gcs,'Handle'),'Lock','off')
    
  % Delete all functions/methods folders in the root and create them anew:
    for i=1:numel(funcCategories)
        try %#ok<ALIGN>
        subsystem = find_system(bdroot,'Name',funcCategories{i});
        subsysPos = get(get_param(subsystem{1},'Handle'),'Position');
        delete_block(subsystem);
        catch end %#ok<CTCH>
        SubSystemBlock = add_block('libraryBase/SubSystName',['ltpda_library/',funcCategories{i}]);
        disp(['-- ',funcCategories{i},' updated'])
        if ~isempty(subsystem), set(SubSystemBlock,'Position',subsysPos); end
        set(SubSystemBlock,'LinkStatus','inactive')
        set(SubSystemBlock,'MaskDisplay',['disp(''',funcCategories{i},''')'])
        clear subsysPos subsystem SubSystemBlock
    end

  % Creating the Methods/<class> folder for each class anew:
    classes = utils.helper.ltpda_classes;

  % Remove improper classes:
    for i=numel(classes):-1:1
       if (numel(classes{i})>5 && strncmpi(classes{i},'ltpda_',6)) || (numel(classes{i})>3 && strncmpi(classes{i},'data',4)),          
            classes(i)=[];
       end;
    end

    for i=1:numel(classes)
        classFolder = add_block('libraryBase/SubSystName',['ltpda_library/Methods/',classes{i}]);
        set(classFolder,'LinkStatus','inactive')
        set(classFolder,'MaskDisplay',['disp(''',classes{i},''')'])
        % Cycle to set proper position:
        x=1;y=1;
        while ~isempty(find_system('ltpda_library/Methods','SearchDepth',1,'Position',[30+80*(y-1) , 30+80*(x-1) , 80+80*(y-1) , 80+80*(x-1)]))
            y=y+1;
            if y==6, x=x+1; y=1; end
        end
        set(classFolder,'Position',[30+80*(y-1) , 30+80*(x-1) , 80+80*(y-1) , 80+80*(x-1)])
    end
    
% =========================================================================
%%                     Rebuild the library contents:
% =========================================================================

  for i=1:origSize
          currMethod = versions{i,2};
          currCateg = versions{i,9};
          currClass = versions{i,10};
          
          % Check to verify whether a folder for this category exists:
            categFolder = find_system(['ltpda_library/Methods/',currClass],'SearchDepth',1,'Name',currCateg);
            try categFolder = categFolder{1}; catch end %#ok<CTCH>
            if isempty(categFolder)
                categFolder = add_block('libraryBase/SubSystName',['ltpda_library/Methods/',currClass,'/',currCateg]);
                set(categFolder,'LinkStatus','inactive')
                set(categFolder,'MaskDisplay',['disp(''',currCateg,''')'])
              % Cycle to set proper position:
                x=1;y=1;
                while ~isempty(find_system(['ltpda_library/Methods/',currClass],'SearchDepth',1,'Position',[30+80*(y-1) , 30+80*(x-1) , 80+80*(y-1) , 80+80*(x-1)]))
                    aaa = find_system(['ltpda_library/Methods/',currClass],'SearchDepth',1,'Position',[30+80*(y-1) , 30+80*(x-1) , 80+80*(y-1) , 80+80*(x-1)]);
                    if (strcmp(aaa{1},['ltpda_library/Methods/',currClass]) && numel(aaa)==1), break; end
                    y=y+1;
                    if y==5, x=x+1; y=1; end
                end                
                set(categFolder,'Position',[30+80*(y-1) , 30+80*(x-1) , 80+80*(y-1) , 80+80*(x-1)])
            end

          % Adding the proper method block:
            if strcmp(currCateg,'Constructor')
                blockH = add_block('libraryBase/constructor',['ltpda_library/Methods/',currClass,'/',currCateg,'/',currMethod]);
            elseif strcmp(currCateg,'Output')
                blockH = add_block('libraryBase/output',['ltpda_library/Methods/',currClass,'/',currCateg,'/',currMethod]);
            elseif ~strcmp(currMethod,'Contents')
                blockH = add_block('libraryBase/function',['ltpda_library/Methods/',currClass,'/',currCateg,'/',currMethod]);
            end

          % Cycle to set proper position:
            x=1;y=1;
            while ~isempty(find_system(['ltpda_library/Methods/',currClass,'/',currCateg],'SearchDepth',1,'Position',[30+70*(y-1) , 30+70*(x-1) , 80+70*(y-1) , 60+70*(x-1)]))
                aaa = find_system(['ltpda_library/Methods/',currClass,'/',currCateg],'SearchDepth',1,'Position',[30+70*(y-1) , 30+70*(x-1) , 80+70*(y-1) , 60+70*(x-1)]);
                if (strcmp(aaa{1},['ltpda_library/Methods/',currClass,'/',currCateg]) && numel(aaa)==1), break; end
                y=y+1;
                if y==5, x=x+1; y=1; end
            end
            set(blockH,'Position',[30+70*(y-1) , 30+70*(x-1) , 80+70*(y-1) , 60+70*(x-1)])
            
            set(blockH,'LinkStatus','inactive')
            set(blockH,'MaskDisplay',['disp(''',currMethod,''')'])
            set(blockH,'Tag',['method ',currClass])
            set(blockH,'Description','')
            maskText = eval(['help(''',currClass,'/',currMethod,''');']);
            maskText = strtok(maskText,'%%');
            set(blockH,'MaskDescription',maskText);
            set(blockH,'OpenFcn','ltpdagui(''callback'',1,''redraw'',2); if (~strcmp(bdroot,''ltpda_library'') && ~isempty(findobj(''Tag'',''LTPDAGUI''))), figure(findobj(''Tag'',''LTPDAGUI'')); end');
            set(blockH,'CopyFcn','GUIprefs = getappdata(0, ''GUIpreferences''); GUIprefs.Copied = 1; setappdata(0, ''GUIpreferences'',GUIprefs);');
            childpath = find_system(blockH,'LookUnderMasks','all','BlockType','M-S-Function');
            set(childpath,'Tag',currMethod)
            set(childpath,'Name',currMethod)
            set(childpath,'Description','')
            
            argsMin = str2double(versions{i,11});
            if argsMin >1
               setInports(blockH,argsMin);
               set(blockH,'Position',[30+70*(y-1) , 30+70*(x-1) , 80+70*(y-1) , 60+70*(x-1)]);
            end
  end

  % Setting proper position and size for subsystem folders in the root:
    subsystems = find_system(bdroot,'LookUnderMasks','all','SearchDepth',1,'BlockType','SubSystem');
    x=1; y=1;
    for i=1:numel(subsystems)
        set_param(subsystems{i},'Position',[30+100*(y-1) , 30+100*(x-1) , 95+100*(y-1) , 90+100*(x-1)])
        y=y+1;
        if y==4, x=x+1; y=1; end
    end
  
    close_system libraryBase.mdl
    
  % Update the annotation:
    annotationHandle = find_system(bdroot,'FindAll','on','SearchDepth',1,'type','annotation');
    caption1 = 'LTPDA Library';
    caption2 = ['v3.0 - ',datestr(now,1)];
    caption = strvcat(caption1,caption2); %#ok<VCAT>
    set_param(annotationHandle, 'HorizontalAlignment','center','Text',caption)

    warning off all
    save_system ltpda_library.mdl
    warning on all
    close_system ltpda_library.mdl

    
    
    
    %----------------------------------------------------------------------
    function setInports(varargin)
    % Called whenever the block to be added has argsmin>1, so it needs
    % multiple data inputs:
       
       currBlock = varargin{1};
       newInports = varargin{2};
       prevInport  = find_system(currBlock,'SearchDepth',1,'LookUnderMasks','all','BlockType','Inport');
       
       % To remove previous data inport and line:
       try %#ok<ALIGN>
          blockLines   = get_param(prevInport,'LineHandles');
          if (blockLines.Outport(1)~=-1 && ~isempty(blockLines.Outport(1))),   delete_line(blockLines.Outport(1)); end
          delete_block(prevInport);
       catch end
       
       % To add new inports, mux and lines:
       if newInports>1
          muxblock = add_block('built-in/Mux', [getfullname(currBlock),'/Mux']);
          set(muxblock,'Position',[70 , 10 , 73 , 150])
          set(muxblock,'Inputs',num2str(newInports))
       end
       for ii=1:newInports
          newBlock = add_block('built-in/Inport', [getfullname(currBlock),'/Inport1'],'MakeNameUnique','on');
          set_param(newBlock,'Port',num2str(ii));
          newBlock = get_param(newBlock,'Handle');
          set(newBlock,'Position',[10 , 10+30*(ii-1) , 30 , 30+30*(ii-1)])
          set(newBlock,'Tag',num2str(ii))
          add_line(currBlock,[get(newBlock,'Name'),'/1'],[get(muxblock,'Name'),'/',num2str(ii)]);
       end

       funcBlock = find_system(currBlock,'SearchDepth',1,'LookUnderMasks','all','BlockType','M-S-Function');
       funcBlock = get_param(funcBlock,'Name');
       add_line(currBlock,[get(muxblock,'Name'),'/1'],[funcBlock,'/1']);
       
              
    end
    %----------------------------------------------------------------------
    
    
end

