/*
* JBoss, Home of Professional Open Source
* Copyright 2007, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.managed.factory.test;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import junit.framework.Test;

import org.jboss.managed.api.ManagedObject;
import org.jboss.managed.api.ManagedProperty;
import org.jboss.managed.api.annotation.ActivationPolicy;
import org.jboss.managed.api.annotation.ManagementObjectID;
import org.jboss.managed.api.annotation.ManagementProperty;
import org.jboss.managed.api.annotation.Masked;
import org.jboss.managed.api.annotation.ViewUse;
import org.jboss.managed.plugins.ManagedPropertyImpl;
import org.jboss.metatype.api.types.SimpleMetaType;
import org.jboss.metatype.api.values.SimpleValueSupport;
import org.jboss.test.managed.factory.AbstractManagedObjectFactoryTest;
import org.jboss.test.managed.factory.support.ManagementPropertyActivationPolicy;
import org.jboss.test.managed.factory.support.ManagementPropertyAnnotations;
import org.jboss.test.managed.factory.support.ManagementPropertyDescription;
import org.jboss.test.managed.factory.support.ManagementPropertyMandatory;
import org.jboss.test.managed.factory.support.ManagementPropertyMasked;
import org.jboss.test.managed.factory.support.ManagementPropertyReadOnly;
import org.jboss.test.managed.factory.support.ManagementPropertySimpleManaged;
import org.jboss.test.managed.factory.support.adminview.PortAdminViewBean;
import org.jboss.test.managed.factory.support.adminview.ServerBean;

/**
 * ManagementPropertyUnitTestCase.
 * 
 * @author <a href="adrian@jboss.com">Adrian Brock</a>
 * @version $Revision: 1.1 $
 */
public class ManagementPropertyUnitTestCase extends AbstractManagedObjectFactoryTest
{
   /**
    * Create a testsuite for this test
    * 
    * @return the testsuite
    */
   public static Test suite()
   {
      return suite(ManagementPropertyUnitTestCase.class);
   }

   /**
    * Create a new ManagementPropertyUnitTestCase.
    * 
    * @param name the test name
    */
   public ManagementPropertyUnitTestCase(String name)
   {
      super(name);
   }
   
