function out = browser_filter_menu(par, str)

% browser_filter_menu - create menus for filters extensions
% ---------------------------------------------------------
%
% out = browser_filter_menu(par, str)
%
% Input:
% ------
%  par - browser handle
%  str - command string
% 
% Output:
% -------
%  out - command dependent output

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 2173 $
% $Date: 2005-11-22 00:26:27 +0100 (Tue, 22 Nov 2005) $
%--------------------------------

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

% NOTE: consider returning if there are no filters at all

%--
% get and sort able signal filters 
%--

SIG_FILTER = get_able_extensions('signal_filters');

if ~isempty(SIG_FILTER)
	
	SIG_FILTER_NAME = {SIG_FILTER.name}';

	category = get_extension_categories(SIG_FILTER);
	
	SIG_CATEGORY = {category.name}';
	
	SIG_CATEGORY_FILTER = {category.children}';
	
else
	
	SIG_FILTER_NAME = cell(0);
	
	SIG_CATEGORY = cell(0); SIG_CATEGORY_FILTER = cell(0);
	
end

%--
% get and sort able image filters
%--

IMG_FILTER = get_able_extensions('image_filters');

if ~isempty(IMG_FILTER)
	
	IMG_FILTER_NAME = {IMG_FILTER.name}';

	category = get_extension_categories(IMG_FILTER);
	
	IMG_CATEGORY = {category.name}';
	
	IMG_CATEGORY_FILTER = {category.children}';

else
	
	IMG_FILTER_NAME = cell(0);
	
	IMG_CATEGORY = cell(0); IMG_CATEGORY_FILTER = cell(0);
	
end

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

%--
% set default command string
%--

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

% NOTE: set command as default output

out = str;

%--
% set default parent figure
%--

if (nargin < 1)
	par = gcf;
end

%--
% get parent state
%--

data = get_browser(par);

%----------------------------------------------------------------------
% COMMAND SWITCH
%----------------------------------------------------------------------

switch str

%------------------------------------------------
% INITIALIZE
%------------------------------------------------

