function out = browser_detect_menu(par, str)

% browser_detect_menu - create menus for available detectors
% ----------------------------------------------------------
%
% out = browser_detect_menu(par, str)
%
% Input:
% ------
%  par - parent browser handle
%  str - command string
%
% Output:
% -------
%  out - command dependent output

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 2101 $
% $Date: 2005-11-10 15:27:34 -0500 (Thu, 10 Nov 2005) $
%--------------------------------

%---------------------------------
% SETUP
%---------------------------------

%--
% set default output
%--

out = [];

%--
% get available detectors
%--

% NOTE: consider returning if there are no detectors

DET = get_extensions('detectors');

if ~isempty(DET)
	DET_NAME = {DET.name}';
end

%---------------------------------
% HANDLE INPUT
%---------------------------------

%--
% set command string
%--

if (nargin < 2)
	str = 'Initialize';
end

%--
% check parent
%--

if ~is_browser(par)
	error('Input handle is not browser handle.');
end

%--
% get parent userdata
%--

data = get_browser(par);
	
%---------------------------------
% COMMAND SWITCH
%---------------------------------

switch (str)
	
%---------------------------------
% INITIALIZE
%---------------------------------

case ('Initialize')

	%--
	% check for existing detector menu
	%--
	
	if get_menu(par, 'Detect')
		return;
	end
		
	%---------------------------
	% DETECT
	%---------------------------
	
	%--
	% create detector menu labels
	%--
	
	detectors = strcat(DET_NAME(:), ' ...');
	
	if ischar(detectors)
		tmp = {detectors}; 
	end
	
	%--
	% create menu
	%--
	
	L = { ... 
		'Detect', ...
		'Active', ...
		detectors{:} ...
	};
	
	n = length(L); S = bin2str(zeros(1, n)); S{3} = 'on';
	
	menus = menu_group(par, 'browser_detect_menu', L, S);
	
	%--
	% set menu position
	%--
	
	set(menus(1), 'position', 7);
	
	%---------------------------
	% ACTIVE
	%---------------------------
	
	%--
	% select active detectors
	%--
	
	if (length(DET) > 1)
		ix = find(struct_field(DET, 'active'));
	else
		ix = DET.active;
	end
		
	DET_ACTIVE = DET_NAME(ix);
	
	%--
	% create menu
	%--
	
	L = { ...
		'No Detection', ...
		DET_ACTIVE{:} ...
	};

	n = length(L); S = bin2str(zeros(1, n)); S{2} = 'on';
	
	menus = menu_group(get_menu(menus, 'Active'), 'browser_detect_menu', L, S);
	
	set(get_menu(menus, 'No Detection'), 'check', 'on');
	
	%--
	% update browser state to contain detector information
	%--
		
	data.browser.detector.ext = DET;
	
	set(par, 'userdata', data);
	
%---------------------------------
% ACTIVE DETECTION
%---------------------------------

% NOTE: these menus have detector name labels

case {'No Detection', DET_NAME{:}}
	
	%--
	% set active detection state
	%--
	
	% NOTE: the active detection state is indicated by the detector name
	
	switch str
		
		case 'No Detection', data.browser.detector.active = '';
		
		otherwise, data.browser.detector.active = str;
			
	end
	
	%--
	% update active detection menu
	%--
			
	top = findobj(par, ...
		'type', 'uimenu', ...
		'label', 'Detect', ...
		'parent', par ...
	);
	
	child =  get(get_menu(top, 'Active'), 'children');
	
	set(child, 'check', 'off'); set(get_menu(child, str), 'check', 'on');
	
	%--
	% update browser state
	%--
	
	set(par, 'userdata', data);
	
	%--
	% update active detection controls in open detector palettes
	%--
	
	update_active_controls(par, 'detector', data.browser.detector.active, data);
	
	%-- 
	% stop marching ants daemon and close explain
	%--
	
	% NOTE: this is a timing issue and this is not the correct way to handle this
	
	daemon = timerfind('name', 'XBAT Marching Ants');
	
	if ~isempty(daemon)
		stop(daemon); delete(daemon);
	end
		
	% TODO: this will require extension input
	
	close_explain(par);
	
	%--
	% update display
	%--
	
	browser_view_menu(par, 'scrollbar');
	
%------------------------------------------------------------------
%------------------------------------------------------------------
% DETECTOR PALETTE
%------------------------------------------------------------------
%------------------------------------------------------------------

% NOTE: these menus have detector name and dots as labels