   /**
    * Test the overridden description
    */
   public void testDescription()
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyDescription.class);
      checkProperty(managedObject, "property", String.class, "changed", false, null);
   }
   
   /**
    * Test the overridden mandatory
    */
   public void testMandatory()
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyMandatory.class);
      checkProperty(managedObject, "property", String.class, "property", true, null);
   }
   
   /**
    * Test the overridden and accessor based read only
    */
   public void testReadOnly()
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyReadOnly.class);
      checkProperty(managedObject, "readOnly", String.class, "readOnly", false, "readOnly");
      checkProperty(managedObject, "readOnly2", String.class, "readOnly2", false, "readOnly2");
      checkProperty(managedObject, "readWrite", String.class, "readWrite", false, "readWrite");
      checkProperty(managedObject, "readWrite2", String.class, "readWrite2", false, "readWrite2");
      ManagedProperty readOnly = managedObject.getProperty("readOnly");
      assertTrue(readOnly.isReadOnly());
      ManagedProperty readOnly2 = managedObject.getProperty("readOnly");
      assertTrue(readOnly2.isReadOnly());
      ManagedProperty readWrite = managedObject.getProperty("readWrite");
      assertFalse(readWrite.isReadOnly());
      ManagedProperty readWrite2 = managedObject.getProperty("readWrite2");
      assertFalse(readWrite2.isReadOnly());
   }

   /**
    * Test the overidden property to managed object
    */
   public void testSimpleManaged()
   {
      ManagementPropertySimpleManaged test = new ManagementPropertySimpleManaged();
      ManagedObject managedObject = checkManagedObject(test);
      checkPropertyIsManagedObject(managedObject, "property", "property", false, test.getProperty());
   }

   /**
    * Test property annotations
    */
   public void testAnnotations()
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyAnnotations.class);
      ManagedProperty managedProperty = managedObject.getProperty("runtime");
      assertNotNull(managedProperty);
      Map<String, Annotation> annotations = managedProperty.getAnnotations();
      assertEquals(2, annotations.size());
      assertTrue(annotations.containsKey(ManagementProperty.class.getName()));
      assertTrue(annotations.containsKey(ManagementObjectID.class.getName()));
   }

   /**
    * Test property ViewUse
    */
   public void testViewUse()
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyAnnotations.class);
      ManagedProperty runtime = managedObject.getProperty("runtime");
      assertNotNull(runtime);
      assertTrue("has ViewUse.RUNTIME", runtime.hasViewUse(ViewUse.RUNTIME));
      assertTrue("!has ViewUse.CONFIGURATION", !runtime.hasViewUse(ViewUse.CONFIGURATION));
      assertTrue("!has ViewUse.STATISTIC", !runtime.hasViewUse(ViewUse.STATISTIC));

      ManagedProperty configuration = managedObject.getProperty("configuration");
      assertTrue("has ViewUse.CONFIGURATION", configuration.hasViewUse(ViewUse.CONFIGURATION));

      ManagedProperty stat = managedObject.getProperty("stat");
      assertTrue("has ViewUse.STATISTIC", stat.hasViewUse(ViewUse.STATISTIC));
   }

   /**
    * Test the 
    */
   @ManagementProperty(name="runtime-stat", use={ViewUse.STATISTIC})
   public void testViewUseField()
      throws Exception
   {
      ManagedPropertyImpl mp = new ManagedPropertyImpl("runtime");
      mp.setMetaType(SimpleMetaType.LONG);
      mp.setValue(SimpleValueSupport.wrap(1000));
      mp.setViewUse(new ViewUse[]{ViewUse.RUNTIME});
      assertTrue("has ViewUse.RUNTIME", mp.hasViewUse(ViewUse.RUNTIME));

      ManagedPropertyImpl mp2 = new ManagedPropertyImpl("runtime-stat");
      mp2.setMetaType(SimpleMetaType.LONG);
      mp2.setValue(SimpleValueSupport.wrap(1000));
      mp2.setViewUse(new ViewUse[]{ViewUse.RUNTIME, ViewUse.STATISTIC});
      assertTrue("has ViewUse.RUNTIME", mp2.hasViewUse(ViewUse.RUNTIME));
      assertTrue("has ViewUse.STATISTIC", mp2.hasViewUse(ViewUse.STATISTIC));

      ManagedPropertyImpl mp3 = new ManagedPropertyImpl("runtime-stat");
      mp3.setMetaType(SimpleMetaType.LONG);
      mp3.setValue(SimpleValueSupport.wrap(1000));
      mp3.setViewUse(new ViewUse[]{ViewUse.RUNTIME});
      HashMap<String, Annotation> annotations = new HashMap<String, Annotation>();
      ManagementProperty mpa = getClass().getMethod("testViewUseField", null).getAnnotation(ManagementProperty.class);
      annotations.put(ManagementProperty.class.getName(), mpa);
      mp3.setAnnotations(annotations);
      assertTrue("has ViewUse.RUNTIME", mp3.hasViewUse(ViewUse.RUNTIME));
      assertTrue("has ViewUse.STATISTIC", mp3.hasViewUse(ViewUse.STATISTIC));
   }

   /**
    * Tests of the activationPolicy()
    * @throws Exception
    */
   public void testActivationPolicy()
      throws Exception
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyActivationPolicy.class);
      ManagedProperty defaultProp = managedObject.getProperty("defaultProp");
      assertNotNull(defaultProp);
      assertEquals(ActivationPolicy.IMMEDIATE, defaultProp.getActivationPolicy());
      ManagedProperty compRestartProp = managedObject.getProperty("compRestartProp");
      assertNotNull(compRestartProp);
      assertEquals(ActivationPolicy.COMPONENT_RESTART, compRestartProp.getActivationPolicy());
      ManagedProperty immediateProp = managedObject.getProperty("immediateProp");
      assertNotNull(immediateProp);
      assertEquals(ActivationPolicy.IMMEDIATE, immediateProp.getActivationPolicy());
      ManagedProperty deployRestartProp = managedObject.getProperty("deployRestartProp");
      assertNotNull(deployRestartProp);
      assertEquals(ActivationPolicy.DEPLOYMENT_RESTART, deployRestartProp.getActivationPolicy());
      ManagedProperty serverRestartProp = managedObject.getProperty("serverRestartProp");
      assertNotNull(serverRestartProp);
      assertEquals(ActivationPolicy.SERVER_RESTART, serverRestartProp.getActivationPolicy());
   }

   /**
    * Tests of isModified()/setModified()
    */
   public void testIsModified()
      throws Exception
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyReadOnly.class);
      ManagedProperty readOnly = managedObject.getProperty("readOnly");
      assertNotNull(readOnly);
      assertFalse(readOnly.isModified());
      try
      {
         readOnly.setValue(SimpleValueSupport.wrap("readOnly-update"));
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
      assertFalse(readOnly.isModified());
      // 
      ManagedProperty readWrite = managedObject.getProperty("readWrite");
      assertNotNull(readWrite);
      assertFalse(readWrite.isModified());
      readWrite.setValue(SimpleValueSupport.wrap("readWrite-update"));
      assertTrue("isModified", readWrite.isModified());

      // Validate that clearing/rewriting the same value does not set isModified
      readWrite.setModified(false);
      assertFalse(readWrite.isModified());
      readWrite.setValue(SimpleValueSupport.wrap("readWrite-update"));
      assertFalse(readWrite.isModified());
   }
   
   public void testMasked()
      throws Exception
   {
      ManagedObject managedObject = createAndCheckDefaultManagedObject(ManagementPropertyMasked.class);
      log.info(managedObject.getPropertyNames());
      ManagedProperty masked1 = managedObject.getProperty("masked1");
      assertNotNull(masked1);
      String maskedKey = Masked.class.getName();
      log.info(masked1.getAnnotations().keySet());
      assertTrue(masked1.hasAnnotation(maskedKey));
      Masked masked1Ann = (Masked) masked1.getAnnotations().get(maskedKey);
      assertNotNull(masked1Ann);
      String[] masked1Opts = masked1Ann.options();
      assertEquals(2, masked1Opts.length);
      assertEquals("hashAlgorithm", masked1Opts[0]);
      assertEquals("MD5", masked1Opts[1]);
      
      ManagedProperty masked2 = managedObject.getProperty("masked2");
      assertNotNull(masked2);
      assertTrue(masked2.hasAnnotation(maskedKey));
      Masked masked2Ann = (Masked) masked2.getAnnotations().get(maskedKey);
      assertNotNull(masked2Ann);
   }

   public void testAdminViews()
      throws Exception
   {
      ManagedObject serverBeanMO = createAndCheckDefaultManagedObject(ServerBean.class);
      ManagedObject portBeanMO = createAndCheckDefaultManagedObject(PortAdminViewBean.class);
      log.info("ServerBean: "+serverBeanMO.getPropertyNames());
      Map<String, Set<String>> serverAdminViews = new HashMap<String, Set<String>>();
      for(ManagedProperty mp : serverBeanMO.getProperties().values())
      {
         String name = mp.getName();
         Set<String> views = serverAdminViews.get(name);
         if(views == null)
         {
            views = new HashSet<String>();
            serverAdminViews.put(name, views);
         }
         Collection<String> adminViews = mp.getAdminViewUses();
         log.info(mp+" uses: "+adminViews);
         for(String view : adminViews)
            views.add(view);
      }
      // Validate the expected admin views
      assertEquals("property1", collection("Port"), serverAdminViews.get("property1"));
      assertEquals("property2", collection("Port", "Bootstrap"), serverAdminViews.get("property2"));
      assertEquals("property3", collection("Interface"), serverAdminViews.get("property3"));
      assertEquals("securityDomain", collection("Security"), serverAdminViews.get("securityDomain"));
      log.info("PortAdminViewBean: "+portBeanMO.getPropertyNames());

      Map<String, Set<String>> portViews = new HashMap<String, Set<String>>();
      for(ManagedProperty mp : portBeanMO.getProperties().values())
      {
         String name = mp.getName();
         Set<String> views = portViews.get(name);
         if(views == null)
         {
            views = new HashSet<String>();
            portViews.put(name, views);
         }
         Collection<String> adminViews = mp.getAdminViewUses();
         log.info(mp+" uses: "+adminViews);
         for(String view : adminViews)
            views.add(view);
      }
      assertEquals("listeningInterface", collection("Interface"), portViews.get("listeningInterface"));
      assertEquals("port", collection("Port"), portViews.get("port"));
      assertEquals("bootstrapPort", collection("Port", "Bootstrap"), portViews.get("bootstrapPort"));
   }

   private Collection<String> collection(String... strings)
   {
      HashSet<String> collection = new HashSet<String>();
      for(String s : strings)
         collection.add(s);
      return collection;
   }
}
