function [node,edge,face,hdata] = checkgeometry(node,edge,face,hdata)

%*****************************************************************************80
%
% CHECKGEOMETRY: Check a geometry input for MESH2D.
%  
%  node  : Nx2 array of XY geometry nodes
%  edge  : Mx2 array of connections between nodes in NODE. (Optional)
%  face  : cell array of edges in each face
%  hdata : Structure array defining size function data. 
%
% The following checks are performed:
%
%  1. Unique edges in EDGE.
%  2. Only nodes referenced in EDGE are kept.
%  3. Unique nodes in NODE.
%  4. No "hanging" nodes and no "T-junctions".
%
% Checks for self-intersecting geometry are NOT done because this can be 
% expensive for big inputs.
%
% HDATA and FACE may be re-indexed to maintain consistency.
%
%  Author:
%
%    Darren Engwirda
%

if (nargin<3)
   face = [];
   if (nargin<2)
      edge = [];
      if (nargin<1)
         error('Insufficient inputs');
      end
   end
elseif (nargin>4)
   error('Wrong number of inputs');
end
if (nargout>4)
   error('Wrong number of outputs');
end
nNode = size(node,1);
if isempty(edge)                                                           % Build edge if not passed
   edge = [(1:nNode-1)',(2:nNode)'; nNode,1];
end
if isempty(face)                                                           % Build face if not passed
   face{1} = 1:size(edge,1);
end
if numel(node)~=2*nNode                                                    % Check inputs
   error('NODE must be an Nx2 array');
end
if numel(edge)~=2*size(edge,1)
   error('EDGE must be an Mx2 array');
end
if (max(edge(:))>nNode)||(min(edge(:))<=0)                                 % Check geometry indexing
   error('Invalid EDGE');
end
for k = 1:length(face)
   if isempty(face{k}) || any( (face{k}<1) | (face{k}>size(edge,1)) )
      error(['Invalid FACE{',num2str(k),'}']);
   end
end
if isfield(hdata,'edgeh') && ~isempty(hdata.edgeh)                         % Check if we've got size data attached to edges
   edgeh = true;
else
   edgeh = false;
end

i = unique(edge(:));                                                       % Remove un-used nodes and re-index
del = nNode-i(end);
if del>0
   node = node(i,:);
   j = zeros(size(node,1),1);
   j(i) = 1;
   j = cumsum(j);
   edge = j(edge);
   i = edge(:,1)~=edge(:,2);
   j = zeros(size(edge,1),1);
   j(i) = 1;
   j = cumsum(j);
   edge = edge(i,:);
   for k = 1:length(face)
      face{k} = unique(j(face{k}));
   end
   disp(['WARNING: ',num2str(del),' un-used node(s) removed']);
   nNode = size(node,1);
end

[i,i,j] = unique(node,'rows');                                             % Remove duplicate nodes and re-index
del = nNode-length(i);
if del>0
   node = node(i,:);
   edge = j(edge);
   i = edge(:,1)~=edge(:,2);
   j = zeros(size(edge,1),1);
   j(i) = 1;
   j = cumsum(j);
   edge = edge(i,:);
   for k = 1:length(face)
      face{k} = unique(j(face{k}));
   end
   disp(['WARNING: ',num2str(del),' duplicate node(s) removed']);
   nNode = size(node,1);
end

nEdge = size(edge,1);
[i,i,j] = unique(sort(edge,2),'rows');                                     % Remove duplicate edges
if edgeh
   hdata.edgeh(:,1) = j(hdata.edgeh(:,1));
   j = zeros(size(edge,1),1);
   j(i) = 1;
   j = cumsum(j);
   edge = edge(i,:);
   for k = 1:length(face)
      face{k} = unique(j(face{k}));
   end
end
del = nEdge-size(edge,1);
if del>0
   disp(['WARNING: ',num2str(del),' duplicate edge(s) removed']);
   nEdge = size(edge,1);
end

nEdge = size(edge,1);
S = sparse(edge(:), [1:nEdge,1:nEdge], 1, nNode, nEdge);                   % Sparse node-to-edge connectivity matrix
i = find(sum(S,2)<2);
if ~isempty(i)                                                             % Check for closed geometry loops
   error(['Open geometry contours detected at node(s): ',num2str(i')]);
end

% i = find(sum(S,2)>2);                                                      % Check for geometry T-junctions
% if ~isempty(i)
%    error(['Multiple geometry branches detected at node(s): ',num2str(i')]);
% end

end      % checkgeometry()
