/**
 * 2402Assignment1.java
 *
 * Caitlin Ross
 * 100735219
 */
 
class Row extends Object {
	
	//Fields
	
	private int rowNumber;
	private int numberOfColumns;
	private Entry head;
	private Row nextRow;
	
	
	//Constructors
	
	//Creates a blank, empty Row
	public Row(){
		rowNumber = 0;
		numberOfColumns = 0;
		head = null;
		nextRow = null;
	}
	
	//Creates a new Row with the given parameters
	public Row(int rowNum, int numCols, Row next){
		rowNumber = rowNum;
		numberOfColumns = numCols;
		head = null;
		nextRow = next;
	}
	
	//Deep copies a Row
	public Row(Row aRow){
		rowNumber = aRow.rowNumber;
		numberOfColumns = aRow.numberOfColumns;
		
		//Check if aRow.head is null before setting the head
		if(aRow.head != null)
			head = new Entry(aRow.head);
		else
			head = null;
		
		//Check if aRow.nextRow is null before setting the nextRow
		if(aRow.nextRow != null)
			nextRow = new Row(aRow.nextRow);
		else
			nextRow = null;
	}
	
	
	//Accessors
	
	//Returns the value at the specified Entry
	public int getEntry(int colNum){
		
		//Find the Entry that matches the column number
		Entry anEntry = findEntry(colNum);
		
		//If the Entry doesn't exist, the value is 0
		if (anEntry == null)
			return 0;
		return anEntry.getValue();
	}
	
	//Returns the row number
	public int getRowNumber(){
		return rowNumber;
	}
	
	//Returns the next Row in the list
	public Row getNext(){
		return nextRow;
	}
	
	//Checks if the Row is empty
	public boolean isEmpty(){
		return (head==null);
	}
	
	//Displays the entire Row
	public String toString(){
		String display = "";
		Entry current;
		
		//Iterate through the Entries in the Row
		for(int i=1; i<=numberOfColumns; i++){
			current = findEntry(i);
			
			//If the Entry exists, create a visual representation of it
			if(current != null)
				display += oneEntry(current.getValue());
			
			//If the Entry doesn't exist, display 0
			else
				display += oneEntry(0);
			current = null;
		}
		return display;
	}
	
	//Displays the Row as a list of Entries
	public void displayList(){
		Entry anEntry = head;
		System.out.print("Row " + rowNumber);
		
		//Iterate through the Entries, calling each object's display method
		while (anEntry != null){
			anEntry.display();
			anEntry = anEntry.getNext();
			System.out.print(" ");
		}
	}
	
	
	//Modifiers
	
	//Sets the value of a given Entry
	public void setEntry(int colNumber, int value){
		
		//Find the Entry with the given column number
		Entry anEntry = findEntry(colNumber);
		
		//If the value is 0, remove the Entry
		if(value == 0){
			removeEntry(anEntry);
			return;
		}
		
		//If the value is not 0, change the Entry
		if (anEntry == null)
			anEntry = insertNewEntry(colNumber);
		anEntry.setValue(value);
	}
	
	//Sets the Row pointed to by this Row
	public void setNext(Row aRow){
		nextRow = aRow;
	}
	
	
	//Helper Methods
	
	//Finds the Entry with the given column number
	private Entry findEntry(int colNum)
	{
		Entry toReturn = head;
		
		//Iterate through the Entries until one is found with the given column number
		while ((toReturn != null) && (toReturn.getColumnNumber() != colNum)){
			toReturn = toReturn.getNext();
		}
		return toReturn;
	}
	
	//Inserts a new Entry at the given column number
	private Entry insertNewEntry(int colNum){
		
		//Find the Entry before the given column number
		Entry entryBefore = findEntryBefore(colNum);
		Entry newEntry;
		
		//If there is no Entry before the current one, create and add one at the head of the list
		if(entryBefore == null)
			newEntry = insertFirst(colNum);
		
		//If there is an Entry before the current one, create and add one after the one before it
		else
			newEntry = insertAfter(entryBefore, colNum);
		return newEntry;
	}
	
	//Finds the Entry that comes before the given column number
	//Returns null if Entry is to be first in the row
	private Entry findEntryBefore(int colNum){
		Entry before = head;
		
		//Iterate over the Entries until getNext has a column number greater than the one being added
		while ((before != null) && (before.getNext() != null) && (before.getNext().getColumnNumber() < colNum)){
			before = before.getNext();
		}
		return before;
	}
	
	//Creates and inserts an Entry at the head of the list
	private Entry insertFirst(int colNum){
		
		//Create a new Entry that points to the old head
		Entry newEntry = new Entry(colNum, head);
		
		//Reset the head
		head = newEntry;
		return newEntry;
	}
	
	//Creates an Entry and inserts it after the given Entry
	private Entry insertAfter(Entry before, int colNumber){
		if (before != null){
			
			//Create a new Entry that points to the one pointed to by the one before it
			Entry newEntry = new Entry(colNumber, before.getNext());
			//Reset the pointer of the Entry before
			before.setNext(newEntry);
			return newEntry;
		}
		
		//If there is no Entry before the current one, cannot add an Entry
		else
			return null;
	}
	
	//Removes a given Entry from the Row
	private void removeEntry(Entry anEntry){
		
		//If the Entry is the head, reset the head pointer
		if(anEntry == head){
			head = head.getNext();
		}
		
		//Otherwise, find the Entry before the current one and reset its pointer
		else{
			Entry before = findEntryBefore(anEntry.getColumnNumber());
			before.setNext (anEntry.getNext());
		}
	}
	
	
	//Static Methods
	
	//Creates a String that represents an entry in the matrix
	private static String oneEntry(int value){
		
		//Create an empty string an add the value
		String anEntry = Integer.toString(value);
		
		//Add the whitespace to the string
		for(int i=0; i<(4-Integer.toString(value).length()); i++)
			anEntry += " ";
		return anEntry;
	}
	
	//Creates a blank row in the matrix with a given number of columns
	public static String blankRow(int cols){
		String row = "";
		
		//Add zeros and whitespace to an empty string
		for(int i=0; i<cols; i++){
			row += oneEntry(0);
		}
		return row;
	}
	
}
