function celltowerApp()
% CELLTOWERAPP
%
% Modifications:
% 08/2013: Changed to a radio button and other details (Sarah Zaranek)
% 08/2013: Incorporates a menu option for ignoring (disabling) an open
%          pool; you can toggle between Parallel and Serial Modes
%          without starting and stopping the pool.(Brett Shoelson)
% 05/2014: Updated handling of objective function
%
% Copyright 2015 The MathWorks, Inc.

% Default Parameter Values
default.towers = [15 40];
default.side   = [10 15];
default.seed   = [5  5 ];
default.tol    = [0.1 0.1];  % .0001 .1

% Initial Parameters

idx  = 1;
serialTime   = nan;
parallelTime = nan;

param.towers = default.towers(idx);
param.side   = default.side(idx);
param.seed   = default.seed(idx);
param.tol    = default.tol(idx);

% Generate Figure
figH = findobj('type', 'figure', 'tag', 'phonetowerGUI');
if ishandle(figH)
    close(figH);
end
figH = figure(...
    'name'                            , 'Phone Tower Location', ...
    'windowstyle'                     ,'normal',...
    'numbertitle'                     , 'off', ...
    'tag'                             , 'phonetowerGUI', ...
    'color'                           , [.8 .8 .8], ...
    'menubar'                         , 'none', ...
    'defaultuicontrolunits'           , 'normalized', ...
    'defaultuicontrolbackgroundcolor' , [.8 .8 .8], ...
    'defaultuicontrolfontunits'       , 'points', ...
    'defaultuicontrolfontsize'        , 11);

axes(...
    'units'           , 'normalized', ...
    'position'        , [.05 .1 .65  .8],...
    'box'             , 'on', ...
    'tag'             , 'mainaxes', ...
    'FontUnits'       , 'normalized');

% placement values
xb1=0.72;  yb1=0.80; xbw=0.13; ybh=0.05;
ybo=0.07;

uicontrol(...
    'style'           , 'text', ...
    'horizontalalignment', 'left',...
    'position'        , [xb1 yb1 xbw, ybh], ...
    'fontweight'      , 'bold', ...
    'string'          , 'Seed');
uicontrol(...
    'style'           , 'text', ...
    'horizontalalignment', 'left',...
    'position'        , [xb1 yb1-ybo xbw, ybh], ...
    'fontweight'      , 'bold', ...
    'string'          , 'Towers');
uicontrol(...
    'style'           , 'text', ...
    'horizontalalignment', 'left',...
    'position'        , [xb1 yb1-2*ybo xbw, ybh], ...
    'fontweight'      , 'bold', ...
    'string'          , 'Side');
uicontrol(...
    'style'           , 'text', ...
    'horizontalalignment', 'left',...
    'position'        , [xb1 yb1-3*ybo xbw, ybh], ...
    'fontweight'      , 'bold', ...
    'string'          , 'Tolerance');
uicontrol(...
    'style'           , 'edit', ...
    'position'        , [xb1+xbw yb1 xbw, ybh], ...
    'backgroundcolor' , 'white', ...
    'string'          , num2str(param.seed), ...
    'callback'        , @changeParamCallback, ...
    'tag'             , 'seed');
uicontrol(...
    'style'           , 'edit', ...
    'position'        , [xb1+xbw yb1-ybo xbw, ybh], ...
    'backgroundcolor' , 'white', ...
    'string'          , num2str(param.towers), ...
    'callback'        , @changeParamCallback, ...
    'tag'             , 'towers');
uicontrol(...
    'style'           , 'text', ...
    'position'        , [xb1+xbw yb1-2*ybo xbw, ybh], ...
    'string'          , num2str(param.side), ...
    'tag'             , 'side');

uicontrol(...
    'style'           , 'text', ...
    'position'        , [xb1+xbw yb1-3*ybo xbw, ybh], ...
    'string'          , num2str(param.tol), ...
    'tag'             , 'tol');

% placement values
xp1=.75;  yp1=.45; yph=.07;
ypo=.1;

newbg=[.9 .9 .9];