case 'Initialize'

	%--
	% check for existing filter menu
	%--
	
	if get_menu(par, 'Filter')
		return;
	end
	
	%-------------------------
	% Filter
	%-------------------------
		
	L = { ... 
		'Filter', ...
		'(Active)', ...
		'Signal', ...
		'Image' ...
	};
	
	n = length(L); 
	
	S = bin2str(zeros(1, n));
	
	g = menu_group(par, 'browser_filter_menu', L, S);

	%--
	% position top menu and disable header
	%--
	
	% NOTE: the top menu is used in later parts of code
	
	g1 = g(1);
	
	set(g1,'position',5); 
	
	set(g(2),'enable','off');

	%-------------------------
	% Active
	%-------------------------
		
	%--
	% Signal
	%--
	
	if ~isempty(SIG_FILTER)
		
		SIG_FILTER_ACTIVE = SIG_FILTER_NAME;
		
		L = {'No Filter', SIG_FILTER_ACTIVE{:}}; n = length(L); 
		
		S = bin2str(zeros(1,n)); S{2} = 'on';
		
		temp = menu_group(get_menu(g, 'Signal'), 'browser_filter_menu', L, S);
		
		set(get_menu(temp, 'No Filter'), 'check', 'on');
		
		set(temp, 'tag', 'signal_filter');
		
	else
		
		temp = get_menu(g, 'Signal'); g = setdiff(g, temp); delete(temp);
				
	end
	
	%--
	% Image
	%--
		
	if ~isempty(IMG_FILTER)
		
		IMG_FILTER_ACTIVE = IMG_FILTER_NAME;
		
		L = {'No Filter', IMG_FILTER_ACTIVE{:}}; n = length(L);
		
		S = bin2str(zeros(1,n)); S{2} = 'on';
		
		temp = menu_group(get_menu(g, 'Image'), 'browser_filter_menu', L, S);
		
		set(get_menu(temp, 'No Filter'), 'check', 'on');
		
		set(temp, 'tag', 'image_filter');
		
	else
		
		temp = get_menu(g, 'Image'); g = setdiff(g, temp); delete(temp);
						
	end
	
	%-------------------------
	% Signal
	%-------------------------
	
	if ~isempty(SIG_FILTER)
						
		%--
		% create signal filter header menu
		%--
				
		uimenu(g1, ...
			'label', '(Signal)', ...
			'separator', 'on', ...
			'enable', 'off' ...
		);
		
		%--
		% create filter category menus
		%--
		
		% NOTE: the logic here is correct but quirky
		
		if (length(SIG_CATEGORY) > 1) && isempty(SIG_CATEGORY{1})
			ki = 2;
		else
			ki = 1;
		end
			
		for k = ki:length(SIG_CATEGORY)
			
			%--
			% create extension category menu
			%--
	
			if isempty(SIG_CATEGORY{k})
				temp = uimenu(g1, 'label', 'Other');
			else
				temp = uimenu(g1, 'label', SIG_CATEGORY{k});
			end
			
			%--
			% add category filters menu
			%--
			
			temp2 = menu_group(temp, 'browser_filter_menu', strcat(SIG_CATEGORY_FILTER{k}, ' ...'));
		
			set(temp2, 'tag', 'signal_filter');
			
		end
				
		%--
		% create 'Other' category menu
		%--
		
		if (ki == 2)
			
			temp = uimenu(g1, 'label', 'Other');
		
			temp2 = menu_group(temp, 'browser_filter_menu', strcat(SIG_CATEGORY_FILTER{1}, ' ...'));
			
			set(temp2, 'tag', 'signal_filter');
			
		end
		
	end

	%-------------------------
	% Image Filters
	%-------------------------
	
	if ~isempty(IMG_FILTER)
			
		%--
		% create image filters header menu
		%--
		
		uimenu(g1, ...
			'label', '(Image)', ...
			'separator', 'on', ...
			'enable', 'off' ...
		);
	
		%--
		% create filter category menus
		%--
		
		if (length(IMG_CATEGORY) > 1) & isempty(IMG_CATEGORY{1})
			ki = 2;
		else
			ki = 1;
		end
			
		for k = ki:length(IMG_CATEGORY)
			
			%--
			% create category menu
			%--
	
			if isempty(IMG_CATEGORY{k})
				temp = uimenu(g1, 'label', 'Other');
			else
				temp = uimenu(g1, 'label', IMG_CATEGORY{k});
			end
			
			%--
			% add category filters menu
			%--
			
			temp2 = menu_group(temp, 'browser_filter_menu', strcat(IMG_CATEGORY_FILTER{k}, ' ...'));
		
			set(temp2, 'tag', 'image_filter');
			
		end
				
		%--
		% create other category menu
		%--
		
		if (ki == 2)
			
			temp = uimenu(g1, 'label', 'Other');
		
			temp2 = menu_group(temp, 'browser_filter_menu', strcat(IMG_CATEGORY_FILTER{1}, ' ...'));
			
			set(temp2, 'tag', 'image_filter');
			
		end
		
	end
	
	%--
	% create filter extension registry
	%--
	
	% NOTE: initialized extensions contain default parameters given context
	
	context.sound = data.browser.sound; 
	
	data.browser.signal_filter.ext = extension_initialize(SIG_FILTER, context);
	
	data.browser.image_filter.ext = extension_initialize(IMG_FILTER, context);
	
	%--
	% update state
	%--
	
	set(par, 'userdata', data);

%------------------------------------------------
% ACTIVE FILTER
%------------------------------------------------

%--
% turn off active filter
%--