case strcat(DET_NAME, ' ...')
	
	%--
	% parse command string
	%--
	
	% NOTE: remove trailing space and periods from command string
	
	str = str(1:end - 4);
	
	%--
	% check for open palette and update position 
	%--
	
	% NOTE: output palette handle
	
	pal = get_palette(par, str, data);
	
	if ~isempty(pal)
		position_palette(pal, par, 'center'); return;
	end
	
	%--------------------------------------------------
	% GET EXTENSION
	%--------------------------------------------------
	
	%--
	% get detector extension
	%--
	
	ext = get_browser_extension('detector', par, str, data);
	
	%--
	% get preset names
	%--
		
	% TODO: get preset names function so we don't have to load full preset
	
	presets = get_presets(ext);
	
	if ~isempty(presets)
		preset_names = struct_field(presets, 'name');
	else
		preset_names = [];
	end

	%--------------------------------------------------
	% COMMON CONTROLS
	%--------------------------------------------------

	%--
	% detection header and tabs
	%--
	
	control(1) = control_create( ...
		'style', 'separator', ...
		'type', 'header', ...
		'space', 0.11, ...
		'string', 'Detect' ...
	);
	
	tabs = { ...
		'Active', ...
		'Persistent', ...
	};

	control(end + 1) = control_create( ...
		'style', 'tabs', ...
		'tab', tabs, ...
		'name', 'Scan Tabs' ...
	);

	%--
	% active
	%--
	
	if strcmp(data.browser.detector.active, ext.name)
		active_state = 1;
	else
		active_state = 0;
	end
	
	control(end + 1) = control_create( ...
		'name', 'active', ...
		'alias', 'On', ...
		'tab', tabs{1}, ...
		'style', 'checkbox', ...
		'callback', '', ...
		'space', 1, ...
		'value', active_state, ...
		'tooltip', ['Enable detector as active detector'] ...
	);

	%--
	% explain
	%--
	
	if strcmp(data.browser.detector.active, ext.name)
		value = 1;
	else
		value = 0;
	end
	
	control(end + 1) = control_create( ...
		'name', 'explain', ...
		'tab', tabs{1}, ...
		'style', 'checkbox', ...
		'callback', '', ...
		'space', 1.25, ...
		'value', 0, ...
		'tooltip', ['Explain active detector'] ...
	);

	
	if xbat_developer
	
		control(end).space = -1.25;
		
		control(end + 1) = control_create( ...
			'name', 'refresh', ...
			'tab', tabs{1}, ...
			'alias', 'REFRESH', ...
			'style', 'buttongroup', ...
			'align', 'right', ...
			'lines', 1.75, ...
			'width', 0.5 ...
		);

	end


	%--
	% output log
	%--
	
	% TODO: this should be a function
	
	if isempty(data.browser.log)
				
		L = {'(No Open Logs)'};
		
		aix = 1;
		
	else
				
		[L, ix] = sort(file_ext(struct_field(data.browser.log, 'file'))); % logs are sorted as in other controls
				
		aix = find(ix == data.browser.log_active);
				
	end
	
	control(end + 1) = control_create( ...
		'name', 'output_log', ...
		'tab', tabs{2}, ...
		'layout', 'normal', ...
		'type', 'slider_length', ...
		'tooltip', 'Log to output detections to', ...
		'style', 'popup', ...
		'space', 0.75, ...
		'lines', 1, ...
		'string', L, ...
		'value', aix ...
	);

	%--
	% scan
	%--
	
	control(end + 1) = control_create( ...
		'name', 'scan', ...
		'tab', tabs{2}, ...
		'style', 'buttongroup', ...
		'width', 0.5, ...
		'align', 'right', ...
		'space', 1.25, ...
		'lines', 1.75, ...
		'tooltip', ['Begin persistent detection scan'] ...
	);

	%--------------------------------------
	% DETECTOR CONTROLS
	%--------------------------------------

	%--
	% get detector controls from extension
	%--
	
	detector_controls = [];
	
	if ~isempty(ext.fun.parameter.control.create)
		
		%--
		% compile context
		%--
		
		context.sound = data.browser.sound; context.ext = ext;
		
		%--
		% get extension parameters
		%--
		
		% NOTE: create parameters if needed before controls
		
		if isempty(ext.parameter)
			ext.parameter = ext.fun.parameter.create(context);
		end
		
		%--
		% create extension controls
		%--
		
		detector_controls = ext.fun.parameter.control.create(ext.parameter, context);

		%--
		% add detection controls if needed
		%--
		
		if ~isempty(detector_controls)
			
			%--
			% add header to detector controls section
			%--

			control(end + 1) = control_create( ...
				'string', 'Parameters', ...
				'style', 'separator', ...
				'type', 'header', ...
				'space', 0.11 ...
			);

			%--
			% adjust spacing of controls if needed
			%--

			% NOTE: this adjustment should be editable, a property for the detector

			switch detector_controls(1).style

				case {'axes', 'slider'}
					control(end).space = 1.5;

				case {'buttongroup'}
					control(end).space = 1;

				case {'edit', 'popup', 'checkbox'}
					control(end).space = 0.75;

				case 'separator'
					control(end).space = 1.5;

				case 'tabs'
					control(end).space = 0.12;

			end

			%--
			% concatenate common controls and detector specific controls
			%--

			control = [control, detector_controls];
		
		end
		
	end

	%--------------------------------------------------
	% DETECTOR PALETTE OPTIONS
	%--------------------------------------------------
	
	if ~isempty(ext.fun.parameter.control.options)
		
		opt = ext.fun.parameter.control.options(context);

		opt = struct_update(control_group, opt);

	else

		%--
		% set control group options
		%--

		% provide a way for extensions to communicate these

		opt = control_group;

		opt.width = 12; % helps to display detector name

		opt.top = 0; % header starts palette

		opt.bottom = 0; % detector controls determine bottom margin

		opt.handle_to_callback = 1;

	end
	
	opt.ext = ext;
	
	opt.header_color = get_extension_color(ext);
	
	%--------------------------------------------------
	% DETECTOR PALETTE
	%--------------------------------------------------
	
	%--
	% create palette
	%--
	
	pal = control_group(par, @extension_dispatch, str, control, opt);
	
	%--
	% set palette properties
	%--
	
	% NOTE: set palette tag, key press, and close request function
	
	% control values are updated in parent as part of close request function
	
	set(pal, ...
		'tag',['XBAT_PALETTE::DETECTOR::' str], ...
		'keypressfcn',['palette_kpfun(' num2str(par) ');'], ...
		'closerequestfcn',['delete_palette(' num2str(par) ',''' str ''');'] ...
	);
	
	%--
	% register palette with parent and set parent windowbuttondown function
	%--
		
	n = length(data.browser.palettes);
	
	data.browser.palettes(n + 1) = pal;
	
	set(par, ...
		'userdata',data, ...
		'buttondown','browser_palettes(gcf,''Show'');' ...
	);
	
	%--------------------------------------------------
	% UPDATE PALETTE CONTROLS
	%--------------------------------------------------
	
	%--
	% update palette controls to reflect previous state of palette
	%--
	
	% control values are part of saved state not tab selections or toggles
	
	values = ext.control;
	
	if ~isempty(values)
		set_control_values(pal, values);
	end
	
	%--
	% update enabled state of output log control
	%--
	
	if isempty(data.browser.log)
		
		control_update([], pal, 'output_log', '__DISABLE__'); 
		
		control_update([], pal, 'scan', '__DISABLE__');
		
	end
	
	%--
	% update enabled state of active detection control
	%--
	
	if ~ext.active
		control_update([], pal, 'active', '__DISABLE__');
	end
	
	%--
	% produce a control callback
	%--			
	
	if ~isempty(values) && ~isempty(detector_controls)

		%--
		% check for and execute onload callbacks
		%--

		onload = struct_field(detector_controls, 'onload');

		if any(onload)

			for k = 1:length(onload)

				if (onload(k))
					control_callback([], pal, detector_controls(k).name);
				end

			end

		%--
		% try to produce a detector control callback
		%--

		% NOTE: this is the older code, so we are backwards compatible

		else

			% NOTE: remove button groups from detector controls

			for k = length(detector_controls):-1:1

				if strcmp(detector_controls(k).style, 'buttongroup')
					detector_controls(k) = [];
				end

			end

			fields = intersect( ...
				struct_field(detector_controls, 'name'), fieldnames(values) ...
			);

			% TODO: consider the 'onload' field first, get control model from palette

			for k = 1:length(fields)

				flag = control_callback([], pal, fields{k});

				if flag
					break;
				end

			end

		end
		
	end
		
	%--
	% position palette
	%--
	
	position_browser_palette(par, pal, data);
	
end


%-------------------------------------------------------------------------
% DETECTOR_RUN
%-------------------------------------------------------------------------

function detector_run(obj, eventdata, detector)


%-------------------------------------------------
% CREATE AND ADD GENERATION SUMMARY
%-------------------------------------------------

% NOTE: when the detector dumps detections the scan values are updated

summary = summary_create( ...
	'preset', preset, ...
	'events', struct_field(detection, 'id'), ...
	'etime', elapsed_time, ... 
	'author', author ...
); 

if isempty(log.generation)
	log.generation = summary;
else 
	log.generation(end + 1) = summary;
end


%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
% GOOD CODE FROM HERE ON
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------


%-------------------------------------------------------------------------
% EXTENSION_DISPATCH
%-------------------------------------------------------------------------

function extension_dispatch(obj, eventdata)

%--
% get callback context and default output
%--

callback = get_callback_context(obj, 'pack'); result = [];

%--
% get fresh extension
%--

ext = get_browser_extension('detector', callback.par.handle, callback.pal.name);

%----------------------------
% CALLBACKS
%----------------------------

switch callback.control.name
		
	%----------------------
	% COMMON CONTROLS
	%----------------------

	%----------------------
	% REFRESH
	%----------------------
	
	case 'refresh'
		
		disp('refresh'); return;
		
		% TODO:  get sufficient context, the dispatcher should get more
		% context
		
% 		refresh_extension(callback, context);
		
	%--
	% DETECTION
	%--
	
	%--
	% toggle active detection
	%--
	
	case 'active'
		
		if (get(callback.obj,'value') == 1)
			str = callback.pal.name; 
		else
			str = 'No Detection'; 
		end
				
		browser_detect_menu(callback.par.handle, str);
	
	%--
	% toggle active explain
	%--
	
	case 'explain'
		
		if (get(callback.obj, 'value') == 0)
			close_explain(callback.par.handle); result.update = 0;
		end
	
	%--
	% set output log for persistent scan
	%--
	
	case 'output_log'
	
		% NOTE: there is no real callback for this case at the moment
		
		result.update = 0;
		
	%--
	% perform persistent scan
	%--
	
	case 'scan'
		
		perform_detector_scan(callback, ext);
		
	%----------------------
	% EXTENSION CONTROLS
	%----------------------
		
	otherwise
		
		%--
		% sync slider if needed
		%--
		
		if has_slider(callback.control.handles)
			slider_sync(callback.obj, callback.control.handles);
		end
		
		%--
		% flash control to indicate callback
		%--
		
		% NOTE: consider hover fade behavior here
		
		control_flash(callback.control, callback.pal);

		%--
		% yield to extension callback function
		%--
		
		fun = ext.fun.parameter.control.callback;
		
		if ~isempty(fun)
			result = fun(callback);
		end
		
end

%--
% consider callback result
%--

% NOTE: the empty result is a default option

if ~isempty(result)
	
	%--
	% return if update is not required
	%--
	
	if isfield(result, 'update') && ~result.update
		return;
	end
	
end

%--
% update display 
%--

browser_view_menu(callback.par.handle, 'scrollbar');


%-------------------------------------------------------------------------
% CLOSE_EXPLAIN
%-------------------------------------------------------------------------

function close_explain(par)

% TODO: add extension to input to handle multiple extensions explaining 
	
%--
% find and delete explain figure with parent
%--

explain = get_xbat_figs( ...
	'parent', par, 'type', 'explain' ...
);

if ~isempty(explain)
	delete(explain);
end


%-------------------------------------------------------------------------
% PERFORM_DETECTOR_SCAN
%-------------------------------------------------------------------------

function perform_detector_scan(callback, ext)

%--
% unpack callback
%--

pal = callback.pal; par = callback.par;

%--------------------------------
% SETUP
%--------------------------------

%--
% get sound and channels
%--

data = get_browser(par.handle);

sound = data.browser.sound; channels = get_channels(data.browser.channels);

%--
% get scan
%--

% TODO: add scan control to palette, intersect sound scan with palette scan

scan = get_sound_scan(sound);

% NOTE: we disregard time stamps while reading

sound.time_stamp = [];

%--
% get output log
%--

output_log = get_control(pal.handle, 'output_log', 'value');

if iscell(output_log)
	output_log = output_log{1};
end

[log, pos] = get_browser_logs(par.handle, 'name', output_log);

%--------------------------------
% DETECT
%--------------------------------

%--
% pack context
%--

context = detector_context(ext, sound, scan, channels, log, par.handle, data);

%--
% scan and update log
%--

data.browser.log(pos) = detector_scan(context);

% NOTE: next two lines are still needed, they are old

set(par.handle, 'userdata', data);

browser_display(par.handle);
