function obj = plotPartitionGUI(obj)
% Ausgabe der aktuellen Partitionierung eines lokalen Modellnetzes
%
% plotPartitionGUI(obj)
%
% Inputs
%
% obj:          model object


% Options
width     = 1000;
height    = 650;
fontname  = 'Times New Roman';
fontsize  = 13;
linewidth = 2;
nGrid1d   = 150; % grid resolution 1D-case
nGrid2d   = 50;  % grid resolution 2D-case
mGrid2d   = 50;

% net       = obj.net;
% dataSet   = obj.dataSet;



% switch trainType
%     case 'HILOMOT'
        warning off MATLAB:contour:ConstantData
        initializePlot();
% end

    function initializePlot()
        % Create figure
        
        scrsize    = get(0,'screensize');
        fposition  = [(scrsize(3)-width)/2 (scrsize(4)-height)/2 ...
            width height];
        bgcolor    = [0.7 0.7 0.7];
        white      = [1 1 1];
        positionen = [];
        load('plotPartitionPositions.mat');
        savedModelComplexity = sum(obj.leafModels);
        savedSmoothness      = obj.smoothness;
        
        
        fh = figure('Position',fposition,'Visible','off',...
            'MenuBar','none','Toolbar','figure','color',bgcolor,...
            'KeyReleaseFcn',@reposElements,...
            'CloseRequestFcn',@myCloseRequest);
        
        %% Panel "Graphical Output"
        hGRpanel = uipanel('Parent',fh,...
            'Title','Graphical presentation',...
            'Units','pixels',...
            'Position',positionen.GRpanel,...
            'Tag','GRpanel');
        
        hInputDimText = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.textInputDim,...
            'String','Number of inputs:',...
            'Tag','textInputDim');
        
        if size(obj.input,2) > 1
            chosenInputDim  = 2;
            enablePopup2    = 'on';
        else
            chosenInputDim  = 1;
            enablePopup2    = 'off';
        end
        
        hInputDim = uicontrol('Style','popupmenu',...
            'Parent',hGRpanel,...
            'String',{'1','2'},...
            'Enable','on',...
            'Value',chosenInputDim,...
            'Position',positionen.InputDim,...
            'Callback',@chooseDim,...
            'Tag','InputDim');
        
        hChooseModelText = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.textChooseModel,...
            'String','Choose number of local models:',...
            'Tag','textChooseModel');
        
        hModelComplexityEdit = uicontrol('Parent',hGRpanel,...
            'Style','edit',...
            'Position',positionen.hModelComplexityEdit,...
            'String',num2str(sum(obj.leafModels)),...
            'Callback',@changeModelComplexity,...
            'Tag','hModelComplexityEdit');
        
        hModelComplexitySlider = uicontrol('Parent',hGRpanel,...
            'Style','slider',...
            'Position',positionen.hModelComplexitySlider,...
            'Min',1,'Max',size(obj.history.leafModelIter,2),...
            'SliderStep',[1/size(obj.history.leafModelIter,2) 0.1],...
            'Value',sum(obj.leafModels),...
            'Callback',@changeModelComplexity,...
            'Tag','hModelComplexitySlider');