case { ...
	'No Filter', 'No Signal Filter', 'No Image Filter' ...
}
	
	%--
	% get type of filter
	%--
	
	% NOTE: this code is too complicated, it should not be
	
	type = '';
	
	switch str

		% NOTE: these cases are for programmatic control of the filter state
		
		case 'No Signal Filter', type = 'signal_filter';
			
		case 'No Image Filter', type = 'image_filter';
	
		% NOTE: type is obtained through callback object
		
		otherwise

			switch get(gcbo, 'type')
				
				case 'uimenu'
					
					type = get(gcbo, 'tag');
			
				case 'uicontrol'
					
					pal = ancestor(gcbo, 'figure');
					
					name = get(pal, 'name');
					
					type = extension_type_from_name(name);
					
			end
			
	end
	
	% NOTE: return if we were unable to determine type
	
	if isempty(type)
		return;
	end
	
	%--
	% turn off active filter of given type
	%--
	
	data.browser.(type).active = '';
		
	set(par, 'userdata', data);
	
	%--
	% update active detection menu
	%--
		
	% TODO: move this code to update active controls, menus are controls
	
	g = findobj(par, ...
		'type', 'uimenu', 'label', 'Filter', 'parent', par ...
	);
	
	% NOTE: we are using the label variable to get the menus that need updating
	
	g =  get(get_menu(g, strtok(title_caps(type), ' ')), 'children');	
	
	set(g, 'check', 'off');
	
	set(get_menu(g, 'No Filter'), 'check', 'on');
	
	%--
	% update active detection controls in available palettes
	%--
	
	update_active_controls(par, type, data.browser.(type).active, data);

	%--
	% update display
	%--
	
	browser_display(par, 'update', data);
			
%--
% set active filter
%--

case { ...
	SIG_FILTER_NAME{:}, IMG_FILTER_NAME{:} ...
}
	
	%--
	% get type of filter to activate
	%--
	
	type = '';
	
	if strcmp(get(gcbo, 'type'), 'uimenu')
		type = get(gcbo, 'tag');
	end
	
	if isempty(type)
		type = extension_type_from_name(str);
	end
	
	% NOTE: return if we were unable to determine type
	
	if isempty(type) || iscell(type)
		return;
	end
	
	%--
	% set active filter state
	%--

	data.browser.(type).active = str;
	
	set(par, 'userdata', data);
	
	%--
	% update active detection menu
	%--
			
	g = findobj(par, ...
		'type', 'uimenu', 'label', 'Filter', 'parent', par ...
	);
	
	% NOTE: we are using the label variable to get the menus that need updating
	
	g =  get(get_menu(g, strtok(title_caps(type), ' ')), 'children');
	
	set(g, 'check', 'off');
	
	set(get_menu(g, str), 'check', 'on');
	
	%--
	% update active detection controls in available palettes
	%--
	
	update_active_controls(par, type, data.browser.(type).active, data);
	
	%--
	% update display
	%--
	
	browser_display(par, 'update', data);
	
%------------------------------------------------
% FILTER ...
%------------------------------------------------

% NOTE: open filter control palette and return palette handle

