/*
 * Copyright 2012 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Eclipse Public License version 1.0, available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.jboss.forge.addon.resource;

import java.util.TreeMap;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.jboss.forge.addon.resource.monitor.FileMonitor;
import org.jboss.forge.addon.resource.monitor.ResourceMonitor;
import org.jboss.forge.addon.resource.transaction.ResourceTransactionListener;
import org.jboss.forge.addon.resource.transaction.file.FileResourceTransactionImpl;
import org.jboss.forge.addon.resource.transaction.file.FileResourceTransactionManager;
import org.jboss.forge.addon.resource.util.RelatedClassComparator;
import org.jboss.forge.furnace.addons.AddonRegistry;
import org.jboss.forge.furnace.services.Imported;
import org.jboss.forge.furnace.spi.ListenerRegistration;
import org.jboss.forge.furnace.util.Assert;

/**
 * Implementation of {@link ResourceFactory}
 * 
 * @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a>
 * @author Mike Brock <cbrock@redhat.com>
 * @author <a href="ggastald@redhat.com">George Gastaldi</a>
 */
@Singleton
public class ResourceFactoryImpl implements ResourceFactory
{
   @Inject
   private AddonRegistry registry;

   @Inject
   private FileMonitor fileMonitor;

   @Inject
   private FileResourceTransactionManager transactionManager;

   @Override
   @SuppressWarnings({ "unchecked", "rawtypes" })
   public <E, T extends Resource<E>> T create(final Class<T> type, final E underlyingResource)
   {
      T result = null;
      synchronized (this)
      {
         TreeMap<Class<?>, ResourceGenerator> generated = new TreeMap<>(
                  new RelatedClassComparator());

         Imported<ResourceGenerator> instances = registry.getServices(ResourceGenerator.class);

         for (ResourceGenerator generator : instances)
         {
            if (generator.handles(type, underlyingResource))
            {
               Class resourceType = generator.getResourceType(this, type, underlyingResource);
               if (type.isAssignableFrom(resourceType))
               {
                  generated.put(resourceType, generator);
               }
            }
            instances.release(generator);
         }
         if (generated.size() > 0)
         {
            result = (T) generated.lastEntry().getValue().getResource(this, type, underlyingResource);
         }
      }
      return result;
   }

   @Override
   @SuppressWarnings("unchecked")
   public <E> Resource<E> create(E underlyingResource)
   {
      return create(Resource.class, underlyingResource);
   }

   @Override
   public ResourceMonitor monitor(Resource<?> resource)
   {
      return monitor(resource, null);
   }

   @Override
   public ResourceMonitor monitor(Resource<?> resource, ResourceFilter resourceFilter)
   {
      Assert.notNull(resource, "Resource cannot be null");
      Assert.isTrue(resource instanceof FileResource, "Resource must be a FileResource, was "
               + resource.getClass().getName());
      if (!resource.exists())
      {
         throw new IllegalStateException("Resource must exist to be monitored");
      }
      FileResource<?> fileResource = (FileResource<?>) resource;
      return fileMonitor.registerMonitor(this, fileResource, resourceFilter);
   }

   @Override
   public FileResourceTransactionImpl getTransaction()
   {
      return transactionManager.getCurrentTransaction(this);
   }

   @Override
   public FileOperations getFileOperations()
   {
      FileResourceTransactionImpl transaction = getTransaction();
      if (transaction.isStarted())
      {
         return transaction;
      }
      else
      {
         return DefaultFileOperations.INSTANCE;
      }
   }

   @Override
   public ListenerRegistration<ResourceTransactionListener> addTransactionListener(ResourceTransactionListener listener)
   {
      return transactionManager.addTransactionListener(listener);
   }
}
@@ -215,16 +215,64 @@
 ource;%0A%0A
+import java.util.HashSet;%0Aimport java.util.Set;%0A
 import j
@@ -289,16 +289,16 @@
 reeMap;%0A
-
 %0Aimport 
@@ -846,58 +846,8 @@
 ry;%0A
-import org.jboss.forge.furnace.services.Imported;%0A
 impo
@@ -1423,24 +1423,158 @@
 onManager;%0A%0A
+   @SuppressWarnings(%22rawtypes%22)%0A   private final Set%3CResourceGenerator%3E generators = new HashSet%3C%3E();%0A   private long version = -1;%0A%0A
    @Override
@@ -1917,17 +1917,13 @@
     
-Imported%3C
+for (
 Reso
@@ -1939,123 +1939,36 @@
 ator
-%3E instances = registry.getServices(ResourceGenerator.class);%0A%0A         for (ResourceGenerator generator : instances
+ generator : getGenerators()
 )%0A  
@@ -2312,50 +2312,8 @@
   %7D%0A
-            instances.release(generator);%0A
     
@@ -2483,24 +2483,24 @@
   %7D%0A      %7D%0A
-
       return
@@ -2506,32 +2506,439 @@
 n result;%0A   %7D%0A%0A
+   @SuppressWarnings(%22rawtypes%22)%0A   private Iterable%3CResourceGenerator%3E getGenerators()%0A   %7B%0A      if (registry.getVersion() != version)%0A      %7B%0A         version = registry.getVersion();%0A         generators.clear();%0A         for (ResourceGenerator generator : registry.getServices(ResourceGenerator.class))%0A         %7B%0A            generators.add(generator);%0A         %7D%0A      %7D%0A      return generators;%0A   %7D%0A%0A
    @Override%0A   

Improve performance of ResourceFactory by caching generators directly.