function VolVTemplateEditor(varargin)
    global data % I find this to be useful when writing code - automatic field completion
                % how does it interfere with running normal running?
    VolVTemplateEditorTag = 'figure_VolVTemplateEditor';
    CallingObject = gcbo();
    if isempty(CallingObject)
        % Called from the commandline.
        f = getappdata( 0, VolVTemplateEditorTag );
        if ishghandle( f )
            % Figure exists.  Bring it to the front.
            figure( f );
        else
            % Figure does not exist.  Create  it.
            createVolVTemplateEditor();
        end
    else
        % VolVTemplateEditor has been invoked as a callback.
        CallingObjectName = get( CallingObject, 'tag' );
        fprintf( 1, '%s callback for ''%s''.\n', mfilename(), CallingObjectName );
        if ~isempty(CallingObjectName)
            PanelH = getappdata( 0, VolVTemplateEditorTag );
            data=guidata(PanelH);
            fh = str2func(CallingObjectName);
            data = fh(data);
            guidata(PanelH,data);
        end
    end
end

function deleteWindow( name )
    h = getappdata( 0, name );
    if ishghandle(h)
        delete(h);
    end
end

function VolVTemplateEditorQuit( varargin )
           % data.VO=commandsVOL(data.VO,'set_close');
    userdata=get(varargin{1},'Userdata');
    if isfield(userdata,'VO');
        VO=userdata.VO;
        if ~isempty(VO)
            commandsVOL(VO,'set_close');
        end
    end
    deleteWindow( 'Plotting_VolVTemplateEditor' );
    deleteWindow( 'figure_VolVTemplateEditor' );
end

function data=initialise(data)
    PanelH=data.PanelH;
    set(PanelH,'CloseRequestFcn', @VolVTemplateEditorQuit );
    set(PanelH,'HandleVisibility','callback'); % prevent panel closing on close all
    %set(PanelH,'HandleVisibility','off'); % prevent panel closing on close all
    objH=findobj(PanelH,'type','uimenu'); % find all names of all objects that could callback
    % temporary setup menu callbacks here
    for i=1:length(objH)
        if isempty(get(objH(i),'Children'))
            %disp(get(H(i),'tag'))
            set(objH(i),'callback','VolVTemplateEditor');
        end
    end
    objH2=findobj(PanelH,'type','uicontrol'); % find all names of all objects that could callback
    %     h=findobj(data.Panel,'type','uicontrol');
    %     set(h,'backgroundcolor',[0.95,1,1])
    %     set(data.Panel,'color',[0.85,1,1])
    set(findobj(data.PanelH,'tag','pushbutton_ping_volviewer'),'BackgroundColor','r','enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_load_image_stack'),'enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_load_msr_data'),'enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_save_msr_data'),'enable','off');
    
    printSetupCode([objH;objH2]);
    % must do these setups first
    %data.markers=false;
    data=menu_replot(data);
    data=menu_controls_to_top_left(data);
end

function data = createVolVTemplateEditor()
    data = [];
    PanelH = modelessRSSSdialogFromFile( 'VolVTemplateEditorLayout.txt' );
    if ~isempty(PanelH)
        set(PanelH,'CloseRequestFcn',@VolVTemplateEditorQuit);
        setappdata( 0, 'figure_VolVTemplateEditor', PanelH );
        data.PanelH=PanelH;
        data=initialise(data);
        guidata(PanelH,data);
    end
end

function data=menu_replot(data)
    if nargin<2
        dynamicOnly=false;
    end
    if ~isfield(data,'FigH')
        % place plot figure to the right
        pos=get(data.PanelH,'Position');
        FigH=figure();
        posfig=[pos(1)+pos(3)+7, pos(2)+1, 500, pos(4)-29];
        set(FigH,'position',posfig,'Name','VolVTemplateEditor','tag','Plotting_VolVTemplateEditor');
        set(FigH,'CloseRequestFcn',@VolVTemplateEditorQuit);
        %set(FigH,'HandleVisibility','off'); % prevent panel closing on close all,
        set(FigH,'HandleVisibility','callback'); % prevent panel closing on close all,
        setappdata( 0, 'Plotting_VolVTemplateEditor', FigH );
        data.AxesH=axes('Parent',FigH); % needs handle to be specified now that it is hidden
        set(data.AxesH,'tag','mainplottingaxes','XLimMode','manual','YLimMode','manual','ZLimMode','manual');
    end
    figure(FigH);
    data.FigH=FigH;
