package com.zoox.graphBoardProroBuilder;

import static org.junit.Assert.assertEquals;

import com.zoox.graphBoardProtoBuilder.GraphBoardNode;
import com.zoox.graphBoardProtoBuilder.GraphBoardProto;

import org.junit.Test;

public class GraphBoardProtoTest {

  @Test
  public void emptyProto()
  {
    GraphBoardProto proto = new GraphBoardProto();
    assertEquals("", proto.toString());
  }

  @Test
  public void singleNode()
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node = new GraphBoardNode("node1");
    proto.addNode(node);
    assertEquals(GraphBoardNodeTest.SINGLE_NODE_1, proto.toString());
  }

  @Test
  public void twoNodes()
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    proto.addNode(node1);
    proto.addNode(node2);
    assertEquals(
      GraphBoardNodeTest.SINGLE_NODE_1 +
        "\n" + GraphBoardNodeTest.SINGLE_NODE_2,
      proto.toString());
  }

  @Test
  public void twoNodesWithConnection()
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    node2.addInNode(node1);
    proto.addNode(node1);
    proto.addNode(node2);
    assertEquals(
      GraphBoardNodeTest.SINGLE_NODE_1 +
        "\n" + GraphBoardNodeTest.IN_NODE_2,
      proto.toString());
  }

  @Test
  public void addNodeTwice()
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node = new GraphBoardNode("node1");
    proto.addNode(node);
    proto.addNode(node);
    assertEquals(GraphBoardNodeTest.SINGLE_NODE_1, proto.toString());
  }

  @Test
  public void addOnlyOneNode()
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    node2.addInNode(node1);
    proto.addNode(node2);
    assertEquals(GraphBoardNodeTest.IN_NODE_2, proto.toString());
  }

  @Test
  public void disappearCables() //Node has exactly 2 inputs and 2 outputs which are identical to disappear
  {
    //success
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");
    
    node1.addInNode(node2); 
    node2.addInNode(node1);
    node2.addInNode(node3);
    node3.addInNode(node2);

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);

    assertEquals(
      GraphBoardNodeTest.IN_NODE_1 +
        "\n" + GraphBoardNodeTest.DOUBLE_CIRCULAR_NODE_2 +
        "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3, 
      proto.toString());
    proto.disappearCables();
    assertEquals(
      GraphBoardNodeTest.CIRCULAR_NODE_1 +
        "\n" + GraphBoardNodeTest.IN_NODE_3, 
      proto.toString());
  }

  @Test
  public void disappearCablesWithExtraBefore() //Node into node1 doesn't block effect
  {
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");
    GraphBoardNode node4 = new GraphBoardNode("node4");
    
    node1.addInNode(node2);
    node1.addInNode(node4); //this is different
    node2.addInNode(node1);
    node2.addInNode(node3);
    node3.addInNode(node2);

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);
    proto.addNode(node4);

    String node1String =
      "node {" +
      "\n\tname: node1" +
      "\n\top: \"???\"" +
      "\n\tinput: \"node2\"" +
      "\n\tinput: \"node4\"" +
      "\n\tinclude: \"EXCLUDE\"" +
      "\n}";

    String node4String = 
      "node {" +
      "\n\tname: node4" +
      "\n\top: \"???\"" +
      "\n\tinclude: \"EXCLUDE\"" +
      "\n}";

    // System.out.println(node1String + 
    // "\n" + GraphBoardNodeTest.DOUBLE_CIRCULAR_NODE_2 +
    // "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3 +
    // "\n" + node4String + "\n");
    // System.out.println(proto);
    assertEquals(
      node1String + 
        "\n" + GraphBoardNodeTest.DOUBLE_CIRCULAR_NODE_2 +
        "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3 +
        "\n" + node4String,
      proto.toString());

    proto.disappearCables();

    node1String =
      "node {" +
      "\n\tname: node1" +
      "\n\top: \"???\"" +
      "\n\tinput: \"node3\"" +
      "\n\tinput: \"node4\"" +
      "\n\tinclude: \"EXCLUDE\"" +
      "\n}";
    assertEquals(
      node1String + 
        "\n" + GraphBoardNodeTest.IN_NODE_3 +
        "\n" + node4String,
      proto.toString());
  }

  @Test
  public void disappearCablesWithExtraAfter()
  {
    //node out of node3 has doesn't blocke effect
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");
    GraphBoardNode node4 = new GraphBoardNode("node4");

    node1.addInNode(node2);
    node2.addInNode(node1);
    node2.addInNode(node3);
    node3.addInNode(node2);
    node4.addInNode(node3); //this is different

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);
    proto.addNode(node4);

    String node4String =
      "node {" +
        "\n\tname: node4" +
        "\n\top: \"???\"" +
        "\n\tinput: \"node3\"" +
        "\n\tinclude: \"EXCLUDE\"" +
        "\n}";
    assertEquals(
      GraphBoardNodeTest.IN_NODE_1 +
        "\n" + GraphBoardNodeTest.DOUBLE_CIRCULAR_NODE_2 +
        "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3 +
        "\n" + node4String,
      proto.toString());
    proto.disappearCables();
    assertEquals(
      GraphBoardNodeTest.CIRCULAR_NODE_1 +
        "\n" + GraphBoardNodeTest.IN_NODE_3 +
        "\n" + node4String, 
      proto.toString());
  }

  @Test
  public void disappearCablesTooFewIn()
  {
    //too few connections, no change
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");

    node1.addInNode(node2); 
    node2.addInNode(node1); //didn't add node 3 into node 2
    node3.addInNode(node2);

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);

    final String expectedDisappear = 
        GraphBoardNodeTest.IN_NODE_1 + "\n" +
        GraphBoardNodeTest.IN_NODE_2 + "\n" +
        GraphBoardNodeTest.CIRCULAR_NODE_3;
    assertEquals(expectedDisappear, proto.toString());
    proto.disappearCables();
    assertEquals(expectedDisappear, proto.toString());
  }

  @Test
  public void disappearCablesTooFewOut()
  {
    //too few connections, no change
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");

    node1.addInNode(node2); 
    node2.addInNode(node1); 
    node2.addInNode(node3); //didn't add node 2 into node 3

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);

    String node2String =
      "node {" +
        "\n\tname: node2" +
        "\n\top: \"???\"" +
        "\n\tinput: \"node1\"" +
        "\n\tinput: \"node3\"" +
        "\n\tinclude: \"EXCLUDE\"" + //2 nodes out but only 1 in
        "\n}";

    final String expectedDisappear = 
        GraphBoardNodeTest.IN_NODE_1 + "\n" +
        node2String + "\n" +
        GraphBoardNodeTest.SINGLE_NODE_3;
    assertEquals(expectedDisappear, proto.toString());
    proto.disappearCables();
    assertEquals(expectedDisappear, proto.toString());
  }

  @Test
  public void disappearCablesTooManyIn()
  {
    //too many connections, no change
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");
    GraphBoardNode node4 = new GraphBoardNode("node4");

    node1.addInNode(node2); 
    node2.addInNode(node1);
    node2.addInNode(node3);
    node2.addInNode(node4); //extra node
    node3.addInNode(node2);

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);
    proto.addNode(node4);

    String node2String =
      "node {" +
      "\n\tname: node2" +
      "\n\top: \"???\"" +
      "\n\tinput: \"node1\"" +
      "\n\tinput: \"node3\"" +
      "\n\tinput: \"node4\"" +
      "\n\tinclude: \"INCLUDE\"" +
      "\n}";

    String node4String = 
      "node {" +
      "\n\tname: node4" +
      "\n\top: \"???\"" +
      "\n\tinclude: \"EXCLUDE\"" +
      "\n}";

    final String expectedDisappear = 
        GraphBoardNodeTest.IN_NODE_1 +
        "\n" + node2String +
        "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3 +
        "\n" + node4String;
    assertEquals(expectedDisappear, proto.toString());
    proto.disappearCables();
    assertEquals(expectedDisappear, proto.toString());
  }

  @Test
  public void disappearCablesTooManyOut()
  {
    //too many connections, no change
    GraphBoardProto proto = new GraphBoardProto();
    GraphBoardNode node1 = new GraphBoardNode("node1");
    GraphBoardNode node2 = new GraphBoardNode("node2");
    GraphBoardNode node3 = new GraphBoardNode("node3");
    GraphBoardNode node4 = new GraphBoardNode("node4");

    node1.addInNode(node2); 
    node2.addInNode(node1);
    node2.addInNode(node3);
    node3.addInNode(node2);
    node4.addInNode(node2); //extra node

    proto.addNode(node1);
    proto.addNode(node2);
    proto.addNode(node3);
    proto.addNode(node4);

    String node4String = 
      "node {" +
      "\n\tname: node4" +
      "\n\top: \"???\"" +
      "\n\tinput: \"node2\"" +
      "\n\tinclude: \"EXCLUDE\"" +
      "\n}";

    final String expectedDisappear = 
        GraphBoardNodeTest.IN_NODE_1 +
        "\n" + GraphBoardNodeTest.DOUBLE_CIRCULAR_NODE_2 +
        "\n" + GraphBoardNodeTest.CIRCULAR_NODE_3 +
        "\n" + node4String;
    assertEquals(expectedDisappear, proto.toString());
    proto.disappearCables();
    assertEquals(expectedDisappear, proto.toString());
  }
}