package org.jboss.cache.aop.integrated;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.aop.test.NetworkAdmin;
import org.jboss.cache.aop.test.NetworkDomain;
import org.jboss.cache.aop.test.NetworkElement;
import org.jboss.cache.aop.test.NetworkNode;

import java.util.List;

/**
 * Sample example for network management that consists of fine-grained replication and object graph (including
 * Collection)
 * <p>Specifically, it illustrates the following object relationship:
 * <ul>
 * <li>Multiple referece, e.g., shared sub-objects (Domain may share DataNode)</li>
 * <li>Recursive, e.g., parent-child relationship (DataNode and Element)</li>
 * </ul>
 *
 * @author Ben Wang
 */

public class NetworkManagementAopTest extends TestCase {
   Log log = LogFactory.getLog(NetworkManagementAopTest.class);
   PojoCache cache1;

   public NetworkManagementAopTest(String name) {
      super(name);
   }

   protected void setUp() throws Exception {
      super.setUp();
      log.info("setUp() ....");
      cache1 = createCache("CacheGroup");
   }

   protected void tearDown() throws Exception {
      super.tearDown();
      cache1.remove("/");
      cache1.stop();
   }

   private PojoCache createCache(String name) throws Exception {
      PojoCache tree = new PojoCache();
      PropertyConfigurator config = new PropertyConfigurator();
      config.configure(tree, "META-INF/replSync-service.xml"); // read in generic replAsync xml
      tree.setClusterName(name);
      tree.createService();
      tree.startService();
      return tree;
   }

   /**
    * Domain shares Admin object.
    */
   public void testDomainAndAdmin() throws Exception {
      NetworkAdmin admin = new NetworkAdmin();
      admin.setId("Benny");

      NetworkDomain tempSensorDomain = new NetworkDomain();
      tempSensorDomain.setName("Temperature sensors");
      tempSensorDomain.setAdmin(admin);


      NetworkDomain vibSensorDomain = new NetworkDomain();
      vibSensorDomain.setName("Vibration sensors");
      vibSensorDomain.setAdmin(admin);

      cache1.putObject("/temp", tempSensorDomain);
      cache1.putObject("/vib", vibSensorDomain);

      NetworkDomain d1 = (NetworkDomain) cache1.getObject("/temp");
      NetworkDomain d2 = (NetworkDomain) cache1.getObject("/vib");

      assertEquals("Admin should be the same", d1.getAdmin(), d2.getAdmin());

      d2.getAdmin().setId("Wen");
      assertEquals("New admin id is ", "Wen", d1.getAdmin().getId());

      assertEquals("New admin id is ", "Wen", admin.getId());

      NetworkDomain temp1 = (NetworkDomain) cache1.removeObject("/temp");
      NetworkDomain vib1 = (NetworkDomain) cache1.removeObject("/vib");

      assertEquals("Vibration sensor ", vibSensorDomain, vib1);
      assertEquals("Temperature sensor ", tempSensorDomain, temp1);
   }

   /**
    * Domain shares Admin object, domain also contains a list of Nodes, and each DataNode has sensor elements
    */
   public void testNodeAndElement() throws Exception {
      // Construct nodes
      NetworkNode taipei = new NetworkNode();
      taipei.setName("Taipei machine");
      taipei.setIpAddress("192.168.1.100");

      NetworkNode tainan = new NetworkNode();
      tainan.setName("Tainan machine");
      tainan.setIpAddress("192.168.1.200");

      // Contruct sensor elements
      NetworkElement vibSensor1 = new NetworkElement();
      vibSensor1.setName("Vibration sensor V10");

      NetworkElement vibSensor2 = new NetworkElement();
      vibSensor2.setName("Vibration sensor V20");

      NetworkElement tempSensor1 = new NetworkElement();
      tempSensor1.setName("Temperature sensor T10");

      NetworkElement tempSensor2 = new NetworkElement();
      tempSensor2.setName("Temperature sensor T20");

      // Add sensor element to DataNode
      taipei.addElement(vibSensor1);
      taipei.addElement(tempSensor1);
      tainan.addElement(vibSensor2);
      tainan.addElement(tempSensor2);

      assertEquals("Element size ", 2, taipei.getElements().size());

      // ask cache to manage the domains
      cache1.putObject("/taipei", taipei);
      cache1.putObject("/tainan", tainan);

      NetworkNode taipei1 = (NetworkNode) cache1.getObject("/taipei");
      NetworkNode tainan1 = (NetworkNode) cache1.getObject("/tainan");

      taipei1.setIpAddress("192.168.10.100");
      assertEquals("New admin id is ", "192.168.10.100", taipei.getIpAddress());

      List l2 = taipei1.getElements();
      assertEquals("Size is ", 2, l2.size());
      NetworkElement vibSens1 = (NetworkElement) l2.get(0);
      NetworkElement tempSens1 = (NetworkElement) l2.get(1);

      int SUSPENDED = 2;
      vibSens1.setStatus(SUSPENDED);
      tempSens1.setStatus(SUSPENDED);

      assertEquals("Status ", vibSensor1.getStatus(), vibSens1.getStatus());
      assertEquals("Status ", tempSensor1.getStatus(), tempSens1.getStatus());
   }

