/** An address is made up of a String representing the Street, a city, a state, and a zip code
 * @author Braskin, Aaron
 * @version March 6th, 2015
 */
public class Address {
	// Constants
	public static final String[] STATE_ABBREVIATIONS={"AK","AL","AR","AZ","CA","CO","CT","DC",
		"DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","LA","MA","MD","ME","MI","MN","MO",
		"MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY","OH","OK","OR","PA","RI","SC","SD",
		"TN","TX","UT","VA","VT","WA","WI","WV","WY"};
	// Class Methods
	/**
	 * Given a string, this method returns true if the upper case of that string matches a
	 * standard two letter code for one of the United States of America
	 * @param possibleState the string to check
	 * @return <code>true</code> only if <code>possibleState</code> is an upper or
	 * lower case two letter state abbreviation
	 */
	public static boolean isValidStateAbreviation(String possibleState) {
		if (possibleState==null) return false;
		for (String aStateAbbreviation:STATE_ABBREVIATIONS) {
			if (possibleState.equalsIgnoreCase(aStateAbbreviation)) return true;	
		}
		return false;
	}
	/**
	 * Determines if the parameter is a five digit string
	 * @param possibleZip the string to check
	 * @return <code>true</code> only if <code>possibleZip</code> is exactly 5 digits
	 */
	public static boolean isValidZip(String possibleZip) {
		if (possibleZip==null || possibleZip.length()!=5) return false;
		String digits="0123456789";
		for (int i=0; i<possibleZip.length(); i++) {
			if (digits.indexOf(possibleZip.substring(i, i+1))==-1) return false;
		}	
		return true;
	}
	// Instance Variables
	private String street;
	private String city;
	private String state; // A two letter state abbreviation
	private String zip; // a five digit zip code
	// Constructors
	/** The default constructor makes the Street, City, State, and Zip empty strings. */
	public Address() {
		street="";
		city="";
		state="";
		zip="";
	}
	/** This constructor sets the Street, City, State, and Zip Code or makes them empty
	 * strings if a <code>null</code> value is given.
	 * @param street the Street Address
	 * @param city the City
	 * @param state the two letter State abbreviation
	 * @param zip the 5 digit Zip Code
	 */
	public Address(String street, String city, String state, String zip) {
		/* For each instance variable (field), only assign the parameter value to the
		 * instance variable if it is valid (i.e. not null), otherwise make it an
		 * empty String
		 */
		if (street!=null) {
			this.street=street;
		} else {
			this.street="";
		}
		if (city!=null) {
			this.city = city;
		} else {
			this.city="";			
		}
		if (isValidStateAbreviation(state)) {
			this.state = state.toUpperCase();
		} else {
			this.state="";
		}
		if (isValidZip(zip)) {
			this.zip = zip;
		} else {
			this.zip="";
		}
	}

	// Getters
	public String getStreet() {
		return street;
	}
	public String getCity() {
		return city;
	}
	public String getState() {
		return state;
	}
	public String getZip() {
		return zip;
	}
	public String toString() {
		String s=street+"\n";
		s+=city+", "+state+" "+zip;
		return s;
	}
	// Setters
	/** 
	 * Sets the field if the parameter is not null, otherwise it remains unchanged
	 * @param street the street address
	 */
	public void setStreet(String street) {
		// If the parameter String isn't null...
		if (street!=null) {
			// Assign the value of the parameter to the instance variable (field)
			this.street = street;
		}
	}
	/**
	 * Sets the field if the parameter is not null, otherwise it remains unchanged
	 * @param city the city
	 */
	public void setCity(String city) {
		// First, check to make sure the parameter String has a value
		if (city==null) return;
		// Assign the instance variable (field) the parameter value
		this.city = city;
	}
	/**
	 * Sets the field to the upper case of the parameter if it is not null and is
	 * a valid two letter state abbreviation,
	 * otherwise it remains unchanged
	 * @param state a valid two letter state abbreviation 
	 */
	public void setState(String state) {
		// Check to make sure the parameter is a valid State abbreviation
		if (isValidStateAbreviation(state)) {
			// Set the instance variable (field) and make sure its upper case
			this.state = state.toUpperCase();
		}
	}
	/**
	 * Sets the field if the parameter is a valid 5 digit United States Zip Code
	 * @param zip a valid 5 digit zip code
	 */
	public void setZip(String zip) {
		if (isValidZip(zip)) {
			this.zip = zip;
		}
	}
}