classdef (Hidden) ImportModelDialog < ctrluis.component.AbstractDialog
    % Import Model dialog in Model Reduction App
    
    % Copyright 2015 The MathWorks, Inc.

    properties(GetAccess = public, SetAccess = private)
        % data
        AppData
        
        %% top panel
        ImportPanel
        PlantTableLabel
        PlantTable          % java swing table
        TableTitle = getString(message('Control:mrtool:ImportModelTableLabel'));
        PlantTableData      % cell array of java.lang.String
        ColumnNames
                
        %% button panel
        ButtonRefresh
        ButtonPanel        
        ButtonImport
        ButtonCancel
        ButtonHelp
        % VE handles
        VEDialogs
    end
    properties(Access = private)
        TableWidth = 350
        TableHeight = 110;
    end
    %% Public methods
    methods(Access = public)        
        %% constructor
        function this = ImportModelDialog(data)
            this.AppData = data;
            this.Name = 'ImportModelDialog';
            this.Title = getString(message('Control:mrtool:TitleImportModelDialog'));
        end        
    end
    %% Implementation of public absract or overloaded methods
    methods(Access = public)        
        function updateUI(this)
            if this.IsDialogValid
                refreshPlantTable(this);
            end
        end        
    end
    %% Implementation of protected absract or overloaded methods
    methods(Access = protected)        
        function MainPanel = createPanel(this)
            import toolpack.component.*
            
            ImportLabel = getString(message('Control:mrtool:ImportDialogImport'));
            ModelsLabel = getString(message('Control:mrtool:ImportDialogModels'));
            TypeLabel = getString(message('Control:mrtool:Type'));
            OrderLabel = getString(message('Control:mrtool:ImportDialogOrder'));
            InputsLabel = getString(message('Control:mrtool:ImportDialogInputs'));
            OutputsLabel = getString(message('Control:mrtool:ImportDialogOutputs'));            
            
            names = {ImportLabel,ModelsLabel,TypeLabel,OrderLabel,InputsLabel,OutputsLabel};
            data = {true,ModelsLabel,TypeLabel,OrderLabel,InputsLabel,OutputsLabel};
            editables = [true false false false false false];
            this.PlantTable = buildGenericTable(this,names,data,editables,this.TableWidth,this.TableHeight);
            this.PlantTable.setName([this.Name '_PlantTable']);
            columnModel = javaMethodEDT('getColumnModel',this.PlantTable);
            column = columnModel.getColumn(0);
            fScaledSize = com.mathworks.util.ResolutionUtils.scaleSize(60);
            column.setPreferredWidth(fScaledSize);
            column.setMaxWidth(fScaledSize);
            % build table panel
            this.PlantTableLabel = TSLabel(getString(message('Control:mrtool:ImportModelTableLabel')));
            this.PlantTableLabel.Name = [this.Name '_PlantTableLabel'];
            buildTablePanel(this);
            % build button Panel 
            buildButtonPanel(this);
            % assemble
            MainPanel = TSPanel('4dlu,p:g,4dlu','4dlu,p,4dlu,p,4dlu');     
            MainPanel.Name = [this.Name '_MainPanel'];
            MainPanel.add(this.ImportPanel,'xy(2,2)');
            MainPanel.add(this.ButtonPanel,'xy(2,4)');                  
        end        
        function connectUI(this)
            % refresh workspace button
            addlistener(this.ButtonRefresh,'ActionPerformed',@(es,ed) callbackRefreshButton(this));
            % table event
            L = addlistener(this.PlantTable.getModel(),'TableChanged',@(hSrc,hData) callbackTableChanged(this, hSrc, hData)); 
            registerUIListeners(this,L);
            % model table HTML link
            L1 = addlistener(this.PlantTable,'MouseClicked', @(hSrc,hData) callbackMouseClicked(this,hSrc,hData));
            L2 = addlistener(this.PlantTable,'MouseMoved', @(hSrc,hData) callbackMouseMoved(this,hSrc,hData));
            L3 = addlistener(this.PlantTable,'MouseExited', @(hSrc,hData) callbackMouseExited(this,hSrc,hData));
            registerUIListeners(this,[L1;L2;L3]);
            % add widget listener to button event
            addlistener(this.ButtonImport,'ActionPerformed',@(es,ed) callbackImportButton(this));
            addlistener(this.ButtonCancel,'ActionPerformed',@(es,ed) callbackCancelButton(this));
            addlistener(this.ButtonHelp,'ActionPerformed',@(es,ed) callbackHelpButton(this));              
        end        
        function cleanupUI(this)
            % custom code
            if ~isempty(this.ImportPanel) && isvalid(this.ImportPanel)
                delete(this.ImportPanel);
            end
            if ~isempty(this.ButtonPanel) && isvalid(this.ButtonPanel)
                delete(this.ButtonPanel);
            end
        end            
        function refreshPlantTable(this)
            this.PlantTableData = getPlantTableData(this);
            model = this.PlantTable.getModel();
            if isempty(this.PlantTableData)
                javaMethodEDT('clearRows',model);
            else
                javaMethodEDT('setData',model,this.PlantTableData);
            end
        end        
    end    
    methods(Access = private)            
        function callbackImportButton(this)
            % force any table editing stops
            this.ButtonImport.Peer.grabFocus();
            drawnow
            % identify which plants to be imported.  Error out if none.
            rows = this.PlantTable.getRowCount();
            vals = false(rows,1);
            for ct = 1:rows
                if this.PlantTableData{ct,1}.booleanValue
                    vals(ct) = true;
                end
            end
            if isempty(vals) || ~any(vals)
                mrtool.util.openJavaModalErrorDialog(this.PlantTable,getString(message('Control:mrtool:ErrorNoImportModelSelected')));
                return
            end
            % construct data set as a cell array of names and plants
            ind = find(vals);
            len = length(ind);
            sys = mrtool.data.ModelWrapper.empty(len,0);
            for ct = 1:len
                var = mrtool.util.manageLinkDisplay('remove',this.PlantTableData{ind(ct),2});
                plant = evalin('base',var);
                [~,plant] = mrtool.util.isValidSystem({plant});
                plant = plant{1};
                sys(ct) = mrtool.util.createModelWrapper({plant},{var});
            end
            % now it is OK to import
            % close
            hide(this);            
            % add plant nodes (no controller is added)
            importModels(this.AppData, sys);  
            Sentence = mrtool.util.createModelNameSentence({sys.Name});
            if length({sys.Name})>1
                Msg = getString(message('Control:mrtool:StatusMessageImportModels',Sentence));
            else
                Msg = getString(message('Control:mrtool:StatusMessageImportModel',Sentence));
            end            
            postActionStatus(getEventManager(this.AppData),'off',mrtool.util.convertStr2Html(Msg));
        end        
        function callbackCancelButton(this)
            for ct=1:length(this.VEDialogs)
                if isvalid(this.VEDialogs(ct))
                    delete(this.VEDialogs(ct))
                end
            end
            hide(this);
        end        
        function callbackHelpButton(this)
            mrtool.guiutil.mrToolHelp('ModelReducerImport',true);
        end        
        function callbackRefreshButton(this)
            refreshPlantTable(this);
        end        
        
        function callbackTableChanged(this, hSrc, hData)
            % changed from JAVA side
            row = hData.getFirstRow + 1;
            col = hData.getColumn + 1;
            if row > 0 && col > 0 && row <= hSrc.getRowCount() && col <= hSrc.getColumnCount()
                % must be first column
                model = this.PlantTable.getModel();                
                selected = javaMethodEDT('getValueAt',model,row-1,0);
                this.PlantTableData{row,1} = java.lang.Boolean(selected);                    
            end
        end        
        
        %% Mouse Movement
        function callbackMouseClicked(this,hSrc,hData)
            row = hSrc.getSelectedRow()+1;
            col = hSrc.getSelectedColumn()+1;
            if row > 0 && col > 0 && row <= hSrc.getRowCount() && col <= hSrc.getColumnCount()
                % display plant info
                if col==2
                    var = mrtool.util.manageLinkDisplay('remove',this.PlantTableData{row,col});
                    sys = evalin('base',var);
                    LocalWorkspace = toolpack.databrowser.LocalWorkspaceModel;
                    assignin(LocalWorkspace,var,sys);
                    ve = toolpack.databrowser.VariableEditorManager.getInstance();
                    veDialog = ve.openDialog(LocalWorkspace, var, hData.getLocationOnScreen());
                    this.VEDialogs = [this.VEDialogs; veDialog];
                end
            end
        end        
        function callbackMouseExited(this, es, ed)
            cursor = es.getCursor();
            es.setCursor(cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
        end        
        function callbackMouseMoved(this, es, ed)
            col = es.columnAtPoint(java.awt.Point(ed.getX(),ed.getY())) + 1;
            cursor = es.getCursor();
            if col==2
                es.setCursor(cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));
            else
                es.setCursor(cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
            end
        end        
        function buildTablePanel(this)
            import toolpack.component.*
            this.ImportPanel = TSPanel('3dlu,p:g,3dlu','3dlu,p,3dlu,p:g,3dlu');
            this.ImportPanel.Name = [this.Name '_ImportPanel'];
            border = javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(),...
                this.TableTitle);
            font = this.ImportPanel.Peer.getFont;
            fontBold = font.deriveFont(java.awt.Font.BOLD,font.getSize);
            border.setTitleFont(fontBold);
            this.ImportPanel.Peer.setBorder(border);                        
            ScrollPane = javaObjectEDT('com.mathworks.mwswing.MJScrollPane',this.PlantTable);
            cc = com.jgoodies.forms.layout.CellConstraints();
            this.ImportPanel.Peer.add(ScrollPane,cc.xy(2,4));
        end
        function buildButtonPanel(this)
            import toolpack.component.*
            % create buttons
            this.ButtonRefresh = TSButton(getString(message('Control:mrtool:ImportRefreshWorkspace')),Icon.REFRESH_16);  
            this.ButtonRefresh.Name = [this.Name '_RefreshButton'];
            this.ButtonRefresh.UsePermanentBorder = true;
            this.ButtonImport = TSButton(getString(message('Control:mrtool:Import')));
            this.ButtonImport.Name = [this.Name '_ImportButton'];
            this.ButtonImport.UsePermanentBorder = true;
            this.ButtonCancel = TSButton(getString(message('Control:mrtool:Cancel')));
            this.ButtonCancel.Name = [this.Name '_CancelButton'];
            this.ButtonCancel.UsePermanentBorder = true;
            this.ButtonHelp = TSButton(getString(message('Control:mrtool:Help')));  
            this.ButtonHelp.Name = [this.Name '_HelpButton'];
            this.ButtonHelp.UsePermanentBorder = true;
            % add to panel
            this.ButtonPanel = TSPanel('4dlu,p,4dlu,p:g,4dlu,p,4dlu,p,4dlu,p,4dlu','p');            
            this.ButtonPanel.Name = [this.Name '_ButtonPanel'];
            this.ButtonPanel.add(this.ButtonRefresh,'xy(2,1)');            
            this.ButtonPanel.add(this.ButtonImport,'xy(6,1)');            
            this.ButtonPanel.add(this.ButtonCancel,'xy(8,1)');            
            this.ButtonPanel.add(this.ButtonHelp,'xy(10,1)');
        end        
        function data = getPlantTableData(this,varargin)
            % get all the variables in the base workspace
            Vars = evalin('base','whos');            
            % get names
            sysvar = {Vars.name}.';
            Nsys = numel(sysvar);
            % make local copies in a cell array
            DataModels = cell(Nsys,1);            
            for ct=1:Nsys
                DataModels(ct) = {evalin('base',sysvar{ct})};
            end
            % accept dynamic system only
            [isValidType,DataModels] = mrtool.util.isValidSystem(DataModels);
                       
            varnum = sum(isValidType);
            varnames = sysvar(isValidType);
            vardata = DataModels(isValidType);
            % create table data
            data = cell(varnum,6);
            % update table data
            for ct = 1:varnum
                data{ct,1} = java.lang.Boolean.FALSE;
                data{ct,2} = java.lang.String(mrtool.util.manageLinkDisplay('add',varnames{ct}));
                data{ct,3} = java.lang.String(class(vardata{ct}));               
                data{ct,4} = java.lang.String(num2str(order(vardata{ct})'));
                data{ct,5} = java.lang.String(num2str(size(vardata{ct},2)));
                data{ct,6} = java.lang.String(num2str(size(vardata{ct},1)));
            end
        end
        function Table = buildGenericTable(this,names, data, editables, width, height)
            len = length(names);
            TableModel = com.mathworks.toolbox.control.tableclasses.BasicTableModel(data,names);
            % set editable columns (have to use java.lang.Boolean.TRUE/FALSE explicitly)
            EditableColumns = javaArray('java.lang.Boolean',len);
            for ct=1:len
                if editables(ct)
                    EditableColumns(ct) = java.lang.Boolean.TRUE;
                else
                    EditableColumns(ct) = java.lang.Boolean.FALSE;
                end
            end
            TableModel.Editablecolumns = EditableColumns;
            % create table
            Table = javaObjectEDT('com.mathworks.mwswing.MJTable',TableModel);
            % make read-only cloumns grey
            columnModel = javaMethodEDT('getColumnModel',Table);
            for ct=1:len
                if ~editables(ct)
                    column_readonly = columnModel.getColumn(ct-1);
                    tmp = javaObjectEDT('javax.swing.table.DefaultTableCellRenderer');
                    tmp.setBackground(getReadOnlyColor());
                    column_readonly.setCellRenderer(tmp);
                end
            end
            % auto commit when losing focus
            Table.putClientProperty('terminateEditOnFocusLost',java.lang.Boolean.TRUE);
            % no row selection
            Table.setRowSelectionAllowed(false);
            % set preferred view size
            Table.setPreferredScrollableViewportSize(java.awt.Dimension(width, height));
        end
    end
    methods (Hidden)
        function Widgets = getWidgets(this)
            Widgets.ColumnNames = this.ColumnNames;
            Widgets.TableData = this.PlantTableData;
            Widgets.DialogName = this.Name;
            Widgets.DialogTitle = this.Title;
            Widgets.DialogTableTitle = this.TableTitle;
            Widgets.VEDialogs = this.VEDialogs;
            Widgets.ButtonImport = this.ButtonImport;
            Widgets.ButtonCancel = this.ButtonCancel;
            Widgets.ButtonHelp = this.ButtonHelp;
        end        
    end    
end

function BackgroundColor = getReadOnlyColor()
    foo = javaObjectEDT('com.mathworks.mwswing.MJPanel');            
    Red = foo.getBackground.getRed;
    Green = foo.getBackground.getGreen;
    Blue = foo.getBackground.getBlue;
    BackgroundColor = java.awt.Color(Red/255,Green/255,Blue/255);
end
