function out = file_process(out, in, fun, opt)

% file_process - process file by lines
% ------------------------------------
%
% file_process(out, in, fun, opt)
%
% opt = file_process
%
% Input:
% ------
%  out - output file or file identifier
%  in - input file or file identifier
%  fun - fun to process each line 
%  opt - options
%
% Output:
% -------
%  info - output file info
%  opt - options

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 1600 $
% $Date: 2005-08-18 17:41:06 -0400 (Thu, 18 Aug 2005) $
%--------------------------------

% NOTE: 'strip_flash' this function to reveal some existing problems

% TODO: update callback handling code to use new callback framework

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

%--
% set and possibly return default options
%--

if (nargin < 4) || isempty(opt)
	
	%--
	% create options struct
	%--
	
	opt.pre = ''; % input comment prefix, indicates skip comments
	
	opt.skip = 0; % skip empty input line indicator

	%--
	% possibly output options and return
	%--
	
	if ~nargin
		out = opt; return;
	end
	
end

%--
% set process function
%--

if (nargin < 3) || isempty(fun)
	fun = []; args = [];
else
	[fun, args] = parse_fun(fun);
end

%---------------------------------
% PROCESS LINES
%---------------------------------

% NOTE: reading and writing from line buffers is revealed through other functions

%--
% get output file identifier or initialize line buffer
%--

% NOTE: empty out stores output in line buffer

buff_out = isempty(out); 

if buff_out
	lines = cell(0);
else
	out = get_fid(out, 'wt');
end

%--
% get input file identifier or rename input to lines buffer
%--

% TODO: make this an 'if' and test 'iscellstr'

switch (class(in))
	
	%--
	% string cell array input
	%--
	
	% NOTE: string cell array input reads lines from line buffer
	
	case ('cell'), buff_in = 1; lines = in;
	
	%--
	% string input or file input
	%--
	
	case ('char')
		
		if exist(in,'file')
		
			buff_in = 0; in = get_fid(in, 'rt'); empty_count = 0;
		
		else	
			
			% NOTE: string buffer input is converted to cell array of strings
			
			buff_in = 1; lines = strread(in, '%s', 'delimiter', '\n', 'whitespace', '')';
		
		end
		
end

if buff_in
	ix = 0; N = length(lines);
end

%--
% iterate over input file lines
%--

while (1)
	
	%--
	% get line from input file or line buffer
	%--
	
	if (buff_in)

		ix = ix + 1;

		if (ix > N)
			break;
		end

		line = lines{ix};
		
	else
		
		% NOTE: this strips line termination

		line = fgetl(in.fid);

		if ~ischar(line)
			break;
		end

	end
	
	%--
	% skip or collapse empty input lines
	%--
		
	% NOTE: collapse multiple empty lines is not available
	
	switch (opt.skip)
		
		%--
		% skip empty input lines
		%--
		
		case (1)
			
			if all(isspace(line))
				continue;
			end
	
		%--
		% collapse multiple empty input lines
		%--
		
		case (-1)
			
			if ~buff_in
				
				% NOTE: for file input simply skip empty lines
				
				if all(isspace(line))
					continue;
				end
				
			else
				
				if all(isspace(line)) && (ix > 1) && all(isspace(lines{ix - 1}))
					continue;
				end
				
			end
			
	end
	
	%--
	% skip comment lines
	%--
	
	% NOTE: this does not strip end of line comments
	
	if ~isempty(opt.pre)
		
		trim_line = strtrim(line);

		if ~isempty(trim_line) && strncmp(opt.pre, trim_line, length(opt.pre)) 
			continue;
		end
		
	end
	
	%--
	% append input line to output file or line buffer
 	%--
	
	% TODO: develop a better escape strategy 
	
	if isempty(fun)
		
		if buff_out
			lines{end + 1} = line;
		else
			line = strrep(line, '\', '\\');
			fprintf(out.fid, [line, '\n']);
		end

		continue;
	
	end
	
	%--
	% process line
	%--
			
	res = apply_fun(line, fun, args);
	
	%--
	% append result
	%--
			
	if buff_out
		
		%--
		% append to line buffer
		%--
		
		if ischar(res)
			lines{end + 1} = res;
		else
			for k = 1:length(res)
				lines{end + 1} = res{k};
			end
		end
		
	else
		
		%--
		% append to output file
		%--
		
		% NOTE: line callbacks return character arrays, or string cell arrays
		
		if ischar(res)
			fprintf(out.fid, [res, '\n']);
		else
			for k = 1:length(res)
				fprintf(out.fid, [res{k}, '\n']);
			end
		end
		
	end
	
end

%--
% rename line buffer or close output file if needed
%--

if buff_out
	
	out = lines';
	
else
	
	if out.file
		fclose(out.fid);
	end

	if nargout
		out = dir(out.name);
	end
	
end

%--
% close input file if needed
%--

if ~buff_in
	
	if in.file
		fclose(in.fid); 
	end

end


