package com.artbeatte.exercises.linkedlist;

import com.artbeatte.exercises.testing.ExternalTestCase;
import com.artbeatte.exercises.testing.SystemTestRunner;
import com.artbeatte.exercises.testing.TestRunner;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.io.IOException;
import java.io.OutputStream;

/**
 * Created by sarbs on 11/17/15.
 */
public class LinkedListNode {
    private static int traversals;
    private static void incTraversals() {
        if (++traversals > (2 << 24))
            throw new RuntimeException("fail");
    }

    private LinkedListNode next;
    private Object value;

    public LinkedListNode getNext() {
        incTraversals();
        return next;
    }

    public Object getValue() {
        return value;
    }

    public void setNext(LinkedListNode next) {
        this.next = next;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    /**
     * Detects if there are any node in a linked list points back to a node in the same list, thus creating a loop.
     *
     * @param start The start of the list
     * @return True if the list contains a loop, false if the list terminates normally
     */
    public static boolean detectLoop(LinkedListNode start) {
        throw new NotImplementedException();
    }

    public static void main(String args[]) {
        TestRunner tr = new SystemTestRunner();
        tr.addTestCase(new ExternalTestCase("shortStraight", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                for (int i = 0; i < 50; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                }

                return !LinkedListNode.detectLoop(root);
            }
        }));

        tr.addTestCase(new ExternalTestCase("longStraight", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                for (int i = 0; i < 500000; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                }

                return !LinkedListNode.detectLoop(root);
            }
        }));

        tr.addTestCase(new ExternalTestCase("smallLoop", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                LinkedListNode reentry = null;
                for (int i = 0; i < 50; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                    if (i == 45)
                        reentry = node;
                }
                node.setNext(reentry);

                return LinkedListNode.detectLoop(root);
            }
        }));

        tr.addTestCase(new ExternalTestCase("smallLoop2", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                LinkedListNode reentry = null;
                for (int i = 0; i < 50; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                    if (i == 44)
                        reentry = node;
                }
                node.setNext(reentry);

                return LinkedListNode.detectLoop(root);
            }
        }));

        tr.addTestCase(new ExternalTestCase("smallLoopFar", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                LinkedListNode reentry = null;
                for (int i = 0; i < 50000; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                    if (i == 49995)
                        reentry = node;
                }
                node.setNext(reentry);

                return LinkedListNode.detectLoop(root);
            }
        }));

        tr.addTestCase(new ExternalTestCase("bigLoop", new ExternalTestCase.ExternalTest() {
            @Override
            public boolean execute(OutputStream outputStream) throws IOException {
                LinkedListNode root = new LinkedListNode();
                LinkedListNode node = root;
                LinkedListNode reentry = null;
                for (int i = 0; i < 500000; i++) {
                    LinkedListNode newNode = new LinkedListNode();
                    node.setNext(newNode);
                    node = newNode;
                    if (i == 45)
                        reentry = node;
                }
                node.setNext(reentry);

                return LinkedListNode.detectLoop(root);
            }
        }));

        tr.runTests();
    }
}

@@ -610,34 +610,8 @@
 ext;
-%0A    private Object value;
 %0A%0A  
@@ -714,204 +714,68 @@
 lic 
-Object getValue() %7B%0A        return value;%0A    %7D%0A%0A    public void setNext(LinkedListNode next) %7B%0A        this.next = next;%0A    %7D%0A%0A    public void setValue(Object value) %7B%0A        this.value = value
+void setNext(LinkedListNode next) %7B%0A        this.next = next
 ;%0A  

Remove unused value