end


% ----------  The following is only present to help create the code -----------%
function     printSetupCode(H)
    cases={};
    casehandlers={};
    casesetups={};
    casecallsetups={};
    for i=1:length(H)
        name=get(H(i),'tag');
        type=get(H(i),'type');
        if exist(name,'file')==2
            % fprintf( 1, '%s exists already\n',name);
        else
            if strcmpi(type,'uimenu')
                if isempty(get(H(i),'children'))
                    cases{end+1}=sprintf('case ''%s''\ndata=%s(arg);\n',name,name);
                    casesetups{end+1}=sprintf('function data=%sSetup(data)\nend\n',name);
                    casecallsetups{end+1}=sprintf('data=%sSetup(data);\n',name);
                    casehandlers{end+1}=sprintf('function data=%s(data)\nend\n',name);
                end
            elseif strcmpi(type,'uicontrol')
                if ~isempty(name)
                    cases{end+1}=sprintf('case ''%s''\ndata=%s;\n',name,name);
                    casesetups{end+1}=sprintf('function data=%sSetup(data)\nend\n',name);
                    casecallsetups{end+1}=sprintf('data=%sSetup(data);\n',name);
                    casehandlers{end+1}=sprintf('function data=%s(data)\nend\n',name);
                end
            end
        end
    end
    if ~isempty(casehandlers)
        disp('\n\nPlease add the following to the existing program')
        disp('%-------------')
        s=sort(casehandlers);
        for i=1:length(cases)
            fprintf(1,'%s',s{i});
        end
        %         disp('%-------------')
        %         s=sort(casesetups);
        %         for i=1:length(cases),fprintf(1,'%s',s{i}),end
        %         disp('%-------------')
        %         disp('function data=DoSetups(data)');
        %         s=sort(casecallsetups);
        %         for i=1:length(cases),fprintf(1,'%s',s{i}),end
        %         disp('end')
        %         disp('%-------------')
    end
end

function data=menu_close_template(data) %#ok<DEFNU>
    fprintf( 1, 'menu_close_template is not implemented.\n' );
end

function data=menu_compute_more_stages(data) %#ok<DEFNU>
    fprintf( 1, 'menu_compute_more_stages is not implemented.\n' );
end

function data=menu_controls_to_top_left(data)
    screensize=get(0,'ScreenSize');
    pos=get(data.PanelH,'Position');
    pos(1)=5;
    pos(2)=screensize(4)-pos(4)-50;
    set(data.PanelH,'Position',pos);
    posfig=[pos(1)+pos(3)+7, pos(2)+1, pos(4)-29, pos(4)-29];
    %posfig=[pos(1)+pos(3)+7, pos(2)+1, 500, pos(4)-29];
    FigH=data.FigH;
    if ishandle(FigH)
        figure(FigH);
        set(FigH,'position',posfig,'Name','VolVTemplateEditor');
    end
end


function data=menu_new_template(data) %#ok<DEFNU>
    answer=questdlg('Default or custom model?','Select type of model','Default','Custom','Default');
    if isempty(answer)
        return
    elseif strcmpi(answer,'Custom')
        data.CustomMode=true;
    else
        data.CustomMode=false;
    end
    data=ResetStaticPlotPropsH(data); % static
    data=ResetDynamicPlotPropsH(data);% dynamic
    cla(data.AxesH);

    %Insert the different components one at a time
