/*
 * @(#)StringIntPair.java    2.5.0   26 April 2006
 *
 * Copyright 2006
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.quick;

import edu.neu.ccs.*;

import java.util.*;

/**
 * <p><code>StringIntPair</code> constructs an immutable pair object
 * from a non-<code>null</code> <code>String</code> and an
 * <code>int</code>.</p>
 *
 * <p>The methods <code>equals</code> and <code>hashCode</code> are
 * designed so that two <code>Pair</code> objects whose contents are
 * equal will be considered equal and will return the same hash code.</p>
 *
 * @author  Richard Rasala
 * @version 2.5.0
 * @since   2.5.0
 */
public class StringIntPair
{
    /** The string in the pair. */
    private String string;
    
    /** The number in the pair. */
    private int number;
    
    
    /**
     * <p>Constructor that constructs the string-int pair using
     * a non-<code>null</code> <code>String</code> and an
     * <code>int</code>.</p>
     *
     * @param  string the string for the pair
     * @param  number the number for the pair
     * @throws <code>NullPointerException</code> if the string is
     *         <code>null</code>
     */
    public StringIntPair(String string, int number) {
        if (string == null)
            throw new NullPointerException
                ("Null String in StringIntPair constructor");
        
        this.string = string;
        this.number = number;
    }
    
    
    /** Returns the string in the pair. */
    public String getString() {
        return string;
    }
    
    
    /**
     * <p>Returns the number in the pair.</p>
     *
     * <p>Synonym for <code>getNumber</code>.</p>
     */
    public int getInt() {
        return number;
    }
    
    
    /**
     * <p>Returns the number in the pair.</p>
     *
     * <p>Synonym for <code>getInt</code>.</p>
     */
    public int getNumber() {
        return number;
    }
    
    
    /**
     * Returns the string
     * combined with the number
     * with a space in between.
     */
    public String toString() {
        String n = Integer.toString(number);
        
        return Strings.joinWithSpace(string, n);
    }
    
    
    /**
     * Returns the string padded on the right to widthS
     * combined with the number
     * with a space in between.
     */
    public String toString(int widthS) {
        String s = Strings.padOnRight(string, widthS);
        String n = Integer.toString(number);
        
        return Strings.joinWithSpace(s, n);
    }
    
    
    /**
     * Returns the string padded on the right to widthS
     * combined with the number padded on the left to widthN
     * with a space in between.
     */
    public String toString(int widthS, int widthN) {
        String s = Strings.padOnRight(string, widthS);
        String n = Strings.padOnLeft (Integer.toString(number), widthN);
        
        return Strings.joinWithSpace(s, n);
    }
    
    
    /**
     * <p><code>Comparator</code> for sorting
     * <code>StringIntPair</code> objects by
     * using the string for the primary sort
     * and the number to distinguish ties.</p>
     * 
     * <p>The <code>compare</code> throws
     * <code>ClassCastException</code> if
     * either argument is not of type
     * <code>StringIntPair</code>.</p>
     */
    public static final Comparator stringFirst
        = new Comparator()
    {
        
        public int compare(Object p, Object q) {
            if (! (p instanceof StringIntPair))
                throw new ClassCastException
                    ("StringIntPair required for compare operation");
            
            if (! (q instanceof StringIntPair))
                throw new ClassCastException
                    ("StringIntPair required for compare operation");
            
            StringIntPair a = (StringIntPair) p;
            StringIntPair b = (StringIntPair) q;
            
            int x = a.string.compareTo(b.string);
            
            if (x != 0)
                return x;
            
            return a.number - b.number;
        }
        
        public boolean equals(Object obj) {
            return obj == this;
        }
    };
    
    
    /**
     * <p><code>Comparator</code> for sorting
     * <code>StringIntPair</code> objects by
     * using the number for the primary sort
     * and the string to distinguish ties.</p>
     * 
     * <p>The <code>compare</code> throws
     * <code>ClassCastException</code> if
     * either argument is not of type
     * <code>StringIntPair</code>.</p>
     */
    public static final Comparator numberFirst
        = new Comparator()
    {
        
        public int compare(Object p, Object q) {
            if (! (p instanceof StringIntPair))
                throw new ClassCastException
                    ("StringIntPair required for compare operation");
            
            if (! (q instanceof StringIntPair))
                throw new ClassCastException
                    ("StringIntPair required for compare operation");
            
            StringIntPair a = (StringIntPair) p;
            StringIntPair b = (StringIntPair) q;
            
            int x = a.number - b.number;
            
            if (x != 0)
                return x;
            
            return a.string.compareTo(b.string);
        }
        
        public boolean equals(Object obj) {
            return obj == this;
        }
    };
    
    
    /**
     * <p>Returns true if the given object is a
     * <code>StringIntPair</code> whose string and number
     * are equal to the corresponding members of this object.</p>
     * 
     * <p>Returns false otherwise.</p>
     */
    public boolean equals(Object object) {
        if (! (object instanceof StringIntPair))
            return false;
        
        StringIntPair x = (StringIntPair) object;
        
        return (x.string.equals(string)) && (x.number == number);
    }
    
    
    /**
     * Returns the sum of the hashcode of the string with
     * the number.
     */
    public int hashCode() {
        return string.hashCode() + number;
    }
    
 }
