function s = checkval(v,t,prefix,dims,bounds,options)

% By Antoine Duchateau. All Rights Reserved.
% Written: 12/05/99

%MAN_PAGE_BEGIN
%
%   @purpose	Check if some value meets requirements
%
%   @synopsys	s = checkval(v,type,prefix,dims,bounds,options)
%   @description  check if <CODE>v</CODE> is of type <CODE>type</CODE>,
%	of dimension <CODE>dims</CODE> and meets the additional criterions
%	specified inside <CODE>options</CODE>. Prefix is added in front of
%	the error message. <CODE>bounds</CODE> is used to specify a limit for the
%	elements of the matrix (if <CODE>v</CODE> is a cell array, bounds is
%	used to check the type of the objects)

%	
%	<CODE>t</CODE> can be:
%	<DL>
%	<DT>'numeric'<DD>A numeric matrix
%	<DT>'real'<DD>A real matrix
%	<DT>'int'<DD>An integer matrix
%	<DT>'zero'<DD>A null matrix
%	<DT>'positive'<DD>A real positive matrix
%	<DT>'negative'<DD>A real negative matrix
%	<DT>'intpos'<DD>A integer positive matrix
%	<DT>'intneg'<DD>A integer negative matrix
%	<DT>'char'<DD>An array of strings
%	<DT>'struct'<DD>A structure
%	<DT>'cell'<DD>A cell array
%	<DT>any name of class<DD>The class to which should belong <CODE>v</CODE>
%	<DT>'any'<DD>Any data type
%	</DL>
%
%	<CODE>dims</CODE> is a cell array (one element for each dimension)
%	whose the elements can be:
%	<DL>
%	<DT>[-1]<DD>For any size
%	<DT>[x]<DD>For a specified size
%	<DT>[min:max]<DD>For a range of size
%	<DT>[x y z ...]<DD>For a descrete number of sizes
%	<DT>[0]<DD>At the end indicates a constraint on the number of dimensions
%	</DL>
%
%	<CODE>options</CODE> is a cell array (one element fo each dimension)
%	whose the elements can be:
%	<DL>
%	<DT>'even'<DD>For an even size of the matrix
%	<DT>'odd'<DD>For an odd size of the matrix
%	<DT>'ascending'<DD>To check if elements are in ascending order
%	<DT>'descending'<DD>To check if elements are in descending order
%	<DT>'any'<DD>For no additional check
%	</DL>
%
%   @see checkargs
%
%MAN_PAGE_END

s = '';

flag =4;

switch t,
case 'numeric',
	if ~isnumeric(v),
		s =[prefix ' should be numeric'];
		return;
	end

case 'real',
	if ~isnumeric(v)|~isreal(v),
		s =[prefix ' should be real'];
		return;
	end
		
case 'int',
	if ~isnumeric(v)|~isreal(v)|any(floor(v(:)) ~= v(:)),
		s =[prefix ' should be integer'];
		return;
	end
		
case 'zero',
	if ~isnumeric(v)|~isreal(v)|any(v(:) ~= 0),
		s =[prefix ' should be null'];
		return;
	end
		
case 'positive',
	if ~isnumeric(v)|~isreal(v)|any(v(:) < 0),
		s =[prefix ' should be positive'];
		return;
	end
		
case 'negative',
	if ~isnumeric(v)|~isreal(v)|any(v(:) > 0),
		s =[prefix ' should be negative'];
		return;
	end
		
case 'intpos',
	if ~isnumeric(v)|~isreal(v)|any(v(:) < 0)|any(floor(v(:)) ~= v(:)),
		s =[prefix ' should be integer positive'];
		return;
	end
		
case 'intneg',
	if ~isnumeric(v)|~isreal(v)|any(v(:) > 0)|any(floor(v(:)) ~= v(:)),
		s =[prefix ' should be integer negative'];
		return;
	end
		
case 'char',
	if ~ischar(v),
		s =[prefix ' should be a char array'];
		return;
	end
	flag = 2;
		
case 'struct',
	if ~isstruct(v),
		s =[prefix ' should be a structure'];
		return;
	end
	flag = 1;
		
case 'cell',
	if ~iscell(v),
		s =[prefix ' should be a cell array'];
		return;
	end
	flag = 2;
		
otherwise,
	if ~strcmp(t,'any'),
		if ~isa(v,t),
			s =[prefix ' should be a object of class ' t];
			return;
		end
	end
	
	flag = 1;
end

if flag < 2, return; end
if nargin < 4, return; end

if dims{end} == 0,
	if ndims(v) ~= length(dims)-1,
		s =[prefix ' must have' num2str(length(dims)-1) dimensions];
		return;
	end
	dims(end) = [];
end

for i=1:length(dims),
	spec = dims{i};
	
	if spec(1) ~= -1,
		if ~any(size(v,i) == spec),
			s =[prefix ' has not the right size along the dim. ' num2str(i)];
			return;
		end
	end
end

if flag < 3, return; end
if nargin < 5, return; end

if ~iscell(v),
	if any(v<bounds(1))|any(v>bounds(2)),
		s =[prefix ' values must be between ' mat2str(bounds)];
	end
else
	for i = 1:length(v),
		s = checkval(v{i},bounds,[' must have elements of type ' bounds]);
		if ~isempty(s), return; end
	end
end

if flag < 4, return; end
if nargin < 6, return; end

for i=1:length(options),
	spec = options{i};
	
	if ~strcmp(spec,'any'),
		switch spec,
		
		case 'even',
		if floor(size(v,i)/2) ~= size(v,i)/2,
			s =[prefix ' must have an even size along the dim. ' num2str(i)];
			return;
		end

		case 'odd',
		if floor(size(v,i)/2) == size(v,i)/2,
			s =[prefix ' must have an odd size along the dim. ' num2str(i)];
			return;
		end

		case 'ascending',
		if sort(v,i) ~= v,
			s =[prefix ' values must be sorted ascending along dim. ' num2str(i)];
			return;
		end

		case 'ascending',
		if flipdim(sort(v,i),i) ~= v,
			s =[prefix ' values must be sorted descending along dim. ' num2str(i)];
			return;
		end
		end
	end
end
