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); } }