/* 
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.  
 */

package org.apache.wiki;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.wiki.util.ClassUtil;
import org.apache.wiki.util.comparators.JavaNaturalComparator;

/**
 * Wrapper class for managing and using the PageNameComparator.
 * <p>
 * <b>Note</b> - this class is deliberately not null safe. Never call any of the
 * methods with a null argument!
 */
public class PageSorter implements Comparator< Object > {
    
    private static Logger log = Logger.getLogger( PageSorter.class );

    // The name of the property that specifies the desired page name comparator
    protected static final String PROP_PAGE_NAME_COMPARATOR = "jspwiki.pageNameComparator.class";

    private Comparator<String> m_comparator;

    /**
     * Default constructor uses Java "natural" ordering.
     */
    public PageSorter() {
        m_comparator = JavaNaturalComparator.DEFAULT_JAVA_COMPARATOR;
    }

    /**
     * Construct with a particular comparator.
     * 
     * @param comparator the Comparator to use
     */
    public PageSorter( Comparator<String> comparator ) {
        m_comparator = comparator;
    }

    /**
     * Compare two page names (Object version). Arguments must be either String
     * or WikiPage.
     * 
     * @throws IllegalArgumentException if incorrect argument types.
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    @Override
    public int compare( Object o1, Object o2 ) {
        if( o1 instanceof String ) {
            if( o2 instanceof String ) {
                return m_comparator.compare( (String) o1, (String) o2 );
            }
            if( o2 instanceof WikiPage ) {
                return m_comparator.compare( (String) o1, ((WikiPage) o2).getName() );
            }
        } else if( o1 instanceof WikiPage ) {
            if( o2 instanceof WikiPage ) {
                return m_comparator.compare( ((WikiPage) o1).getName(), ((WikiPage) o2).getName() );
            }
            if( o2 instanceof String ) {
                return m_comparator.compare( ((WikiPage) o1).getName(), (String) o2 );
            }
        }

        throw new IllegalArgumentException( "Can only compare String or WikiPage" );
    }

    /**
     * Compare two page names (String version).
     * 
     * @param pageName1 the first page name
     * @param pageName2 the second page name
     * @return see java.util.Comparator
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare( String pageName1, String pageName2 ) {
        return m_comparator.compare( pageName1, pageName2 );
    }

    /**
     * Compare two pages (WikiPage version). Compares them by name first. If the
     * same name, compares their versions.
     * 
     * @param page1 the first page
     * @param page2 the second page
     * @return see java.util.Comparator
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare( WikiPage page1, WikiPage page2 ) {
        if( page1 == page2 ) {
            return 0; // the same object
        }

        int res = m_comparator.compare( page1.getName(), page2.getName() );
        if( res == 0 ) {
            res = page1.getVersion() - page2.getVersion();
        }
        return res;
    }

    @Override
    public boolean equals( Object o ) {
        if( !(o instanceof PageSorter) ) {
            return false; // Definitely not equal
        }
        PageSorter that = (PageSorter) o;
        if( this == that || m_comparator == that.m_comparator ) {
            return true; // Essentially the same object
        }
        return m_comparator.equals( that.m_comparator );
    }

    /**
     * Called by WikiEngine to initialise this instance. Tries to use class
     * given by the PROP_PAGE_NAME_COMPARATOR property as the page name
     * comparator. Uses a default comparator if this property is not set or
     * there is any problem loading the specified class.
     * 
     * @param props this WikiEngine's properties.
     */
    public void initialize( Properties props ) {
        // Default is Java natural order
        m_comparator = JavaNaturalComparator.DEFAULT_JAVA_COMPARATOR;
        String className = props.getProperty( PROP_PAGE_NAME_COMPARATOR );
        if( className != null && className.length() > 0 ) {
            try {
                m_comparator = ClassUtil.getMappedObject( "org.apache.wiki.util.comparators." + className );
            } catch( Exception e ) {
                log.error( "Falling back to default \"natural\" comparator", e );
            }
        }
    }

    /**
     * Sorts the specified list into ascending order based on the
     * PageNameComparator. The actual sort is done using
     * <code>Collections.sort()</code>.
     * 
     * @param nameList the page names to be sorted
     */
    public void sort( List< String > nameList ) {
        Collections.sort( nameList, m_comparator );
    }

    /**
     * Sorts the specified array into ascending order based on the
     * PageNameComparator. The actual sort is done using
     * <code>Arrays.sort()</code>.
     * 
     * @param nameArray the page names to be sorted
     */
    public void sort( String[] nameArray ) {
        Arrays.sort( nameArray, m_comparator );
    }

    /**
     * Sorts the specified list into ascending order based on the
     * PageNameComparator. The actual sort is done using
     * <code>Collections.sort()</code>.
     * 
     * @param pageList the pages to be sorted
     */
    public void sortPages( List< Object > pageList ) {
        Collections.< Object >sort( pageList, this );
    }

    /**
     * Sorts the specified array into ascending order based on the
     * PageNameComparator. The actual sort is done using
     * <code>Arrays.sort()</code>.
     * 
     * @param pageArray the pages to be sorted
     */
    public void sortPages( Object[] pageArray ) {
        Arrays.sort( pageArray, this );
    }

}

@@ -4976,32 +4976,69 @@
 erties.%0A     */%0A
+    @SuppressWarnings( %22unchecked%22 )%0A
     public void 
@@ -5369,33 +5369,48 @@
 r = 
-ClassUtil.getMappedObject
+(Comparator%3CString%3E) ClassUtil.findClass
 ( %22o
@@ -5444,12 +5444,10 @@
 tors
-.%22 +
+%22,
  cla
@@ -5453,16 +5453,30 @@
 assName 
+).newInstance(
 );%0A     

revert change on PageSorter, breaks build :-/