case ( ...
	strcat({SIG_FILTER_NAME{:}, IMG_FILTER_NAME{:}},' ...') ...
)
	
	% NOTE: remove trailing space and periods from command string

	str = str(1:end - 4); 

	%---------------------------
	% CHECK FOR PALETTE
	%---------------------------
	
	%--
	% check for existing palette
	%--
	
	out = get_palette(par, str, data);

	% NOTE: position and return if palette exists
	
	if ~isempty(out)
		position_palette(out, par, 'center'); return;
	end
	
	%---------------------------
	% GET FILTER EXTENSION
	%---------------------------
	
	%--
	% get filter type
	%--
	
	type = '';
	
	if strcmp(get(gcbo, 'type'), 'uimenu')
		type = get(gcbo, 'tag');
	end
	
	if isempty(type)
		type = extension_type_from_name(str);
	end
	
	% NOTE: return if we were unable to determine type
	
	if isempty(type) || iscell(type)
		return;
	end
	
	%--
	% get filter from browser registry
	%--
	
	[ext, ignore, context] = get_browser_extension(type, par, str, data);
	
	%--------------------------------------------------
	% CREATE FILTER PALETTE
	%--------------------------------------------------
	
	control = empty(control_create);

	%---------------------
	% FILTER
	%---------------------
	
	control(end + 1) = control_create( ...
		'style', 'separator', ...
		'type', 'header', ...
		'string', 'Filter' ...
	);

	%--
	% opacity
	%--
	
	if ext.fade
		
		control(end + 1) = control_create( ...
			'name', 'opacity', ...
			'alias', 'Fade', ...
			'tooltip', 'Fade result of filtering', ...
			'style', 'slider', ...
			'min', 0, ...
			'max', 1, ...
			'value', 1, ...
			'callback', {@filter_dispatch, ext} ...
		);

	end
	
	%--
	% active filter
	%--
	
	active_state = double(strcmp(data.browser.(type).active, str));
	
	control(end + 1) = control_create( ...
		'name', 'active', ...
		'alias', 'On', ...
		'style', 'checkbox', ...
		'value', active_state, ...
		'callback', {@filter_dispatch, ext}, ...
		'tooltip', ['Make filter active'] ...
	);
	
	%--
	% active filter
	%--
	
	if xbat_developer
	
		control(end).space = -1.25;
		
		control(end + 1) = control_create( ...
			'name', 'refresh', ...
			'alias', 'REFRESH', ...
			'style', 'buttongroup', ...
			'align', 'right', ...
			'lines', 1.75, ...
			'width', 0.5, ...
			'callback', {@filter_dispatch, ext} ...
		);

	end

	%---------------------
	% PARAMETERS
	%---------------------
	
	%--
	% get filter controls
	%--
	
	ext_controls = empty(control_create);
	
	if ~isempty(ext.fun.parameter.control.create)
		
		try
			ext_controls = ext.fun.parameter.control.create(ext.parameter, context);
		catch
			extension_warning(ext, 'Parameter control creation failed.', lasterror);
		end
		
	end
	
	%--
	% append filter specific controls to controls array
	%--
	
	if ~isempty(ext_controls)
	
		control(end + 1) = control_create( ...
			'style', 'separator', ...
			'type', 'header', ...
			'string', 'Parameters' ...
		);

		%--
		% consider separator or tabs at start of filter controls
		%--

		switch (ext_controls(1).style)
			
			case ('separator') 
				
				if (~isempty(ext_controls(1).string))
					control(end).space = 1.25;
				end

			case ('tabs'), control(end).space = 0.11;
				
			case ('popup'), control(end).space = 0.75;

		end

		%--
		% set filter control callbacks
		%--
		
		% NOTE: this routes the filter-specific callbacks through our own
		
		for k = 1:length(ext_controls)
			ext_controls(k).callback = {@filter_dispatch, ext, ext_controls(k).callback};
		end
		
		%--
		% concatenate common controls and specific controls
		%--

		control = [control, ext_controls];
		
	end
	
	%--------------------------------------------------
	% FILTER PALETTE OPTIONS
	%--------------------------------------------------
	
	if ~isempty(ext.fun.parameter.control.options)
		
		opt = ext.fun.parameter.control.options(context);

		opt = struct_update(control_group, opt);

	else
		
		%--
		% get and set control group options
		%--

		opt = control_group;

		opt.left = 1;

		opt.right = 1;

		opt.width = 9; % helps to display filter name

		opt.top = 0; % header starts palette

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

		opt.handle_to_callback = 1;

	end
	
	opt.header_color = get_extension_color(ext);
	
	opt.ext = ext;
	
	%--------------------------------------------------
	% CREATE FILTER PALETTE
	%--------------------------------------------------
	
	%--
	% create control group
	%--
	
	pal = control_group(par, '', str, control, opt);
	
	%--
	% set palette tag, key press, and close request function
	%--
	
	% NOTE: control values are updated in parent as part of close request function
	
	% NOTE: the type of filter in palette tag has not been tested
	
	set(pal, ...
		'visible','off', ...
		'tag',['XBAT_PALETTE::', upper(type), '::', 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
	%--------------------------------------------------
	
	
	
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%% WE ARE HERE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



	% TODO: the logic of this code needs to be reviewed
	
	%--
	% update palette controls to reflect current state of palette
	%--
		
	% NOTE: we remove the value of active since things could have changed
	
	values = ext.control;
	
	%--------------------------------------------------
	% PERFORM ONLOAD CALLBACK(S)
	%--------------------------------------------------
	
	% TODO: factor this to use for all extensions and preset loaders
	
	% TODO: order 'onload' callbacks by making value a position
	
	%--
	% check for onload callbacks
	%--
	
	if ~isempty(ext_controls)
		
		onload = [ext_controls.onload];

		if any(onload)

			for k = 1:length(onload)
				
				if onload(k)
					control_callback([], pal, ext_controls(k).name);
				end
				
			end

		else

			% NOTE: this is older code kept for backwards compatibility
			
			flag = 0;

			for k = 1:length(ext_controls)

				try	
					flag = control_callback([], pal, ext_controls(k).name);
				end

				if (flag)
					break;
				end

			end

		end
		
	end
	
	%--
	% position palette relative to parent
	%--
	
	position_browser_palette(par, pal, data);
	
	%--
	% output palette handle
	%--
	
	out = pal;
	
end


%-------------------------------------------------------------------------
% FILTER_DISPATCH
%-------------------------------------------------------------------------

function filter_dispatch(obj, eventdata, filter, control_callback)

% filter_dispatch - callback dispatch for filter extensions
% ---------------------------------------------------------
%
% filter_dispatch(obj, eventdata, filter, control_callback)
%
% Input:
% ------
%  obj, eventdata - MATLAB callback inputs
%  filter - filter extension
%  control_callback - control specific callback, typically empty

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 2173 $
% $Date: 2005-11-22 00:26:27 +0100 (Tue, 22 Nov 2005) $
%--------------------------------

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

%--
% get callback context from handle
%--

callback = get_callback_context(obj, 'pack'); 

%--
% get fresh extension
%--

sound = get_browser(callback.par.handle, 'sound');

context.ext = filter; context.sound = sound;

%--
% set default result
%--

result = [];

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

switch callback.control.name
		
	%----------------------
	% REFRESH
	%----------------------
	
	case 'refresh'
		
		refresh_extension(callback, context);
		
	%----------------------
	% FILTER
	%----------------------
	
	case 'opacity'
		
		slider_sync(obj, callback.control.handles);

		control_flash(callback.control, callback.pal);
	
	case 'active'

		%--
		% update active filter state
		%--
		
		% NOTE: we compute command string from control value
		
		if get(obj, 'value')
			str = callback.pal.name; 
		else
			str = 'No Filter'; 
		end
				
		browser_filter_menu(callback.par.handle, str); 
		
		% NOTE: the filter gateway updates the parent display so we return
		
		return;
		
	%----------------------
	% EXTENSION
	%----------------------
		
	otherwise
		
		%--
		% sync and flash to indicate callback is being handled
		%--
		
		% NOTE: consider hover fade behavior here
		
		if has_slider(callback.control.handles)
			slider_sync(obj, callback.control.handles);
		end
		
		control_flash(callback.control, callback.pal);

		%--
		% yield to extension callback function
		%--
		
		% TODO: handle control specific callback
		
		fun = filter.fun.parameter.control.callback;
		
		if ~isempty(fun)
			result = fun(callback, context);
		end
	
end

%--
% consider callback result
%--

% NOTE: return if result indicate no need for update

if ~isempty(result) && isfield(result, 'update') && ~result.update
	return;
end

%--
% update display considering results
%--

update_parent_display(callback.pal.handle);


%-------------------------------------------------------------------------
% UPDATE_PARENT_DISPLAY
%-------------------------------------------------------------------------

function update_parent_display(pal)

% update_parent_display - update parent display on filter state change
% --------------------------------------------------------------------
%
% par = update_parent_display(pal)
%
% Input:
% ------
%  pal - filter extension palette
%
% Output:
% -------
%  par - updated parent

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 1474 $
% $Date: 2005-08-05 20:29:15 -0400 (Fri, 05 Aug 2005) $
%--------------------------------

% TODO: update this to include active detection update

% NOTE: previously this was achieved with the 'Scrollbar' callback

%--
% set default palette handle
%--

% NOTE: since this is usually called after updating a palette control it makes sense

if (nargin < 1)
	pal = gcf;
end

%--
% check for parent
%--

par = get_xbat_figs('child', pal);

if isempty(par)
	return;
end

%--
% get parent userdata
%--

data = get(par, 'userdata');

%--
% get relevant filter state information
%--

% NOTE: get palette filter from name

filter_name = get(pal, 'name'); 

% NOTE: get active filters from parent

signal_filter = data.browser.signal_filter.active;

image_filter = data.browser.image_filter.active;

%--
% update parent if needed
%--

if strcmp(signal_filter, filter_name) || strcmp(image_filter, filter_name)
		
	% NOTE: this does not clear the browser selection
	
	browser_display(par, 'update', data);

end

