//////////////////////////////////////////////////////////////////////////////
// Clirr: compares two versions of a java library for binary compatibility
// Copyright (C) 2003 - 2004  Lars Khne
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//////////////////////////////////////////////////////////////////////////////

package net.sf.clirr.checks;

import java.util.ArrayList;
import java.util.List;

import net.sf.clirr.event.Severity;
import net.sf.clirr.framework.AbstractDiffReporter;
import net.sf.clirr.framework.ApiDiffDispatcher;
import net.sf.clirr.framework.ClassChangeCheck;
import org.apache.bcel.classfile.JavaClass;

/**
 * Detects changes in the set of superclasses.
 *
 * @author lkuehne
 */
public final class ClassHierarchyCheck
        extends AbstractDiffReporter
        implements ClassChangeCheck
{
    /**
     * Create a new instance of this check.
     * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners.
     */
    public ClassHierarchyCheck(ApiDiffDispatcher dispatcher)
    {
        super(dispatcher);
    }

    private List getSetDifference(JavaClass[] orig, JavaClass[] subtracted)
    {
        List list1 = getClassNames(orig);
        List list2 = getClassNames(subtracted);

        List retval = new ArrayList(list1);
        retval.removeAll(list2);

        return retval;
    }

    private List getClassNames(JavaClass[] orig)
    {
        List list = new ArrayList(orig.length);
        for (int i = 0; i < orig.length; i++)
        {
            JavaClass javaClass = orig[i];
            list.add(javaClass.getClassName());
        }
        return list;
    }

    /** {@inheritDoc} */
    public boolean check(JavaClass compatBaseline, JavaClass currentVersion)
    {
        JavaClass[] compatSuper = compatBaseline.getSuperClasses();
        JavaClass[] currentSuper = currentVersion.getSuperClasses();

        boolean isThrowable = false;
        for (int i = 0; i < compatSuper.length; i++)
        {
            JavaClass javaClass = compatSuper[i];
            if ("java.lang.Throwable".equals(javaClass.getClassName()))
            {
                isThrowable = true;
            }
        }

        List added = getSetDifference(currentSuper, compatSuper);
        List removed = getSetDifference(compatSuper, currentSuper);

        final String className = compatBaseline.getClassName();
        for (int i = 0; i < added.size(); i++)
        {
            String s = (String) added.get(i);
            log("Added " + s + " to the list of superclasses of " + className,
                    isThrowable ? Severity.WARNING : Severity.INFO, className, null, null);
        }

        for (int i = 0; i < removed.size(); i++)
        {
            String s = (String) removed.get(i);
            log("Removed " + s + " from the list of superclasses of " + className,
                    Severity.ERROR, className, null, null);
        }

        return true;
    }
}

@@ -1273,16 +1273,113 @@
 eCheck;%0A
+import net.sf.clirr.framework.CoIterator;%0Aimport net.sf.clirr.framework.JavaClassNameComparator;%0A
 import o
@@ -2572,24 +2572,25 @@
  compatSuper
+s
  = compatBas
@@ -2646,16 +2646,17 @@
 entSuper
+s
  = curre
@@ -2761,16 +2761,17 @@
 patSuper
+s
 .length;
@@ -2831,16 +2831,17 @@
 patSuper
+s
 %5Bi%5D;%0A   
@@ -2996,74 +2996,73 @@
     
-List added = getSetDifference(currentSuper, compatSuper
+final String className = compatBaseline.getClassName(
 );%0A
+%0A
         
 List
@@ -3061,40 +3061,90 @@
     
-List removed = getSetDifference(
+CoIterator iter = new CoIterator(%0A            JavaClassNameComparator.COMPARATOR, 
 comp
@@ -3150,16 +3150,17 @@
 patSuper
+s
 , curren
@@ -3165,16 +3165,17 @@
 entSuper
+s
 );%0A%0A    
@@ -3182,72 +3182,207 @@
     
-final String className = compatBaseline.getClassName
+while (iter.hasNext())%0A        %7B%0A            iter.next();%0A            JavaClass baselineSuper = (JavaClass) iter.getLeft();%0A            JavaClass currentSuper = (JavaClass) iter.getRight
 ();%0A
+%0A
         
 for 
@@ -3381,131 +3381,131 @@
     
-for (int i = 0; i %3C added.size(); i++)%0A        %7B%0A            String s = (String) added.get(i);%0A            log(%22Added %22 + s
+    if (baselineSuper == null)%0A            %7B%0A                log(%22Added %22 + currentSuper.getClassName()%0A                   
  + %22
@@ -3563,32 +3563,36 @@
                 
+ 
+   
 isThrowable ? Se
@@ -3647,34 +3647,37 @@
  null);%0A        
+    
 %7D
-%0A
 %0A        for (in
@@ -3673,137 +3673,139 @@
     
-for (int i = 0; i %3C removed.size(); i++)%0A        %7B%0A            String s = (String) removed.get(i);%0A            log(%22Removed %22 + s
+    else if (currentSuper == null)%0A            %7B%0A                log(%22Removed %22 +  baselineSuper.getClassName()%0A                   
  + %22
@@ -3873,16 +3873,20 @@
         
+    
 Severity
@@ -3909,32 +3909,46 @@
 e, null, null);%0A
+            %7D%0A
         %7D%0A%0A     

Use CoIterator.