   /**
    * Domain shares Admin object, domain also contains a list of Nodes, and each DataNode has sensor elements
    */
   public void testSharedNodeAndElement() throws Exception {
      // Construct nodes
      NetworkNode taipei = new NetworkNode();
      taipei.setName("Taipei machine");
      taipei.setIpAddress("192.168.1.100");

      NetworkNode tainan = new NetworkNode();
      tainan.setName("Tainan machine");
      tainan.setIpAddress("192.168.1.200");

      // Contruct sensor elements
      NetworkElement vibSensor1 = new NetworkElement();
      vibSensor1.setName("Vibration sensor V10");

      NetworkElement vibSensor2 = new NetworkElement();
      vibSensor2.setName("Vibration sensor V20");

      NetworkElement tempSensor1 = new NetworkElement();
      tempSensor1.setName("Temperature sensor T10");

      NetworkElement tempSensor2 = new NetworkElement();
      tempSensor2.setName("Temperature sensor T20");

      // Add sensor element to DataNode
      taipei.addElement(vibSensor1);
      taipei.addElement(tempSensor1);
      tainan.addElement(vibSensor2);
      tainan.addElement(tempSensor2);

      assertEquals("Element size ", 2, taipei.getElements().size());

      // ask cache to manage the domains
      cache1.putObject("/taipei", taipei);
      cache1.putObject("/alias", taipei);
      System.out.println(cache1.printDetails());

      NetworkNode taipei1 = (NetworkNode) cache1.getObject("/taipei");
      NetworkNode taipei2 = (NetworkNode) cache1.getObject("/alias");

      taipei1.setIpAddress("192.168.10.100");
      assertEquals("New admin id is ", "192.168.10.100", taipei.getIpAddress());

      List l2 = taipei2.getElements();
      assertEquals("Size is ", 2, l2.size());
      NetworkElement vibSens1 = (NetworkElement) l2.get(0);
      NetworkElement tempSens1 = (NetworkElement) l2.get(1);

      int SUSPENDED = 2;
      vibSens1.setStatus(SUSPENDED);
      tempSens1.setStatus(SUSPENDED);

      assertEquals("Status ", vibSensor1.getStatus(), vibSens1.getStatus());
      assertEquals("Status ", tempSensor1.getStatus(), tempSens1.getStatus());
   }


   /**
    * Domain shares Admin object, domain also contains a list of Nodes, and each DataNode has sensor elements
    */
   public void testRecursive() throws Exception {
      NetworkAdmin admin = new NetworkAdmin();
      admin.setId("Benny");

      // Construct domains
      NetworkDomain tempSensorDomain = new NetworkDomain();
      tempSensorDomain.setName("Temperature sensors");
      tempSensorDomain.setAdmin(admin);

      NetworkDomain vibSensorDomain = new NetworkDomain();
      vibSensorDomain.setName("Vibration sensors");
      vibSensorDomain.setAdmin(admin);

      // Construct nodes
      NetworkNode taipei = new NetworkNode();
      taipei.setName("Taipei machine");
      taipei.setIpAddress("192.168.1.100");

      NetworkNode tainan = new NetworkNode();
      tainan.setName("Tainan machine");
      tainan.setIpAddress("192.168.1.200");

      // Contruct sensor elements
      NetworkElement vibSensor1 = new NetworkElement();
      vibSensor1.setName("Vibration sensor V10");

      NetworkElement vibSensor2 = new NetworkElement();
      vibSensor2.setName("Vibration sensor V20");

      NetworkElement tempSensor1 = new NetworkElement();
      tempSensor1.setName("Temperature sensor T10");

      NetworkElement tempSensor2 = new NetworkElement();
      tempSensor2.setName("Temperature sensor T20");

      // Add sensor element to DataNode
      taipei.addElement(vibSensor1);
      taipei.addElement(tempSensor1);
      tainan.addElement(vibSensor2);
      tainan.addElement(tempSensor2);

      assertEquals("Element size ", 2, taipei.getElements().size());

      // Add elements to domains
      vibSensorDomain.addElement(vibSensor1);
      vibSensorDomain.addElement(vibSensor2);

      tempSensorDomain.addElement(tempSensor1);
      tempSensorDomain.addElement(tempSensor2);

      // ask cache to manage the domains
      cache1.putObject("/vib", vibSensorDomain);

//      System.out.println(cache1.printDetails());
   }

