package l23_3;

public class DoubleLinkedList {
	private DllNode head;
	private DllNode tail;
	private static boolean trace;
	
	// Note... default constructor initializes head to null... good nuff
	
	public static void startTrace() { trace=true; }
	public static void stopTrace() { trace=false; }
	
	public void pushHead(int payload) {
		DllNode newNode = new DllNode(payload);
		if (head==null) tail=newNode;
		else head.setPrev(newNode);
		newNode.setNext(head);
		head=newNode;
		if (trace) 
			System.out.println("pushHead(" + payload + ") : " + toString());
	}
	
	public void pushTail(int payload) {
		DllNode newNode = new DllNode(payload);
		if (tail==null) head=newNode;
		else tail.setNext(newNode);
		newNode.setPrev(tail);
		tail=newNode;
		if (trace) 
			System.out.println("pushTail(" + payload + ") : " + toString());
	}
	
	public void pushOrder(int payload) {
		if (head==null) head=tail=new DllNode(payload);
		else if (payload < head.getPayload()) pushHead(payload);
		else pushOrder(payload,head);
		if (trace) 
			System.out.println("pushOrder(" + payload + ") : " + toString());
	}
	
	private void pushOrder(int payload,DllNode after) {
		DllNode afterNext=after.getNext();
		if (afterNext==null) {
			DllNode newNode=new DllNode(payload);
			after.setNext(newNode);
			newNode.setPrev(after);
			tail=newNode;
		}
		else if (payload >= afterNext.getPayload()) pushOrder(payload,afterNext);
		else {
			DllNode newNode = new DllNode(payload);
			// Insert new node in list between after and afternext
			after.setNext(newNode);
			newNode.setNext(afterNext);
			afterNext.setPrev(newNode);
			newNode.setPrev(after);
		}
	}

	@Override
	public String toString() {
		if (head==null) return "empty";
		return toString(head);
	}
	
	private String toString(DllNode from) {
		DllNode next=from.getNext();
		String result ="";
		if (from.getPrev()==null) result="null -> ";
		result +=from.toString();
		if (next==null) result+= " -> null";
		else result += " <-> " + toString(next);
		return result;
	}
	
	private class DllNode {
		private int payload;
		private DllNode prev;
		private DllNode next;
		
		public DllNode(int payload) {
			this.payload=payload;
			this.prev=null;
			this.next=null;
		}

		public int getPayload() { return payload; }
		
		public DllNode getNext() { return next; }

		public void setNext(DllNode next) { this.next = next; }

		public DllNode getPrev() { return prev; }

		public void setPrev(DllNode prev) { this.prev = prev; }

		@Override
		public String toString() {
			return "[" + 
					((prev==null)? "null" : prev.getPayload()) + "<-" + 
	 				payload + 
	 				"->" + ((next==null)? "null" : next.getPayload()) + 
	 				"]";
		}	

	}
	
}