%         addlistener(hModelComplexitySlider,...
%             'ContinuousValueChange',@changeSmoothness);
        
        haSurf = axes('Units','pixels',...
            'Parent',hGRpanel,...
            'Position',positionen.haSurf,...
            'Tag','haSurf');
        
        haCont = axes('Units','pixels',...
            'Parent',hGRpanel,...
            'Position',positionen.haCont,...
            'Tag','haCont');
        
        hPlotu1 = uicontrol('Style','popupmenu',...
            'Parent',hGRpanel,...
            'String',obj.info.inputDescription,...
            'Enable','on',...
            'Value',1,'Position',positionen.plotu1,...
            'Callback',@checkInputs,...
            'Tag','plotu1');
        
        hPlotu1Text = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.plotu1text,...
            'String','x-axis',...
            'Tag','plotu1text');
        
        hPlotu2 = uicontrol('Style','popupmenu',...
            'Parent',hGRpanel,...
            'String',obj.info.inputDescription,...
            'Value',chosenInputDim,...
            'Position',positionen.plotu2,...
            'Enable',enablePopup2,...
            'Callback',@checkInputs,...
            'Tag','plotu2');
        
        hPlotu2Text = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.plotu2text,...
            'String','y-axis',...
            'Tag','plotu2text');
        
        hSmText = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.hSmText,...
            'String','Current smoothness:',...
            'Tag','hSmText');
        
        hSmEdit = uicontrol('Parent',hGRpanel,...
            'Style','edit',...
            'Position',positionen.hSmEdit,...
            'String',num2str(obj.smoothness),...
            'Callback',@changeSmoothness,...
            'Tag','hSmEdit');
        
        hSmSlider = uicontrol('Parent',hGRpanel,...
            'Style','slider',...
            'Position',positionen.hSmSlider,...
            'Min',0.1,'Max',3,...
            'Value',obj.smoothness,...
            'Callback',@changeSmoothness,...
            'Tag','hSmSlider');
        addlistener(hSmSlider,...
            'ContinuousValueChange',@changeSmoothness);
        
        hSaveSmoothnessButton = uicontrol('Parent',hGRpanel,...
            'Style','Pushbutton',...
            'String','Save smoothness',...
            'Enable','on',...
            'Position',positionen.hSaveSmoothness,...
            'Tag','hSaveSmoothness',...
            'Callback',@changeObject);
        
        hSaveModelComplexityButton = uicontrol('Parent',hGRpanel,...
            'Style','Pushbutton',...
            'String','Save model complexity',...
            'Enable','on',...
            'Position',positionen.hSaveModelComplexity,...
            'Tag','hSaveModelComplexity',...
            'Callback',@changeObject);
        
        hSaveText = uicontrol('Parent',hGRpanel,...
            'Style','text',...
            'Position',positionen.hSaveText,...
            'String',['All settings you saved during the use ',...
            'of this plotPartition-GUI will be saved in the output ',...
            'of this GUI as an model-object.'],...
            'HorizontalAlignment','left',...
            'Tag','hSaveText');
        
        hExportValidity = uicontrol('Parent',hGRpanel,...
            'Style','Pushbutton',...
            'String','Export figure of validity functions',...
            'Enable','on',...
            'Position',positionen.hExportValidity,...
            'Tag','hExportValidity',...
            'Callback',@exportFigure);
        
        hExportPartitioning = uicontrol('Parent',hGRpanel,...
            'Style','Pushbutton',...
            'String','Export figure of partitioning',...
            'Enable','on',...
            'Position',positionen.hExportPartitioning,...
            'Tag','hExportPartitioning',...
            'Callback',@exportFigure);
        
        hExportBoth = uicontrol('Parent',hGRpanel,...
            'Style','Pushbutton',...
            'String','Export both axes to own figure',...
            'Enable','on',...
            'Position',positionen.hExportBoth,...
            'Tag','hExportBoth',...
            'Callback',@exportFigure);
        
        %% Panel "Scrollbars"
        hSBpanel = uipanel('Parent',fh,...
            'Title','Set operating point',...
            'Units','pixels',...
            'Position',positionen.SBpanel,...
            'Tag','SBpanel');
        
        set(fh,'Visible','on');
        
        % Define background color of all elements, that are not white
        set([hGRpanel,hSBpanel,hInputDimText,hPlotu1Text,hPlotu2Text,...
            hSmText,hSmSlider,hModelComplexitySlider,hChooseModelText,...
            hSaveSmoothnessButton,hSaveModelComplexityButton,hSaveText],...
            'BackgroundColor',bgcolor);
        
        % Define background color of all white elements
        set([hInputDim,hPlotu1,hPlotu2,hSmEdit,hModelComplexityEdit],...
            'BackgroundColor',white);
        
        % Initialize axes
        sb         = getSBinputs(size(obj.input,2));
        sbBars     = cell(length(sb),1);
        sbTolEdit  = sbBars;
        sbBezText  = sbBars;
        sbTolText  = sbBars;
        sbValEdit  = sbBars;
        sbWertText = sbBars;
        pSurf      = [];
        pCont      = [];
        updateBedienelemente;
        updatePlot([],[],haSurf,haCont);
        
        
        function changeSmoothness(hObject,eventdata)
            size(eventdata);
            
            if isnumeric(hObject) && hObject == hSmEdit
                % Function call via edit field
                value = str2double(get(hSmEdit,'String'));
                set(hSmSlider,'Value',value);
            else
                % Function call via slider
                value = get(hSmSlider,'Value');
                set(hSmEdit,'String',num2str(value));
            end
            
            % Syndicate smoothness of model and corresponding slider
            obj.smoothness = value;
            updatePlot(hObject,eventdata);
            
        end % end changeSmoothness
        
        function updateBedienelemente(varargin)
            size(varargin);
            % Create GUI elements
            
            % Slider definitions
            if size(sbBars,1) > 0 && ~isempty(sbBars{1})
                % All former created elements has to be deleted
                for ii=1:length(sbBars)
                    delete(sbBars{ii});
                    delete(sbTolEdit{ii});
                    delete(sbBezText{ii});
                    delete(sbTolText{ii});
                    delete(sbValEdit{ii});
                    delete(sbWertText{ii});
                end
            end
            sb         = getSBinputs(size(obj.input,2));
            sbBars     = cell(length(sb),1);
            sbTolEdit  = sbBars;
            sbBezText  = sbBars;
            sbTolText  = sbBars;
            sbValEdit  = sbBars;
            sbWertText = sbBars;
            sbwidth    = 210;
            sbheight   = 20;
            editwidth1 = 100;
            editwidth2 = 40;
            editheight = 20;
            topmargin  = 15;
            zwmargin   = 55;
            sbtextmarg = 20;
            sbtextunte = 15;
            sbpanelpos = get(hSBpanel,'Position');
            input       = obj.unscaledInput;
            output      = obj.unscaledOutput;
            data        = [input output];
            for ii=1:length(sb)
                yposSB  = sbpanelpos(end)-topmargin-40-(ii-1)*zwmargin;
                tmpMax  = max(data(:,sb(ii)));
                tmpMin  = min(data(:,sb(ii)));
                wert    = (tmpMax + tmpMin)/2;
                
                sbWertText{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','text',...
                    'Position',[15 yposSB-sbtextunte 26 15],...
                    'HorizontalAlignment','left',...
                    'String','Wert:');
                
                sbTolEdit{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','edit',...
                    'Position',[340-editwidth2, yposSB-sbtextunte,...
                    editwidth2, editheight],...
                    'String','10',...
                    'Callback',@updatePlot);
                
                sbBezText{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','text',...
                    'Position',[15 yposSB+sbtextmarg 215 15],...
                    'HorizontalAlignment','left',...
                    'String',obj.info.inputDescription{1,sb(ii)});
                
                sbTolText{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','text',...
                    'Position',[340-(editwidth2+48),...
                    yposSB-sbtextunte, 45, 15],...
                    'HorizontalAlignment','left',...
                    'String','Toleranz:');
                
                sbValEdit{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','edit',...
                    'Position',[46,...
                    yposSB-sbtextunte,...
                    editwidth1, editheight],...
                    'String',num2str(wert),...
                    'Callback',@getScrBarValue);
                
                sbBars{ii,1} = uicontrol('Parent',hSBpanel,...
                    'Style','slider',...
                    'Position',[15 yposSB sbwidth sbheight],...
                    'Min',tmpMin,'Max',tmpMax,...
                    'Value',wert,...
                    'Callback',@updatePlot);
                addlistener(sbBars{ii,1},...
                    'ContinuousValueChange',@updatePlot);
            end
            set([sbBars{:},sbBezText{:},sbTolText{:},sbWertText{:}],...
                'BackgroundColor',bgcolor);
            set([sbTolEdit{:}],'BackgroundColor',white);
            
        end % end updateBedienelemente
        
        function checkInputs(hObject,eventdata)
            size(hObject);
            size(eventdata);
            u1 = get(hPlotu1,'Value');
            u2 = get(hPlotu2,'Value');
            dimDarstellung = get(hInputDim,'Value');
            if u1 == u2 && dimDarstellung == 2
                if u2 == size(obj.input,2)
                    set(hPlotu2,'Value',u2-1);
                else
                    set(hPlotu2,'Value',u2+1);
                end
            end
            updateBedienelemente;
            updatePlot(hObject,eventdata);
        end % end checkInputs
        
        function chooseDim(hObject,eventdata)
            size(eventdata);
            value = get(hObject,'Value');
            if value == 1
                set(hPlotu2,'Enable','off');
            elseif value == 2 && size(obj.input,2) > 1
                set(hPlotu2,'Enable','on');
                checkInputs(hObject,eventdata);
            else
                msgbox('There is only one input dimension!!');
                set(hObject,'Value',1);
                return;
            end
            updateBedienelemente;
            updatePlot(hObject,eventdata);
        end % end chooseDim
        
        function sbInputs = getSBinputs(noDSspalten)
            % Read popup entries
            valueU1 = get(hPlotu1,'Value');
            valueU2 = get(hPlotu2,'Value');
            xInputs = 1:size(obj.input,2);
            
            dimDarstellung = get(hInputDim,'Value');
            if dimDarstellung == 2
                achsen = unique([xInputs(valueU1) xInputs(valueU2)]);
            else
                achsen = xInputs(valueU1);
            end
            reihen     = 1:noDSspalten;
            sbInputs   = setxor(achsen,reihen);
        end % end getSBinputs
        
        
        function getScrBarValue(hObject,eventdata)
            size(hObject);
            size(eventdata);
            [~,~,ib] = intersect(hObject,cell2mat(sbValEdit));
            set(sbBars{ib,1},'Value',...
                str2double(get(hObject,'String')));
            updatePlot(hObject,eventdata);
        end % end getScrBarValue
        
        
        function updatePlot(hObject,eventdata,varargin)
            size(hObject);
            size(eventdata);
            % Determine to which axis should be plotted
            if size(varargin,2) == 0
                % If there are no arguments passed update the axes within
                % the plotPartitionGUI
                haLinks  = haSurf;
                haRechts = haCont;
            else
                % If there are arguments passed, this function is called
                % for a figure export. If haLinks is not empty the
                % information from haSurf will be plotted in the new
                % figure. If haRechts is not empty the information from
                % haCont will be plotted in the new figure.
                haLinks = varargin{1,1};
                haRechts = varargin{1,2};
            end
            dimDarstellung = get(hInputDim,'Value');
            if dimDarstellung == 1
                dim = get(hPlotu1,'Value');
            else
                dim = [get(hPlotu1,'Value') get(hPlotu2,'Value')];
            end
            
            dimensional = length(dim);
            
            switch dimensional
                
                case 1
                    set([haCont;get(haCont,'Children');hExportBoth;...
                        hExportPartitioning],'Visible','off');
                    
                    % Read scrollbar values
                    inputData = zeros(nGrid1d,size(obj.input,2));
                    sbInputs  = getSBinputs(size(obj.input,2));
                    sbInputs  = [sbInputs;1:size(sbInputs,2)];
                    for jj = sbInputs
                        inputData(:,jj(1)) = get(sbBars{jj(2),1},'Value');
                        set(sbValEdit{jj(2),1},'String',...
                            num2str(get(sbBars{jj(2),1},'Value')));
                    end
                    % Because the scrollbar values are not normalized, they
                    % have to be normalized, if the model was trained with
                    % normalized training data
                    if ~isempty(obj.scaleInput)
                        inputData      = obj.scaleInput.scale(inputData);
                    end
                    
                    inputData(:,dim) = ...
                        linspace(min(obj.input(:,dim)),...
                        max(obj.input(:,dim)),nGrid1d)';
                    
                    % Calculate validity function for chosen dimensions
                    zRegressor = obj.data2zRegressor(inputData);
                    phi = GUIvisualize.calculateValidityFunctionAllClasses(obj,zRegressor);
                    
                    % Denormalize data
                    if ~isempty(obj.scaleInput)
                        inputData   = obj.scaleInput.unscale(inputData);
                    end
                    
                    hold(haLinks,'off')
                    for lm = 1:size(phi,2)
                        pSurf = plot(haLinks,inputData(:,dim),phi(:,lm),'LineWidth',linewidth);
                        %text(net.center(lm,dimensions),0.5,num2str(lm))
                        hold(haLinks,'on')
                        set(haLinks,'Tag','haSurf');
                    end
                    ht=title(haLinks,'Validity Functions');
                    hx=xlabel(haLinks,obj.info.inputDescription{1,dim});
                    hz=zlabel(haLinks,'\Phi');
                    axis([inputData(1,dim) inputData(end,dim) 0 1.05])
                    set([haLinks,hx,hz,ht],'FontName',fontname,...
                        'FontSize',fontsize);
                    
                case 2
                    set([haCont,hExportBoth,hExportPartitioning],...
                        'Visible','on');
                    % Get slider values
                    inputData = ...
                        zeros(nGrid2d*mGrid2d,size(obj.input,2));
                    sbInputs  = getSBinputs(size(obj.input,2));
                    sbInputs  = [sbInputs;1:size(sbInputs,2)];
                    for jj = sbInputs
                        inputData(:,jj(1)) = get(sbBars{jj(2),1},'Value');
                        set(sbValEdit{jj(2),1},'String',...
                            num2str(get(sbBars{jj(2),1},'Value')));
                    end
                    % Normalize slider values
                    if ~isempty(obj.scaleInput)
                        inputData      = obj.scaleInput.scale(inputData);
                    end
                    
                    u1v = linspace(min(obj.input(:,dim(1))),...
                        max(obj.input(:,dim(1))),nGrid2d);
                    u2v = linspace(min(obj.input(:,dim(2))),...
                        max(obj.input(:,dim(2))),mGrid2d);
                    [u1g, u2g] = meshgrid(u1v, u2v);
                    u1 = u1g(:);
                    u2 = u2g(:);
                    
                    inputData(:,dim(1)) = u1;
                    inputData(:,dim(2)) = u2;
                    
                    % Calculate validity function for chosen dimensions
                    zRegressor = obj.data2zRegressor(inputData);
                    phi = GUIvisualize.calculateValidityFunctionAllClasses(obj,zRegressor);
                    
                    % Denormalize inputs
                    if ~isempty(obj.scaleInput)
                        inputData   = obj.scaleInput.unscale(inputData);
                    end
                    
                    if ~isempty(haLinks)
                        cameraPosition = get(haLinks,'View');
                        if cameraPosition == [0 90]
                            cameraPosition = [-30 40];
                        end
                        hold(haLinks,'off');
                        for lm = 1:size(phi,2)
                            pSurf = surf(haLinks,...
                                reshape(inputData(:,dim(1)),nGrid2d,mGrid2d),...
                                reshape(inputData(:,dim(2)),nGrid2d,mGrid2d),...
                                reshape(phi(:,lm),...
                                nGrid2d,mGrid2d));
                            hold(haLinks,'on');
                        end
                        set(haLinks,'View',cameraPosition);
                        %                     view(-30,40)
                        ht=title(haLinks,'Validity Functions');
                        hx=xlabel(haLinks,obj.info.inputDescription{1,dim(1)});
                        hy=ylabel(haLinks,obj.info.inputDescription{1,dim(2)});
                        hz=zlabel(haLinks,'\Phi');
                        set([haLinks,ht,hx,hy,hz],'fontsize',fontsize,...
                            'FontName',fontname);
                        xlim(haLinks,[min(inputData(:,dim(1))) max(inputData(:,dim(1)))]);
                        ylim(haLinks,[min(inputData(:,dim(2))) max(inputData(:,dim(2)))]);
                    end
                    
                    if ~isempty(haRechts)
                        hold(haRechts,'off');
                        for lm = 1:sum(obj.leafModels)
                            pCont = ...
                                contour(haRechts,...
                                reshape(inputData(:,dim(1)),nGrid2d,mGrid2d),...
                                reshape(inputData(:,dim(2)),nGrid2d,mGrid2d),...
                                reshape(phi(:,lm),nGrid2d,mGrid2d),[0.5 0.5],...
                                'LineColor','k','LineWidth',linewidth);
                            hold(haRechts,'on');
                        end
                        
                        ht=title(haRechts,'Partitioning');
                        hx=xlabel(haRechts,obj.info.inputDescription{1,dim(1)});
                        hy=ylabel(haRechts,obj.info.inputDescription{1,dim(2)});
                        set([haRechts,ht,hx,hy],'fontsize',fontsize,...
                            'FontName',fontname)
                    end
                    
                otherwise
                    
                    error('More than 2 dimensions cannot be plotted. Please select a subset of 2 dimensions to be plotted.')
                    
            end
        end % end updatePlot
        
        function changeModelComplexity(hObject,eventdata)
            size(eventdata);
            
            % determine which GUI-component has called this function
            if hObject == hModelComplexitySlider
                modelComplexity     = get(hModelComplexitySlider,'Value');
            elseif hObject == hModelComplexityEdit
                modelComplexity     = ...
                    str2double(get(hModelComplexityEdit,'String'));
            end
            
            % make sure, that the desired model complexity is always an
            % integer
            if modelComplexity < 1
                modelComplexity = 1;
            elseif modelComplexity > size(obj.history.leafModelIter,2)
                modelComplexity = size(obj.history.leafModelIter,2);
            else
                modelComplexity = round(modelComplexity);
            end
            set(hModelComplexityEdit,'String',...
                num2str(modelComplexity));
            set(hModelComplexitySlider,'Value',modelComplexity);
            
            % update the selected model complexity
            obj.leafModels  = ...
                obj.history.leafModelIter{modelComplexity};
            %             net             = obj;
            
            % update graphical representation
            changeSmoothness(hSmSlider,[]);
            
        end % end changeModelComplexity
        
        
        function changeObject(hObject,eventdata)
            size(eventdata);
            
            if hObject == hSaveSmoothnessButton
                savedSmoothness      = get(hSmSlider,'Value');
            elseif hObject == hSaveModelComplexityButton
                savedModelComplexity = get(hModelComplexitySlider,'Value');
            end
        end % end changeObject
        
        function exportFigure(hObject,eventdata)
            size(hObject);
            size(eventdata);
            if hObject == hExportBoth
                figure;
                haLeft = subplot(1,2,1);
                haRight = subplot(1,2,2);
                updatePlot(hObject,eventdata,haLeft,haRight);
            else
                if hObject == hExportValidity
                    figure;
                    haLeft = axes;
                    updatePlot(hObject,eventdata,haLeft,[]);
                elseif hObject == hExportPartitioning
                    figure;
                    haRight = axes;
                    updatePlot(hObject,eventdata,[],haRight);
                end
            end
        end % end exportFigure
        
        function myCloseRequest(hObject,eventdata)
            size(eventdata);
            size(hObject);
            obj.smoothness = savedSmoothness;
            obj.leafModels = ...
                obj.history.leafModelIter{savedModelComplexity};
            delete(fh);
        end % end myCloseRequest
        

        function reposElements(hObject,eventdata)
            % Function makes it possible to repsition gui elements easily
            size(hObject);
            if strcmp(eventdata.Key,'r')
                hList1     = [get(fh,'children');...
                    get(hSBpanel,'children');get(hGRpanel,'children')];
                set(hList1,'Visible','on');
                reposGUIelements(hList1,fh);
            end
        end % end reposElements
        
    end % end initializePlot
waitfor(fh);
end