/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.buddyreplication.aop;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.aop.test.Address;
import org.jboss.cache.aop.test.Person;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.misc.TestingUtil;

/**
 * Tests PojoCache behaviour when data owners fail.
 *
 * @author <a href="mailto:bstansberry@jboss.org">Brian Stansberry</a>
 */
public class BuddyReplicationFailoverTest extends BuddyReplicationTestsBase
{
    protected boolean optimisticLocks = false;
    private Person husband;
    private Person wife;
    private Address address;
    private List medications;
    private Map hobbies;
    private PojoCache[] caches;

    
    protected void setUp() throws Exception
   {
      super.setUp();
      
      husband = new Person();
      husband.setName("Joe");
      husband.setAge(60);
      
      wife = new Person();
      wife.setName("Mary");
      wife.setAge(20);
      
      medications = new ArrayList();
      medications.add("Viagra");
      husband.setMedication(medications);
      
      hobbies = new HashMap();
      hobbies.put("Tennis", "Excellent");
      
      wife.setHobbies(hobbies);
      
      address = new Address();
      address.setStreet("101 Easy Street");
      address.setCity("Fremont, CA");
      address.setZip(94536);
      
      husband.setAddress(address);
      wife.setAddress(address);
   }


   protected void tearDown()
    {
        if (caches != null)
        {
            cleanup(caches);
            caches = null;
        }
    }


    public void testSimpleSharedObjectGravitationKillOwner() throws Exception
    {
        testSimpleSharedObjectGravitation(true);
    }

    public void testSimpleSharedObjectGravitationDontKillOwner() throws Exception
    {
        testSimpleSharedObjectGravitation(false);
    }

    private void testSimpleSharedObjectGravitation(boolean killOwner) throws Exception
    {
        caches = createCaches(3, false, true, optimisticLocks);

        String fqnH = "/husband";
        String backupFqnH = "/" + BuddyManager.BUDDY_BACKUP_SUBTREE + "/" + BuddyManager.getGroupNameFromAddress(caches[0].getLocalAddress()) + fqnH;
        
        String fqnW = "/wife";
        String backupFqnW = "/" + BuddyManager.BUDDY_BACKUP_SUBTREE + "/" + BuddyManager.getGroupNameFromAddress(caches[0].getLocalAddress()) + fqnW;

        caches[0].putObject(fqnH, husband);
        caches[0].putObject(fqnW, wife);
        
        dumpCacheContents(caches);

        assertEquals("Husband should exist", husband, caches[0].getObject(fqnH));

        // use exists instead of get() to prevent going up the interceptor stack
        assertTrue("Should be false", !caches[1].exists(fqnH));
        assertTrue("Should be false", !caches[2].exists(fqnH));
        assertTrue("Should be false", !caches[1].exists(fqnW));
        assertTrue("Should be false", !caches[2].exists(fqnW));

        assertTrue("Husband exists", caches[1].exists(backupFqnH));
        assertTrue("Wife exists", caches[1].exists(backupFqnW));

        if (killOwner)
        {
            caches[0].stopService();
            caches[0] = null;
            TestingUtil.sleepThread(500);
            System.out.println("***** Killed original data owner, about to call a get on a different cache instance.  *****");
            
            dumpCacheContents(caches);
        }
       
        // according to data gravitation, a call to *any* cache should 
        // retrieve the data and move the data to the new cache.
        
        Person wife2 = (Person) caches[2].getObject(fqnW);
        
        dumpCacheContents(caches);
        
        assertNotNull("Wife has gravitated", wife2);
        assertEquals("Wife's address has gravitated", wife.getAddress().getStreet(), 
                     wife2.getAddress().getStreet());
        assertEquals("Wife's hobby has gravitated", "Excellent", 
              wife2.getHobbies().get("Tennis"));
        
//        Person husband2 = (Person) caches[2].getObject(fqnH);
//        
//        assertNotNull("Husband has gravitated", husband2);
//        assertTrue("Husband's medication has gravitated", 
//                   husband2.getMedication().contains("Viagra"));
        
//        TestingUtil.sleepThread(500);
//
//        dumpCacheContents(caches);
//        
//        // now lets test the eviction part of gravitation
//        String newBackupFqn = "/" + BuddyManager.BUDDY_BACKUP_SUBTREE + "/" + BuddyManager.getGroupNameFromAddress(caches[2].getLocalAddress()) + fqnW;
//
//        // use exists instead of get() to prevent going up the interceptor stack
//        if (!killOwner) assertTrue("Should be false", !caches[0].exists(fqnW));
//        assertTrue("Should be false", !caches[1].exists(fqnW));
//
//        // the old backup should no longer exist
//        if (!killOwner) assertTrue("Should be null", caches[0].exists(backupFqnW));
//        assertTrue("Should be null", caches[1].exists(backupFqnW));
//        assertTrue("Should be null", caches[2].exists(backupFqnW));
//
//        // and the backup should now exist in caches[2]'s buddy which is caches[0]
//        if (killOwner)
//        {
//            assertTrue("Value should exist", caches[1].exists(newBackupFqn));
//        }
//        else
//        {
//            assertTrue("Value should exist", caches[0].exists(newBackupFqn));
//            assertFalse("Should be null", caches[1].exists(newBackupFqn));
//        }
//        assertFalse("Should be null", caches[2].exists(newBackupFqn));
    }
}