%     [data,cancelled]=create_cellitself(data);
%     if cancelled
%         return;
%     end
    % Create organelles
    [data,cancelled,OrganelleList]=create_cellprops(data);
    if cancelled
        return;
    end
    % delete the old
    cla(data.AxesH);
    % create the new
    data.iterations = 0;
    data.templatename = '';
    data.parentdir = '';
    data.factorprops = emptyFactorProps();
    % 
    % tidy up the data structures to look nice and alphabetical
    % start setting up the working data structure
    data=orderfields(data);
    fields=fieldnames(data);
    for i=1:length(fields)
        field=fields{i};
        if isstruct(data.(field))
            data.(field)=orderfields(data.(field));
        end
    end
    % finally sort out the working data structure
    data=ResetWorkingStructure(data);
    update_control_panel(data);
    data=menu_replot(data);
    if data.CustomMode
        data=menu_save_template_as(data);
    end
end

function data=menu_open_template(data) %#ok<DEFNU>
    startdir = pwd();
    while true
        dirname = uigetdir( startdir, 'Select a template directory' );
        if isnumeric(dirname)
            % User cancelled.
            return;
        end
        [parentdir,basedir] = fileparts( dirname );
        fullmodelfile = fullfile( dirname, [basedir, '.mat'] );
        if exist( fullmodelfile, 'file' )
            data = loadtemplate( data, fullmodelfile );
            % update models
            if ~isfield(data.plotprops,'markers')
                data.markers=false;
            end
            return;
        end
        queryDialog( 1, 'Not found', '%s is not a template directory', dirname );
    end
end

function data = loadtemplate( data, templatefile )
    d=load(templatefile);
    d = upgradeData( d );
    data = setFromStruct( data, d );
    [templatedir, data.templatename] = fileparts( templatefile );
    data.parentdir = fileparts( templatedir );
    fprintf(1, 'template data from %s loaded.\n',templatefile);
    data=update_control_panel(data);
    data=update_organelle_menus(data);
    data=ResetStaticPlotPropsH(data); % clear static organelles
    data=ResetDynamicPlotPropsH(data);% clear dynamic organelles - eg. microtubules
    cla(data.AxesH);
    % should now have got rid of all handles except the fig. and main axis.
    set( data.PanelH, 'Name', data.templatename );
    data=menu_replot(data);
end


function data=menu_show_template_on_desktop(data) %#ok<DEFNU>
    if isempty(data)
        return;
    end
    templatedir = gettemplateDir( data );
    if isempty( templatedir )
        queryDialog( 1, '', 'The model must first be saved as a template.' );
        return;
    end
    [s,d] = opendir( templatedir );
    if (s ~= 0) && ~isempty(d)
        complain( 'Error %d: %s\n', s, d );
    end
end