uicontrol(...
    'style'           , 'pushbutton', ...
    'backgroundcolor', newbg,...
    'position'        , [xp1 yp1 .2, yph], ...
    'fontweight'      , 'bold', ...
    'callback'        , @runBtnCallback, ...
    'string'          , 'Run', ...
    'tag'             , 'run');

uicontrol(...
    'style'           , 'togglebutton', ...
    'backgroundcolor', newbg,...
    'position'        , [xp1 yp1-ypo .2, yph], ...
    'fontweight'      , 'bold', ...
    'callback'        , @pauseBtnCallback, ...
    'string'          , 'Pause', ...
    'tag'             , 'pause', ...
    'enable'          , 'off');


htoggle = uibuttongroup('Position',[.71 .05 .27, .25], ...
    'backgroundcolor', newbg);

% placement values
tx1=0.05; ty1=0.01; tbx1=0.50; tby=0.33;
tx2=0.57; ty2=0.37; tbx2=0.4;
ty3=0.66;

toggleobj(1) = uicontrol('Style','Radio','String','Serial:','units','normalized',...
    'pos',[tx1 ty3 tbx1 tby],'parent',htoggle,'backgroundcolor', newbg);
toggleobj(2) = uicontrol('Style','Radio','String','Parallel:','units','normalized',...
    'pos',[tx1 ty2 tbx1 tby],'parent',htoggle,'backgroundcolor', newbg);
uicontrol(...
    'Parent', htoggle, ...
    'Style', 'text', ...
    'backgroundcolor', newbg,...
    'Position', [tx1 ty1 tbx1 tby], ...
    'HorizontalAlignment', 'left', ...
    'String', 'Speed Up: ');
hSerialTime = uicontrol(...
    'Parent', htoggle, ...
    'Style', 'text', ...
    'backgroundcolor', newbg,...
    'Position', [tx2 ty3-.06 tbx2 tby], ...
    'HorizontalAlignment', 'right', ...
    'String', '');
hParallelTime = uicontrol(...
    'Parent', htoggle, ...
    'Style', 'text', ...
    'backgroundcolor', newbg,...
    'Position', [tx2 ty2-.08 tbx2 tby], ...
    'HorizontalAlignment', 'right', ...
    'String', '');
hSpeedUp = uicontrol(...
    'Parent', htoggle, ...
    'Style', 'text', ...
    'backgroundcolor', newbg,...
    'Position', [tx2 ty1 tbx2 tby], ...
    'HorizontalAlignment', 'right', ...
    'String', '');
set(htoggle,'SelectedObject',toggleobj(1));  % Default in Serial Mode

set(findobj(figH, 'Type', 'uicontrol'), 'FontUnits', 'Normalized');
set(toggleobj, 'FontUnits', 'Normalized');

handles = guihandles(figH);

stopOptim  = false;
pauseOptim = false;

% Initialize
[dimensions, lb, ub, x0] = ...
    helper.celltowersetup(param.towers, param.side, param.seed);

helper.plotFcn(x0, 0, '', dimensions);

%-------------------------------------------------
    function changeParamCallback(obj, edata)
        
        resetTimes;
        
        tmp = str2double(get(obj, 'string'));
        
        try
            switch get(obj, 'tag')
                case 'towers'
                    validateattributes(tmp, {'double'}, {'scalar', 'integer', '>=', 3, '<=', 50}, '', '"Towers"');
                    param.side = ceil(sqrt(tmp)*2.35);    % dimension of piece of land (one side)
                    set(handles.side  , 'String', param.side);
                    %  param.tol=(1e-1)*round(((tmp/55).^2)); % dimension of piece of land (one side)
                    param.tol = 0.1;
                    set(handles.tol  , 'String', param.tol);
                case 'seed'
                    validateattributes(tmp, {'double'}, {'scalar', '>=', 0}, '', '"Seed"');
            end
        catch ME
            uiwait(errordlg(ME.message, 'modal'));
            tmp = param.(get(obj, 'tag'));
        end
        
        param.(get(obj, 'tag')) = tmp;
        set(obj, 'string', num2str(tmp));
        
        [dimensions, lb, ub, x0] = ...
            helper.celltowersetup(param.towers, param.side, param.seed);
        helper.plotFcn(x0, 0, '', dimensions);
        
    end

