import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.PriorityQueue;

import org.junit.AfterClass;
import org.junit.Test;

public class Testing {
	
	private static int points = 0;

	@Test
	public void testAddandtoArray(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		assertTrue(q.add(4));
		assertTrue(q.add(2));

		try {
			q.add(null);
			fail("Did not throw NullPointerException");
		} catch (Exception e){
			if (!(e instanceof NullPointerException)) {
				fail("Did not throw NullPointerException");				
			}
		}
		Object[] a = q.toArray();
//		for (int i = 0; i < a.length; i++) System.out.println(a[i]);
		assertEquals(2,a[0]);
		assertEquals(2,a[1]);
		assertEquals(3,a[2]);
		assertEquals(5,a[3]);
		assertEquals(4,a[4]);

		points+=7;
	}
	

	
	@Test
	public void testToArray(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		Object[] a = q.toArray();
		assertEquals(3, a.length);
		a[1] = 4;
		Object[] b = q.toArray();
		assertFalse(a[1].equals(b[1]));
		points+=2;
	}

	@Test
	public void testOffer(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.offer(3));
		assertTrue(q.offer(5));
		assertTrue(q.offer(2));
		assertTrue(q.offer(4));
		assertTrue(q.offer(2));
		try {
			q.add(null);
			fail("Did not throw NullPointerException");
		} catch (Exception e){
			if (!(e instanceof NullPointerException)) {
				fail("Did not throw NullPointerException");				
			}
		}
		Object[] a = q.toArray();
		assertEquals(2,a[0]);
		assertEquals(2,a[1]);
		assertEquals(3,a[2]);
		assertEquals(5,a[3]);
		assertEquals(4,a[4]);
		points+=2;
	}
	
	@Test
	public void testPeek(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertEquals(null ,q.peek());		
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		assertEquals(new Integer(2) ,q.peek());	
		points += 2;
	}
	
	@Test
	public void testClear(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		q.clear();
		assertEquals(0,q.toArray().length);
		points += 2;
	}

	@Test
	public void testContains(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		assertTrue(q.contains(2));
		assertFalse(q.contains(7));
		points += 2;
	}
	
	@Test
	public void testSize(){	
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.add(3));
		assertTrue(q.add(5));
		assertTrue(q.add(2));
		assertEquals(3,q.size()); //q.toArray().length);
		points += 2;
	}
	
	@Test
	public void testPoll(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.offer(3));
		assertTrue(q.offer(5));
		assertTrue(q.offer(2));
		assertTrue(q.offer(4));
		assertTrue(q.offer(2));
		assertTrue(q.offer(7));
		assertTrue(q.offer(1));
		Iterator<Integer> it = q.iterator();
		ArrayList<Integer> a = new ArrayList();
		a.add(1);
		a.add(2);
		a.add(2);
		a.add(5);
		a.add(4);
		a.add(7);
		a.add(3);
		for (int i = 0; i < a.size(); i++) {
			assertTrue(it.hasNext());
			assertEquals(a.get(i), it.next());
		}
		assertEquals(new Integer(1),q.poll());
		assertEquals(new Integer(2),q.poll());
		assertEquals(new Integer(2),q.poll());
		assertEquals(new Integer(3),q.poll());
		assertEquals(new Integer(4),q.poll());
		assertEquals(new Integer(5),q.poll());
		assertEquals(new Integer(7),q.poll());
		assertEquals(null,q.poll());
		points += 7;
	}
	
	@Test
	public void testRemove(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		assertTrue(q.offer(3));
		assertTrue(q.offer(5));
		assertTrue(q.offer(2));
		assertTrue(q.offer(4));
		assertTrue(q.offer(2));
		assertFalse(q.remove(new Integer(7)));
		assertTrue(q.remove(new Integer(2)));
		assertTrue(q.remove(new Integer(4)));
		assertFalse(q.remove(new Integer(4)));
		Object[] temp = q.toArray();
		assertEquals(3, temp.length);
		Integer[] test = {2, 5, 3};
		for (int i = 0; i < temp.length; i++){
			assertEquals(test[i], temp[i]);
		}
		points += 5;
	}
	public static int count = 0;
	public boolean isMinQueue(Integer[] a, int index){
		count++;
		int parent = a[index];
		int rightChildIndex = (index+1)*2;
		int leftChildIndex = rightChildIndex-1;
		if (rightChildIndex >= a.length) return true;
		if (leftChildIndex >= a.length) return true;
		if (parent <= a[leftChildIndex] && parent <= a[rightChildIndex])
			return isMinQueue(a, leftChildIndex) && isMinQueue(a, rightChildIndex);
		return false;
	}
	
	@Test
	public void testLogBehavior(){
		MyPriorityQueue<Integer> q = new MyPriorityQueue<Integer>();
		int nums = 3000000;
		for (int i = 0; i < nums; i++){
			q.offer((int) (Math.random() * nums));
		}
//		assertTrue(isMinQueue(q.toArray(new Integer[0]), 0));
//		System.out.println(count);
		int end = q.size();
		int last = q.peek();
		assertEquals(nums, end);
		for (int i = 0; i < end; i++){
//			System.out.println(i);
			int temp = q.poll();
//			if (last>temp) {System.out.println(last + " " + temp);}
			assertTrue(last <= temp);
			last = temp;
		}
		assertEquals(0, q.size());
		points += 19;
	}
	
	@AfterClass
	public static void testNothing(){
		System.out.println("Points: " + points + "/50");
	}

}