function zoomOrientation(axh,state)
% ----------------------------------------------------------------------------------------
%
% zoomOrientation reduces axes width and height and adds
% two new axes, xOrientation and yOrientation plus xSlider and ySlider
% if axes is in full view on startup, initial zoom factor is set to 2
%
% Function Inputs:
%   axh = axes handle
%   state = on/off/update
%
% Examples to use zoomOrientation:
%   figure(1);
%   plot(1:100,randn(1,100))
%   zoomOrientation(gca,'on')
% ----------------------------------------------------------------------------------------
    % check input
    if ~ishghandle(axh)
        errordlg('Function input 1 is not a valid axes object','zoomOrientation') 
        return % end function
    end
    
    switch state
        case 'on'
            handles.hfig = gcf;            
            % set axes units to normalized
            set(axh,'Units','normalized')
            % get necassary axes properties
            % axes position
            handles.axhPos = get(axh,'Position');
            % lin or log scaling x axis
            xscale = get(axh,'XScale');
            % lin or log scaling y axis
            yscale = get(axh,'YScale');
            % axes parent
            handles.axhParent = get(axh,'Parent');
%             type = get(handles.axhParent,'Type');
%             if strcmp(type,'figure')
%                 stop=1
%             end
            % init UserData
            set(handles.axhParent,'UserData',0);
            % xlim and ylim
            limX = get(axh,'XLim');
            limY = get(axh,'YLim');            
            % axes BackgroundColor
            BgColor = get(axh,'Color');
            % tickcolors
            xtickColor = get(axh,'XColor');
            ytickColor = get(axh,'YColor');
            % extract data from plot
            y = get(get(axh,'children'),'Ydata');
            x = get(get(axh,'children'),'Xdata');
            
            % in case there is only one trace in the plot => change XData and YData into cell
            if iscell(y)==0
                xtmp = x;
                x = cell(1);
                x{1} = xtmp;
                ytmp = y;
                y = cell(1);
                y{1} = ytmp;
            end
            
            % for SignalViewer only!
            for i=1:length(y)
                % delete signal dummies
                if sum(y{i}) == 10 && sum(x{i}) == 55
                    y{i} = [];
                    x{i} = [];
                end
            end
            
            % delete empty cells
            x = x(~cellfun('isempty',x));
            y = y(~cellfun('isempty',y));
            
            maxXLim = NaN;
            maxYLim = NaN;
            minXLim = NaN;
            minYLim = NaN;
            % get axis limits of plot data and compare to current axis limits
            for i=1:length(y)
                maxXLim = max([maxXLim limX(2) max(x{i})]);
                minXLim = min([minXLim limX(1) min(x{i})]);
                maxYLim = max([maxYLim limY(2) max(y{i})]);
                minYLim = min([minYLim limY(1) min(y{i})]);
            end
            
            % save limits in handle
            handles.dataLim = [minXLim maxXLim minYLim maxYLim];
            
            % if axes in full view, set inital zoom
            if minXLim == limX(1) && maxXLim == limX(2) && minYLim == limY(1) && maxYLim == limY(2)
                zoom(handles.hfig,'on')
                handles.zoomFactor = 2;
                zoom(handles.hfig,handles.zoomFactor)
                hZoom = zoom;
                % get new axis limits
                limX = get(axh,'XLim');
                limY = get(axh,'YLim');
            else
                zoom(handles.hfig,'on')
                % get handle
                hZoom = zoom;
            end
            
            % define zoom callback for mouse gestures
            set(hZoom,'RightClickAction','InverseZoom','ActionPostCallback',@MouseAction)

            % reduces main axes height
            newPlotPos = handles.axhPos .* [1, 1, 1, 0.70] + [0, 0.30*handles.axhPos(4), 0, 0];
            set(axh, 'position',newPlotPos);
            % reduces main axes width
            newPlotPos = newPlotPos .* [1, 1, 0.85, 1];
            set(axh, 'position',newPlotPos);
            % get new axes position
            axhPosNew = get(axh,'Position');
            % create xSlider
            handles.xSlider = uicontrol('Style', 'slider',...
                                'Units','normalized',...
                                'Parent',handles.axhParent,...
                                'Min',minXLim,'Max',maxXLim-diff(limX),'Value',limX(1),...
                                'Position', [axhPosNew(1), axhPosNew(2)-0.155, axhPosNew(3), 0.04],...
                                'Tag','xSlider',...
                                'Callback', @xSlider_Callback);                


            % create x axes orientation window
            xWinPos = handles.axhPos .* [1, 0.63, 0.85, 0.15];
            handles.xWin = axes('Units','normalized',...
                               'Parent',handles.axhParent,...
                               'Position',xWinPos,...
                               'Color',BgColor,...
                               'XColor',xtickColor,...
                               'YColor','none',...
                               'NextPlot','add',...
                               'Clipping','on',...
                               'Box','off',...
                               'HitTest','off',...
                               'PickableParts','none',...
                               'XScale',xscale,...
                               'FontSize',7,...
                               'Tag','xWin');                   


            % create ySlider
            handles.ySlider = uicontrol('Style', 'slider',...
                                'Units','normalized',...
                                'Parent',handles.axhParent,...
                                'Min',minYLim,'Max',maxYLim-diff(limY),'Value',limY(1),...
                                'Position', [axhPosNew(1)+axhPosNew(3)+0.026, axhPosNew(2), 0.03, axhPosNew(4)],...
                                'Tag','ySlider',...
                                'Callback', @ySlider_Callback);

            % create y axes orientation window
            yWinPos = [axhPosNew(1)+axhPosNew(3)+0.06, axhPosNew(2), axhPosNew(3)*0.15, axhPosNew(4)];
            handles.yWin = axes('Units','normalized',...
                               'Parent',handles.axhParent,...
                               'Position',yWinPos,...
                               'YAxisLocation','right',...
                               'Color',BgColor,...
                               'XColor','none',...
                               'YColor',ytickColor,...
                               'NextPlot','add',...
                               'Clipping','on',...
                               'Box','off',...
                               'HitTest','off',...
                               'PickableParts','none',...
                               'yScale',yscale,...
                               'FontSize',7,...
                               'Tag','yWin');
                
            % hold axes on for multiple signals
            hold(handles.xWin,'on')
            hold(handles.yWin,'on')
            
            for i=1:length(y)
                handles.hLineX(i) = plot(handles.xWin,x{i},y{i});
                handles.hLineY(i) = plot(handles.yWin,x{i},y{i});                
            end            

            axis(handles.xWin,'tight')
            axis(handles.yWin,'tight')
            % get window y-axis limits
            ylimxWin = get(handles.yWin,'YLim');
            
            % create x zoom window
            set(handles.hfig,'CurrentAxes',handles.xWin)
            handles.hZoomXWin = rectangle('Position',[limX(1),ylimxWin(1),diff(limX),diff(ylimxWin)],...
                                          'LineWidth',2,...
                                          'LineStyle','-',...
                                          'EdgeColor','k',...
                                          'Clipping','on',...
                                          'HitTest','off',...
                                          'PickableParts','none');
                                             
            hold(handles.xWin,'off')
            
            % get window x-axis limits
            xlimyWin = get(handles.yWin,'XLim');
            
            % create y zoom window
            set(handles.hfig,'CurrentAxes',handles.yWin)
            handles.hZoomYWin = rectangle('Position',[xlimyWin(1),limY(1),diff(xlimyWin),diff(limY)],...
                                          'LineWidth',2,...
                                          'LineStyle','-',...
                                          'EdgeColor','k',...
                                          'Clipping','on',...
                                          'HitTest','off',...
                                          'PickableParts','none');
            
            hold(handles.yWin,'off')

            axis(handles.xWin,'tight')
            axis(handles.yWin,'tight') 
            
            % back to main axes
            set(handles.hfig,'CurrentAxes',axh)
            % save limits
            handles.limX = limX;
            handles.limY = limY;
            
            % save handles
            setappdata(axh,'zoomOrientation',handles)

            % Wait until UserData has changed
            waitfor(handles.axhParent,'UserData')
            
        case 'update'
            % xlim and ylim
            limX = get(axh,'XLim');
            limY = get(axh,'YLim');
            
            % extract data from plot
            y = get(get(axh,'children'),'Ydata');
            x = get(get(axh,'children'),'Xdata');
            
            % in case there is only one trace in the plot => change XData and YData into cell
            if iscell(y)==0
                xtmp = x;
                x = cell(1);
                x{1} = xtmp;
                ytmp = y;
                y = cell(1);
                y{1} = ytmp;
            end
            
            % for SignalViewer only!
            for i=1:length(y)
                % delete signal dummies
                if sum(y{i}) == 10 && sum(x{i}) == 55
                    y{i} = [];
                    x{i} = [];
                end
            end
            
            % delete empty cells
            x = x(~cellfun('isempty',x));
            y = y(~cellfun('isempty',y));
            
            maxXLim = NaN;
            maxYLim = NaN;
            minXLim = NaN;
            minYLim = NaN;
            % get axis limits of plot data and compare to current axis limits
            for i=1:length(y)
                maxXLim = max([maxXLim limX(2) max(x{i})]);
                minXLim = min([minXLim limX(1) min(x{i})]);
                maxYLim = max([maxYLim limY(2) max(y{i})]);
                minYLim = min([minYLim limY(1) min(y{i})]);
            end
            
            % save limits in handle
            handles.dataLim = [minXLim maxXLim minYLim maxYLim];
        case 'off'
            handles = getappdata(axh,'zoomOrientation');
            % change userdata to resume zoomOrientation
            set(handles.axhParent,'UserData',1)
            delete(handles.xSlider)
            delete(handles.ySlider)
            delete(handles.xWin)
            delete(handles.yWin)
            % resizes main axes
            set(axh,'Position',handles.axhPos)
            
        otherwise
            errordlg('Function input 2 - unknown state','zoomOrientation') 
            return % end function
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %                                                                         %
    %   Callbacks                                                             %
    %                                                                         %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % slider moved
    function xSlider_Callback(hObject,~)
        value = get(hObject,'Value');
        
        handles = getappdata(axh,'zoomOrientation');
        pos = get(handles.hZoomXWin,'Position');
        set(handles.hZoomXWin,'Position',[value pos(2) pos(3) pos(4)]);
        set(axh,'XLim',handles.limX - diff([value handles.limX(1)]))
    end
    % slider moved
    function ySlider_Callback(hObject,~)
        value = get(hObject,'Value');
        
        handles = getappdata(axh,'zoomOrientation');
        pos = get(handles.hZoomYWin,'Position');
        set(handles.hZoomYWin,'Position',[pos(1) value pos(3) pos(4)]);
        set(axh,'YLim',handles.limY - diff([value handles.limY(1)]))        
    end
    % ActionPostCallback for mouse clicks
    function MouseAction(~,~)
        handles = getappdata(axh,'zoomOrientation');
        % get new limits
        handles.limX = get(axh,'XLim');
        handles.limY = get(axh,'YLim');
        
        % update sliders        
        set(handles.xSlider,'Max',handles.dataLim(2) - diff(handles.limX))
        set(handles.ySlider,'Max',handles.dataLim(4) - diff(handles.limY))
        set(handles.xSlider,'Value',handles.limX(1))
        set(handles.ySlider,'Value',handles.limY(1))
        
        % check if axes is in full view, disable slider
        if get(handles.xSlider,'Min') == handles.limX(1) && get(handles.xSlider,'Max') == handles.limX(1)
            set(handles.xSlider,'Enable','inactive')
        else
            set(handles.xSlider,'Enable','on')
        end
        
        if get(handles.ySlider,'Min') == handles.limY(1) && get(handles.ySlider,'Max') == handles.limY(1)
            set(handles.ySlider,'Enable','inactive')
        else
            set(handles.ySlider,'Enable','on')
        end
        Test = {'Min: ' get(handles.xSlider,'Min'); 'Max: ' get(handles.xSlider,'Max'); 'Value: ' handles.limX(1)}
        Test = {'Min: ' get(handles.ySlider,'Min'); 'Max: ' get(handles.ySlider,'Max'); 'Value: ' handles.limY(1)}
%         Test2 = {'Max: ' get(handles.xSlider,'Max')}
%         Test2 = {'Max: ' get(handles.ySlider,'Max')}
        
        % update y zoom window        
        pos = get(handles.hZoomXWin,'Position');
        set(handles.hZoomXWin,'Position',[handles.limX(1),pos(2),diff(handles.limX),pos(4)]);                                             
        % update y zoom window        
        pos = get(handles.hZoomYWin,'Position');    
        set(handles.hZoomYWin,'Position',[pos(1),handles.limY(1),pos(3),diff(handles.limY)]);
        
        % save handles
        setappdata(axh,'zoomOrientation',handles)
    end
end