package brooklyn.location.basic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.config.BrooklynProperties;
import brooklyn.location.Location;
import brooklyn.location.LocationResolver;

public class LocationRegistry {

    public static final Logger log = LoggerFactory.getLogger(LocationRegistry.class);
    
    private final Map properties;
    
    public LocationRegistry() {
        this(BrooklynProperties.Factory.newDefault());
    }
    public LocationRegistry(Map properties) {
        this.properties = properties;
        findServices();
    }
    
    protected Map<String,LocationResolver> resolvers = new LinkedHashMap<String, LocationResolver>();
    
    protected void findServices() {
        ServiceLoader<LocationResolver> loader = ServiceLoader.load(LocationResolver.class);
        for (LocationResolver r: loader)
            resolvers.put(r.getPrefix(), r);
    }

    public Location resolve(String spec) {
        int colon = spec.indexOf(':');
        String prefix = colon>=0 ? spec.substring(0, colon) : spec;
        LocationResolver resolver = resolvers.get(prefix);
        
        if (resolver==null) {
            //default to jclouds; could do a lookup to ensure provider supported by jclouds
            resolver = resolvers.get("jclouds");
        }
        
        if (resolver!=null) {
            return resolver.newLocationFromString(properties, spec);
        }
        
        throw new NoSuchElementException("No resolver found for '"+prefix+"' when trying to find location "+spec);
    }
    
    /** Expects a collection of strings being the spec for locations, returns a list of locations.
     * For legacy compatibility this also accepts nested lists, but that is deprecated
     * (and triggers a warning).
     */
    public List<Location> getLocationsById(Collection<String> ids) {
        List<Location> result = new ArrayList<Location>();
        for (Object id: ids) {
            if (id instanceof String) result.add(resolve((String)id));
            else if (id instanceof Collection) {
                log.warn("LocationRegistry got list of list of location strings, "+ids+"; flattening");
                result.addAll(getLocationsById((Collection)id));
            } else if (id instanceof Location) result.add((Location)id);
            else {
                throw new IllegalArgumentException("Cannot resolve '"+id+"' to a location; unsupported type "+
                        (id==null ? "null" : ""+id.getClass()));
            }
        }
        return result;
    }
    
}

@@ -1357,18 +1357,20 @@
 resolver
+ 
 ==
+ 
 null) %7B%0A
@@ -1553,10 +1553,12 @@
 lver
+ 
 !=
+ 
 null
@@ -1782,16 +1782,23 @@
 %0A    /**
+%0A     *
  Expects
@@ -2056,25 +2056,18 @@
 yId(
-Collection%3CString
+Iterable%3C?
 %3E id
@@ -2152,16 +2152,17 @@
 bject id
+ 
 : ids) %7B
@@ -2199,16 +2199,34 @@
  String)
+ %7B%0A               
  result.
@@ -2245,16 +2245,17 @@
 (String)
+ 
 id));%0A  
@@ -2259,24 +2259,26 @@
 %0A           
+ %7D
  else if (id
@@ -2289,26 +2289,24 @@
 tanceof 
-Collection
+Iterable
 ) %7B%0A    
@@ -2457,19 +2457,21 @@
 Id((
-Collection)
+Iterable%3C?%3E) 
 id))
@@ -2518,16 +2518,34 @@
 ocation)
+ %7B%0A               
  result.
@@ -2558,16 +2558,17 @@
 ocation)
+ 
 id);%0A   
@@ -2575,16 +2575,18 @@
         
+ %7D
  else %7B%0A
@@ -2723,18 +2723,20 @@
      (id
+ 
 ==
+ 
 null ? %22
@@ -2747,11 +2747,8 @@
 %22 : 
-%22%22+
 id.g
@@ -2756,19 +2756,30 @@
 tClass()
+.getName()
 ));
+ 
 %0A       

Tidy up Location Registry so that getLocationById() will take an Iterable instead of a Collection.