//-----------------------------------------------------------------------------
// Copyright © 2003 - Philip Howard - All rights reserved
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/avl
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// G. M. Adelson-Velskii and E. M. Landis are the inventors of the algorithm
// bearing their initials, AVL.  Their algorithm for height-balanced binary
// search trees is the basis of the code in this package.  Some modification
// is made to the balancing operations, and features are added for practical
// purposes.
//-----------------------------------------------------------------------------

#include "avl_lib.h"

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	avl_diff_key_count
//
// purpose	Scan two binary trees for node differences, counting the
//		number of nodes different in each based on just the key.
//
// arguments	1 (AVL *) pointer to binary tree one
//		2 (AVL *) pointer to binary tree two
//		3 (int *) store count of nodes in tree one not in tree two here
//		4 (int *) store count of nodes in tree two not in tree one here
//
// returns	(int) == 0 : trees have the same keys
//		(int)  > 0 : number of nodes not match in either tree
//		(int)  < 0 : error
//
// note		In order for tree-to-tree comparison to be made, both trees
//		MUST be using exactly the same comparison function.
//
// note		This function does not depend on the shape of the tree or any
//		aspect of the order the nodes were inserted.
//-----------------------------------------------------------------------------
int
avl_diff_key_count (
    AVL *	arg_tree_one
    ,
    AVL *	arg_tree_two
    ,
    int *	arg_count_one
    ,
    int *	arg_count_two
    )
__PROTO_END__
{
    int ( *		cmp_f		)( avl_link *, avl_link *, struct avl_root * );
    avl_link *		node_one	;
    avl_link *		node_two	;
    avl_link *		select_one	;
    avl_link *		select_two	;
    int			count_one	;
    int			count_two	;


#if AVL_CHECK_ARGS
    //--------------------------------------
    // Make sure we were given binary trees.
    //--------------------------------------
    if ( ! arg_tree_one ) return AVL_ERR_BAD_ROOT;
    if ( ! arg_tree_two ) return AVL_ERR_BAD_ROOT;
#endif

    //------------------------------------------------------
    // Make sure the binary trees are compared the same way.
    //------------------------------------------------------
    if ( ! ( cmp_f = arg_tree_one->compare_f ) ) return -1;
    if ( arg_tree_two->compare_f != cmp_f ) return -1;

    //--------------------------------------------
    // For both trees, save the currently selected
    // node and start them at the beginning.
    //--------------------------------------------
    select_one = arg_tree_one->select;
    select_two = arg_tree_two->select;
    node_one = avl_first( arg_tree_one );
    node_two = avl_first( arg_tree_two );
    count_one = 0;
    count_two = 0;

    //-------------------------------------------------------
    // Scan both trees in parallel counting mismatched nodes.
    //-------------------------------------------------------
    for (;;) {
	if ( node_one ) {
	    if ( node_two ) {
		int delta;
		delta = ( * cmp_f )( avl_node_to_link( arg_tree_one, node_one ),
				     avl_node_to_link( arg_tree_two, node_two ),
				     NULL );
		if ( delta <= 0 ) {
		    node_one = avl_forward( arg_tree_one, node_one );
		    if ( delta != 0 ) ++ count_one;
		}
		if ( delta >= 0 ) {
		    node_two = avl_forward( arg_tree_two, node_two );
		    if ( delta != 0 ) ++ count_two;
		}
	    } else {
		node_one = avl_forward( arg_tree_one, node_one );
		++ node_one;
	    }
	} else if ( node_two ) {
	    node_two = avl_forward( arg_tree_two, node_two );
	    ++ count_two;
	} else break;
    }

    //----------------------------
    // Restore the selected nodes.
    //----------------------------
    arg_tree_one->select = select_one;
    arg_tree_two->select = select_two;

    //----------------------------------------------------
    // Store individual counts and return the total count.
    //----------------------------------------------------
    if ( arg_count_one ) * arg_count_one = count_one;
    if ( arg_count_two ) * arg_count_two = count_two;
    return count_one + count_two;
}