function data=menu_save_template_as(data) %#ok<DEFNU>
    while true
        gotName = false;
        result = performRSSSdialogFromFile( 'MTboxNewtemplateLayout.txt' );
        if isempty(result)
            return;
        end
        proposedtemplatedir = [ result.prefix result.basename result.suffix ];
        if isempty(proposedtemplatedir)
            return;
        end
        templatename = makeFunctionName( proposedtemplatedir );
        if isempty(templatename)
            queryDialog( 1, '', ...
                '%s is not a valid template name.  Must contain only%cletters, digits, or underscore, and begin with a letter.', ...
                proposedtemplatedir, char(10) );
            continue;
        elseif ~strcmp( proposedtemplatedir, templatename )
            response = queryDialog( 3, '', ...
                '%s is not a valid template name.  Change it to %s?', ...
                proposedtemplatedir, templatename );
            switch response
                case 1 % Yes
                    gotName = true;
                case 2 % No, try again
                    continue;
                case 3 % No, give up
                    return;
            end
        else
            gotName = true;
        end
        if gotName
            parentname = uigetdir( pwd(), 'Select a directory' );
            if isempty(parentname) || isnumeric(parentname)
                % User cancelled.
                return;
            end
            [success,msg,msgid] = mkdir( parentname, templatename );
            if success==1
                if isempty(msg)
                    % Success.
                    fulltemplatedir = fullfile( parentname, templatename );
                    break;
                else
                    answer = queryDialog( 3, 'Directory already exists', ...
                        'A directory ''%s'' already exists. Use it?', templatename );
                    switch answer
                        case 1 % Yes
                            fulltemplatedir = fullfile( parentname, templatename );
                            break;
                        case 2 % No, try again
                            continue;
                        case 3 % Cancel
                            return;
                    end
                end
            else
                % Could not create.
                answer = queryDialog( 2, 'Cannot create', ...
                    'Could not create ''%s'' (%s). Try again?', basename, msgid );
                switch answer
                    case 1 % Yes
                        continue;
                    case 2 % No, give up
                        return;
                end
            end
        end
    end
    % Phew.  We now have a name and host directory for the new template.
    
    if isempty( data.templatename )
        oldtemplatedir = '';
    else
        oldtemplatedir = fullfile( data.parentdir, data.templatename );
    end
    [data.parentdir, data.templatename] = fileparts( fulltemplatedir );
    olddir = trymkdircd( fulltemplatedir );
    if isempty(olddir)
        queryDialog( 1, 'Cannot find template directory %s.', fulltemplatedir );
    else
        if isempty( oldtemplatedir )
            % We are saving the current state of the structure as a new
            % template.
            data.iterations = 0;
        else
            % Copy everything from the old template to the new template
            % except stuff we specifically don't want to copy.
            includes = {};
            excludes = { ...
                '^movies$', ...
                '^snapshots$', ...
                '^runs$', ...
                '^\.', ... % Dot files.
                '\~$', ... % Matlab backup files.
                '\.asv$'}; % Matlab backup files.
            copyFilesAndFolders( oldtemplatedir, fulltemplatedir, ...
                includes, excludes );
        end
        saveCurrentState( data );
        set( data.PanelH, 'Name', data.templatename );
    end
    if ~isempty(olddir)
        cd( olddir );
    end
end

function templatedir = gettemplateDir( data )
    if isfield(data,'templatename') && ~isempty(data.templatename)
        templatedir = fullfile(data.parentdir, data.templatename);
    else
        templatedir = '';
    end
end

function olddir = goToMTtemplateDir( data )
    templatedir = gettemplateDir( data );
    if isempty( templatedir )
        olddir = '';
    else
        olddir = trycd( templatedir );
    end
end

function data=menu_snapshot(data) %#ok<DEFNU>
    fprintf( 1, 'menu_snapshot is not implemented.\n' );
    
    % Take a snapshot.
    % Generate a name for the snapshot file, from the template name and the
    % iteration count, plus a unique suffix.
    % Save it in the template directory, snapshots subdirectory.
end

function data=menu_start_movie_recording(data) %#ok<DEFNU>
    fprintf( 1, 'menu_start_movie_recording is not implemented.\n' );
    
    % Go to the movies directory in the template drectory.
    % Generate a name for the movie.
    % Start the movie going.
    % cd to the previous directory.
end

function data=menu_stop_movie_recording(data) %#ok<DEFNU>
    fprintf( 1, 'menu_stop_movie_recording is not implemented.\n' );
    
    % Go to the movies directory in the template drectory.
    % Close the movie.
    % cd to the previous directory.
    % The cd-ing is necessary because on at least one platform, the movie
    % will be saved into the current directory, regardless of the location
    % specified when the movie was opened.
end



function data=pushbutton_reset(data) %#ok<DEFNU>
    % This should only be used to recover from interaction function failure etc.
end

function data=pushbutton_restart(data) %#ok<DEFNU>
    % clear the working arrays
    data=ResetWorkingStructure(data);
    % clear factors
    fields=fieldnames( data.factorprops.Name2Index);
    for i=1:length(fields)
        factorname=fields{i};
        factortag = ['factor_' factorname];
        data.factorprops.Concentration=zeros(size(data.factorprops.Concentration));
    end
    % clear the graphics
    data=ResetDynamicPlotPropsH(data); % only clear dynamic organelles
    data=ResetFactorPropsH(data);
    delete( findobj(0,'tag','ViewVols') );
end

