package edu.hawaii.ics.yucheng;
import java.util.Scanner;
/**
* A undirected, non-cyclical edge. This class is immutable.
*/
final class Edge implements Comparable<Edge> {
private final int myFirst;
private final int mySecond;
/**
* Initializes a new instance of the class.
*
* @param first The first vertex.
*
* @param second The second vertex.
*/
public Edge(final int first, final int second) {
if (first < 0 || second < 0 || first == second)
throw new GraphException("Invalid arguments.");
if (first < second) {
myFirst = first;
mySecond = second;
} else {
myFirst = second;
mySecond = first;
}
}
/**
* Initializes a new instance of the class.
*
* @param scanner The scanner.
*
* @throws GraphException Thrown if there is an error reading from the
* scanner.
*/
public Edge(final Scanner scanner) throws GraphException {
if (scanner == null)
throw new NullPointerException("scanner");
// Catch and rethrow an exceptions in this constructor.
try {
// Read the next line.
final String from = scanner.nextLine();
// Split the line into a left and right side of the comma.
final String[] fields = from.split(",");
if (fields.length != 2)
throw new GraphException("Invalid edge (No comma present)");
// Parse the first and second values as integers. The values are stored
// in the file as 1-based values, but this class stores them as 0-based
// values.
final int first = Integer.parseInt(fields[0].trim()) - 1;
final int second = Integer.parseInt(fields[1].trim()) - 1;
// Check for bad indices.
if (first < 0)
throw new GraphException("Invalid edge (First index too small)");
if (second < 0)
throw new GraphException("Invalid edge (Second index too small)");
if (first == second)
throw new GraphException("Invalid edge (self-loop detected at vertex "
+ (first + 1) + ")");
if (first < second) {
myFirst = first;
mySecond = second;
} else {
myFirst = second;
mySecond = first;
}
} catch (final GraphException e) {
throw e;
} catch (final Exception e) {
final String name = e.getClass().getName();
throw new GraphException("Invalid edge (" + name + ")", e);
}
}
/**
* Compares this edge to another edge.
*
* @param o The other edge.
*
* @return Negative if less than, positive if greater than, and zero if equal.
*/
public int compareTo(final Edge o) {
// This is always greater than null edges.
if (o == null)
return 1;
// Return zero if both are found.
if (o.contains(myFirst) && o.contains(mySecond))
return 0;
// Sort by first, then by second.
int result;
if (0 != (result = myFirst - o.myFirst))
return result;
return mySecond - o.mySecond;
}
/**
* Returns true if the edge contains a specified index.
*
* @param index The index.
*
* @return True if the edge contains the index or false if it does not.
*/
public boolean contains(final int index) {
return myFirst == index || mySecond == index;
}
/**
* Returns true if the object equals this instance.
*
* @param obj The object to compare.
*
* @return True indicates the object equals this instance.
*/
@Override
public boolean equals(final Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!obj.getClass().equals(getClass()))
return false;
return 0 == compareTo((Edge) obj);
}
/**
* Returns the first index.
*
* @return The first index.
*/
public int first() {
return myFirst;
}
/**
* Returns the opposite index of the one specified. For example, passing the
* value of first() will return seconds(), and passing the value of second()
* will return first().
*
* @param index The index.
*
* @return The opposite index.
*/
public int getOpposite(final int index) {
if (myFirst == index)
return mySecond;
if (mySecond != index)
throw new GraphException("Invalid index");
return myFirst;
}
/**
* Returns a hash code value for the object.
*
* @return A hash code value for this object.
*/
@Override
public int hashCode() {
return myFirst | mySecond << 16;
}
/**
* Returns the second index.
*
* @return The second index.
*/
public int second() {
return mySecond;
}
/**
* Returns the string representation of the class data.
*
* @return The string representation of the class data.
*/
@Override
public String toString() {
return myFirst + 1 + ".." + (mySecond + 1);
}
}