// 
// The Waveset SPML General License 
// 
// Version 0.1, April 2003
// Copyright (C) 2003 Waveset Technologies, Inc..
// 6034 West Courtyard Drive, Suite 210, Austin, Texas 78730
// All rights reserved.
// 
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// 
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions, and the disclaimers in Sections 6
//    and 7 below.
// 
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the disclaimers in Sections 6
//    and 7 below in the documentation and/or other materials provided
//    with the distribution.
// 
// 3. The end-user documentation included with the redistribution, if
//    any, must include the following acknowledgment:
// 
//    "This product includes software developed by 
//     Waveset Technologies, Inc. (www.waveset.com)."
// 
//    Alternately, this acknowledgment may appear in the software itself, if
//    and wherever such third-party acknowledgments normally appear.
//  
// 4. The names "Waveset" and "Waveset Technologies, Inc." must not be
//    used to endorse or promote products derived from this software
//    without the prior written permission of Waveset. For written
//    permission, please contact www.waveset.com.
//  
// 5. Products derived from this software may not be called "Waveset",
//    nor may "Waveset" appear in their name, without the prior written
//    permission of Waveset.
//  
// 6. NO WARRANTY 
// 
//    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED
//    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//    DISCLAIMED.
// 
// 7.  LIMITATION OF LIABILITY
// 
//    IN NO EVENT SHALL THE WAVESET OR ITS LICENSORS BE LIABLE FOR ANY
//    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
//    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
//    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
//    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// End of Terms and Conditions
// ====================================================================
//
// Component Name: org.openspml.message.SearchResponse
//
// Author(s): Jeff Larson
//
// Description:
//
// Memory representation for a <searchResponse> element.
//
//

package org.openspml.message;

import java.util.*;
import org.openspml.util.*;

/**
 * A class used to represent a <code>searchResponse</code> element.
 */
public class SearchResponse extends SpmlResponse {

    //////////////////////////////////////////////////////////////////////
    //
    // Fields
    //
    //////////////////////////////////////////////////////////////////////

    static final String ELEMENT = "searchResponse";

    /**
     * A list of SearchResult objects.
     */
    List _results;

    //////////////////////////////////////////////////////////////////////
    //
    // Constructors
    //
    //////////////////////////////////////////////////////////////////////

    public SearchResponse() {
    }

    SearchResponse(XmlElement e) {
	parseXml(e);
    }

    public void setResults(List l) {
        _results = l;
    }

    public void addResult(SearchResult sr) {
        if (_results == null)
            _results = new ArrayList();
        _results.add(sr);
    }

    //////////////////////////////////////////////////////////////////////
    //
    // Accessors
    //
    //////////////////////////////////////////////////////////////////////

    public List getResults() {
        return _results;
    }

    //////////////////////////////////////////////////////////////////////
    //
    // Sorting
    //
    //////////////////////////////////////////////////////////////////////

    /**
     * Convenience method to sort the list of SearchResult objects.
     * If the attribute name is "identifier", the sort will be based on 
     * the _identifer field of the SearchResult, otherwise by one
     * of the Attributes returned in the result.
     *
     * This can be used for display purposes but is also handy
     * for unit tests since the XML will be emitted in a predictable order
     * for comparison against expected results.
     */
    public void sort(String attname) {

        if (_results != null) {
            Collections.sort(_results, new SearchResultComparator(attname));

            // also sort the attributes in each result, not necessary
            // for display, but necessary for unit tests
            Iterator it = _results.iterator();
            while (it.hasNext())
                ((SearchResult)it.next()).sort();
        }
    }

    public void sort() {
        sort(null);
    }

    /**
     * Internal class that implenents the Comparator interface
     * for sorting SearchResults.
     */
    private class SearchResultComparator implements java.util.Comparator {

        String _attname;
        boolean _identifierSort;

	public SearchResultComparator(String attname) {
            _attname = attname;
            if (attname == null || attname.equals("identifier"))
                _identifierSort = true;
	}

	public int compare(Object o1, Object o2) {

	    int cmp = 0;

            SearchResult sr1 = (SearchResult)o1;
            SearchResult sr2 = (SearchResult)o2;

            Object value1 = null;
            Object value2 = null;

            if (_identifierSort) {
                value1 = sr1.getIdentifierString();
                value2 = sr2.getIdentifierString();
            }
            else {
                value1 = sr1.getAttributeValue(_attname);
                value2 = sr2.getAttributeValue(_attname);
            }

            if (value1 != null && value2 != null)
                cmp = value1.toString().compareTo(value2);
            else if (value1 == null && value2 == null)
                cmp = 0;
            else if (value1 == null)
                cmp = -1;
            else
                cmp = 1;

	    return cmp;
	}

	public boolean equals(Object obj) {
	    boolean eq = false;
	    if (obj instanceof SearchResultComparator) {
		SearchResultComparator src = (SearchResultComparator)obj;
		eq = (_attname == src._attname);
	    }
	    return eq;
	}
    }

    //////////////////////////////////////////////////////////////////////
    //
    // Pruning
    //
    //////////////////////////////////////////////////////////////////////

    /**
     * Remove response attributes with certain names.   
     * This can be used with unit tests to remove attributes
     * with non-deterministic values like dates or generated
     * passwords, prior to the serialization of the response.
     * The xml can then be compared against an expected result
     * captured at another time.
     */
    public void removeAttributes(List names) {

        if (names != null && _results != null) {
            Iterator it = _results.iterator();
            while (it.hasNext()) {
                SearchResult sr = (SearchResult)it.next();
                sr.removeAttributes(names);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////
    //
    // XML
    //
    //////////////////////////////////////////////////////////////////////

    String getElementName() {
        return ELEMENT;
    }

    void addSubclassElements(SpmlBuffer b) {

        if (_results != null) {
            Iterator it = _results.iterator();
            while (it.hasNext()) {
                SearchResult r = (SearchResult)it.next();
                r.toXml(b);
            }
        }
    }

    void parseXml(XmlElement e) {

        super.parseXml(e);

	for (XmlElement child = e.getChildElement() ; 
	     child != null ; child = child.next()) {

	    String tag = child.getLocalName();

	    if (tag.equals(SearchResult.ELEMENT))
                addResult(new SearchResult(child));
        }
    }

}