%-------------------------------------------------
    function runBtnCallback(obj, edata)
        
        if strcmp(get(obj, 'string'), 'Run')
            set(obj           , 'string', 'Stop');
            set(handles.pause , 'enable', 'on');
            set(handles.seed  , 'enable', 'off');
            set(handles.towers, 'enable', 'off');
            set(handles.side  , 'enable', 'off');
            set(handles.tol   , 'enable', 'off');
            
            drawnow
            options = optimset;
            options = optimset(options, 'Display'    , 'none');
            options = optimset(options, 'TolFun'     , param.tol);
            options = optimset(options, 'OutputFcn'  , {@(x,it,f) helper.plotFcn(x,it,f,dimensions), @helper.myOutputFcn, @optimControlFcn});
            options = optimset(options, 'Algorithm'  , 'active-set');
            isParallel = ~get(toggleobj(1),'Value');
            
            if isParallel
                options = optimset(options, 'UseParallel', 1);
                disp('Parallel Mode')
            else
                options = optimset(options, 'UseParallel', 0);
                disp('Serial Mode')
            end
            
            objfun = iMakeObjFun(dimensions.R);
            
            startTic = tic;
            fmincon(objfun, x0, [], [], [], [], lb, ub, [], options);
            tm = toc(startTic);
            
            % Display execution time
            if isParallel
                parallelTime = tm;
                set(hParallelTime, 'String', sprintf('%0.1f sec', parallelTime));
            else
                serialTime = tm;
                set(hSerialTime, 'String', sprintf('%0.1f sec', serialTime));
            end
            drawnow
            
            % Compute speed up if both serial and parallel time exist
            if ~isnan(serialTime) && ~isnan(parallelTime)
                set(hSpeedUp, 'String', sprintf('%0.2fx', serialTime/parallelTime));
            end
            
            if ~ishandle(figH)
                return;
            end
            
            set(obj           , 'string', 'Run');
            set(handles.pause , 'enable', 'off', 'string', 'Pause', 'value', false);
            set(handles.seed  , 'enable', 'on');
            set(handles.towers, 'enable', 'on');
            set(handles.side  , 'enable', 'on');
            set(handles.tol   , 'enable', 'on');
            stopOptim  = false;
            pauseOptim = false;
            
        else
            
            set(obj           , 'string', 'Run');
            set(handles.pause , 'enable', 'off', 'string', 'Pause', 'value', false);
            set(handles.seed  , 'enable', 'on');
            set(handles.towers, 'enable', 'on');
            set(handles.side  , 'enable', 'on');
            set(handles.tol   , 'enable', 'on');
            stopOptim  = true;
            pauseOptim = false;
            
        end
        
    end
%-------------------------------------------------

%-------------------------------------------------
    function pauseBtnCallback(obj, edata)
        pauseOptim = ~pauseOptim;
        if pauseOptim
            set(obj, 'string', 'Resume');
        else
            set(obj, 'string', 'Pause');
        end
    end
%-------------------------------------------------

%-------------------------------------------------
    function stop = optimControlFcn(x,itervals,flag)
        % Control the flow of the optimization (pause, resume, stop)
        
        if ~ishandle(figH)
            stop = true;
            return;
        end
        
        switch flag
            case {'iter', ''}
                while pauseOptim && ishandle(figH)
                    drawnow;
                end
        end
        
        stop = stopOptim;
        
    end
%-------------------------------------------------
%-------------------------------------------------

    function resetTimes()
        set(hSerialTime, 'String', '');
        set(hParallelTime, 'String', '');
        set(hSpeedUp, 'String', '');
        serialTime = nan;
        parallelTime = nan;
    end

end
function fun = iMakeObjFun(R)
fun = @(x) helper.objFcn(x, R);
end


%#ok<*INUSD>
%#ok<*INUSL>