   /**
    * Domain shares Admin object, domain also contains a list of Nodes, and each DataNode has sensor elements
    */
   public void testAll() throws Exception {
      // Construct domains
      NetworkDomain tempSensorDomain = new NetworkDomain();
      tempSensorDomain.setName("Temperature sensors");

      NetworkDomain vibSensorDomain = new NetworkDomain();
      vibSensorDomain.setName("Vibration sensors");

      // Construct nodes
      NetworkNode taipei = new NetworkNode();
      taipei.setName("Taipei machine");
      taipei.setIpAddress("192.168.1.100");

      NetworkNode tainan = new NetworkNode();
      tainan.setName("Tainan machine");
      tainan.setIpAddress("192.168.1.200");

      // Contruct sensor elements
      NetworkElement vibSensor1 = new NetworkElement();
      vibSensor1.setName("Vibration sensor V10");

      NetworkElement vibSensor2 = new NetworkElement();
      vibSensor2.setName("Vibration sensor V20");

      NetworkElement tempSensor1 = new NetworkElement();
      tempSensor1.setName("Temperature sensor T10");

      NetworkElement tempSensor2 = new NetworkElement();
      tempSensor2.setName("Temperature sensor T20");

      // Add sensor element to DataNode
      taipei.addElement(vibSensor1);
      taipei.addElement(tempSensor1);
      tainan.addElement(vibSensor2);
      tainan.addElement(tempSensor2);

      assertEquals("Element size ", 2, taipei.getElements().size());

      // Add elements to domains
      vibSensorDomain.addElement(vibSensor1);
      vibSensorDomain.addElement(vibSensor2);

      tempSensorDomain.addElement(tempSensor1);
      tempSensorDomain.addElement(tempSensor2);

      // ask cache to manage the domains
      cache1.putObject("/vib", vibSensorDomain);
      cache1.putObject("/temp", tempSensorDomain);
      System.out.println(cache1.printDetails());

      NetworkDomain temp1 = (NetworkDomain) cache1.getObject("/temp");
      NetworkDomain vib1 = (NetworkDomain) cache1.getObject("/vib");

      NetworkNode taipei1 = (NetworkNode) temp1.getNodes().get(0);
//      NetworkNode taipei1 = (NetworkNode)temp1.getNodes().get(1);   this would fail on equality
      NetworkNode taipei2 = (NetworkNode) vib1.getNodes().get(0);

      List l1 = temp1.getNodes();
      assertEquals("Size is ", 2, l1.size());

      l1 = taipei.getElements();
      assertEquals("Size is ", 2, l1.size());

      assertEquals("IPAddress ", taipei.getIpAddress(), taipei1.getIpAddress());
      assertTrue("DataNode should be the same", (taipei1 == taipei2));

      taipei2.setIpAddress("192.168.10.100");
      assertEquals("New admin id is ", "192.168.10.100", taipei.getIpAddress());

      List l2 = taipei1.getElements();
      assertEquals("Size is ", 2, l2.size());
      NetworkElement vibSens1 = (NetworkElement) l2.get(0);
      NetworkElement tempSens1 = (NetworkElement) l2.get(1);

      int SUSPENDED = 2;
      vibSens1.setStatus(SUSPENDED);
      tempSens1.setStatus(SUSPENDED);

      assertEquals("Status ", vibSensor1.getStatus(), vibSens1.getStatus());
      assertEquals("Status ", tempSensor1.getStatus(), tempSens1.getStatus());
   }

   public static Test suite() throws Exception {
      return new TestSuite(NetworkManagementAopTest.class);
   }

   public static void main(String[] args) throws Exception {
      junit.textui.TestRunner.run(suite());
   }

}