function setStopRequest( stopneeded )
    % Can only be called from within a callback.
    hh = guidata(gcbo);
    h = findobj(hh.PanelH,'tag','pushbutton_stop');
    if ishghandle(h)
        ud = get(h,'Userdata');
        if isempty(ud)
            ud = struct( 'stopneeded', stopneeded );
        elseif ud.stopneeded==stopneeded
            return;
        else
            ud.stopneeded = stopneeded;
        end
        set( h, 'Userdata', ud );
        if stopneeded
            fprintf( 1, 'Stop request received from user.\n' );
        else
            fprintf( 1, 'Stop request fulfilled.\n' );
            set (h,'value',0,'backgroundcolor',[0.8 0.8 0.8]);
        end
    end
end

function stopneeded = stopWasRequested()
    % Can only be called from within a callback.
    hh = guidata(gcbo);
    h = findobj(hh.PanelH,'tag','pushbutton_stop');
    if ishghandle(h)
        ud = get(h,'Userdata');
        stopneeded = isfield(ud,'stopneeded') && ud.stopneeded;
    else
        stopneeded = false;
    end
end

%-------------
function data=ReportLine1(data)
end
function data=ReportLine2(data)
end
function data=ReportLine3(data)
end
function data=checkbox_launch_volviewer(data)
    set(findobj(data.PanelH,'tag','pushbutton_ping_volviewer'),'BackgroundColor','r','Enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_load_image_stack'),'enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_load_msr_data'),'enable','off');
    set(findobj(data.PanelH,'tag','pushbutton_save_msr_data'),'enable','off');
    if get(gcbo,'value')
        handshakeHandle=findobj(data.PanelH,'tag','pushbutton_ping_volviewer');
        data.VO=VolViewer(handshakeHandle,1,'D:\VolViewer_x64','D:\VolViewer_x64');
        if ~handshakeVOL(data.VO)
            timeoutcell=get(data.VO,'timeout');
            error(sprintf('VolViewer failed to respond within %d seconds',timeoutcell{1}))
        else
            disp('VolViewer launched successfully');
            set(findobj(data.PanelH,'tag','pushbutton_ping_volviewer'),'BackgroundColor','g','Enable','on');
            set(findobj(data.PanelH,'tag','pushbutton_load_image_stack'),'enable','on');
            set(findobj(data.PanelH,'tag','pushbutton_load_msr_data'),'enable','on');
            set(findobj(data.PanelH,'tag','pushbutton_save_msr_data'),'enable','on');
            userdata=get(data.PanelH,'Userdata');
            userdata.VO=data.VO;
            set(data.PanelH,'userdata',userdata);
        end
    else
        data.VO=commandsVOL(data.VO,'set_close');
    end
end
function data=menu_about(data)
end
function data=menu_facets(data)
end
function data=menu_lines(data)
end
function data=menu_primaries(data)
end
function data=menu_secondaries(data)
end
function data=pushbutton_load_image_stack(data)
    [FileName,PathName,FilterIndex]=uigetfile('*.png','Select an image in a stack');
    if ischar(FileName)
        data.FileName=FileName;
        data.PathName=PathName;
        pathfilename=fullfile(PathName,FileName);
        data.VO=showImageOrMSRusingVOL(data.VO, 'PathTo', PathName);
    end
end
function data=pushbutton_load_msr_data(data)
    [FileName,PathName,FilterIndex]=uigetfile('*.msr','Select an msr (results) file');
    if ischar(FileName)
        data.FileName=FileName;
        data.PathName=PathName;
        pathfilename=fullfile(PathName,FileName);
        data.VO=showImageOrMSRusingVOL(data.VO, 'PathTo', PathName,'msrFilename',FileName);
        data.MSR=msrfilereader(pathfilename);
        MSRshow(data.MSR,data.AxesH);
    end
end
function data=pushbutton_save_msr_data(data)
end
function data=pushbutton_echo_msr_data(data)
    if isfield(data,'MSR')
        MSRshow(data.MSR,data.AxesH);
    else
        fprintf(1,'No MSR data\n');
    end
end
function data=pushbutton_ping_volviewer(data)
    checkForVolViewer(data.VO); %get(data.VO,'timeout'),get(data.VO,'handshakeHandle'));
end



