package brooklyn.location.basic;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;

import org.jclouds.rest.Providers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.config.BrooklynProperties;
import brooklyn.location.LocationResolver;
import brooklyn.location.basic.jclouds.CredentialsFromEnv;
import brooklyn.location.basic.jclouds.JcloudsLocation;
import brooklyn.location.basic.jclouds.JcloudsLocationFactory;

import com.google.common.collect.Lists;

public class JcloudsResolver implements LocationResolver {

    public static final Logger log = LoggerFactory.getLogger(JcloudsResolver.class);
    
    public static final String JCLOUDS = "jclouds";
    
    public static final Collection<String> PROVIDERS = Lists.newArrayList(Providers.getSupportedProviders());
    public static final Collection<String> AWS_REGIONS = Arrays.asList(
            // from http://docs.amazonwebservices.com/general/latest/gr/rande.html as of Apr 2012.
            // it is suggested not to maintain this list here, instead to require aws-ec2 explicitly named.
            "eu-west-1","us-east-1","us-west-1","us-west-2","ap-southeast-1","ap-northeast-1","sa-east-1");
         
    public static JcloudsLocation resolve(String spec) {
        return (JcloudsLocation) new LocationRegistry().resolve(JCLOUDS+":"+spec);
    }
    
    public JcloudsLocation newLocationFromString(String spec) {
        return newLocationFromString(new LinkedHashMap(), spec);
    }
    
    @Override
    public JcloudsLocation newLocationFromString(Map properties, String spec) {
        String provider=spec, region=null;
        int split = spec.indexOf(':');
        if (split<0) {
            if (spec.equalsIgnoreCase(getPrefix()))
                throw new IllegalArgumentException("Cannot use '"+spec+"' as a location ID; it is insufficient. "+
                       "Try jclouds:aws-ec2 (for example).");
        } else {
            provider = spec.substring(0, split);
            region = spec.substring(split+1);
            while (provider.equalsIgnoreCase(JCLOUDS)) {
                //strip any number of jclouds: prefixes, for use by static "resolve" method
                provider = region;
                region = null;
                split = provider.indexOf(':');
                if (split>=0) {
                    region = provider.substring(split+1);
                    provider = provider.substring(0, split);
                }
            }
        }
        
        if (region==null && AWS_REGIONS.contains(provider)) {
            // treat amazon as a default
            region = provider;
            provider = "aws-ec2";
            log.warn("Use of deprecated location '"+region+"'; in future refer to with explicit provider '"+provider+":"+region+"'");
        }
        
        if (!PROVIDERS.contains(provider)) {
            log.warn("Unknown jclouds provider '"+provider+"' (will throw); known providers are: "+PROVIDERS);
            throw new NoSuchElementException("Unknown location '"+spec+"'");
        }
        
        return new JcloudsLocationFactory(
                new CredentialsFromEnv(BrooklynProperties.Factory.newEmpty().addFromMap(properties), provider).asMap()).
                newLocation(region);
    }
    
    @Override
    public String getPrefix() {
        return JCLOUDS;
    }
    
}

@@ -200,12 +200,47 @@
 uds.
-rest
+Constants;%0Aimport org.jclouds.providers
 .Pro
@@ -244,17 +244,24 @@
 Provider
-s
+Metadata
 ;%0Aimport
@@ -568,32 +568,149 @@
 ocationFactory;%0A
+import brooklyn.util.MutableMap;%0A%0Aimport com.google.common.base.Function;%0Aimport com.google.common.collect.Iterables;
 %0Aimport com.goog
@@ -994,16 +994,23 @@
 ROVIDERS
+_LOADER
  = Lists
@@ -1023,16 +1023,318 @@
 rayList(
+Iterables.transform(org.jclouds.providers.Providers.all(), new Function%3CProviderMetadata,String%3E() %7B%0A        @Override%0A        public String apply(ProviderMetadata input) %7B return input.getId(); %7D%0A    %7D));%0A    public static final Collection%3CString%3E PROVIDERS_REST = Lists.newArrayList(org.jclouds.rest.
 Provider
@@ -1357,24 +1357,29 @@
 oviders());%0A
+    %0A
     public s
@@ -3401,16 +3401,21 @@
 ROVIDERS
+_REST
 .contain
@@ -3537,16 +3537,21 @@
 ROVIDERS
+_REST
 );%0A     
@@ -3628,32 +3628,24 @@
 ;%0A        %7D%0A
-        
 %0A        ret
@@ -3645,59 +3645,47 @@
     
-return new JcloudsLocationFactory(%0A                
+Map jcloudsProperties = new MutableMap(
 new 
@@ -3787,46 +3787,594 @@
 p())
-.%0A                newLocation(region);
+;%0A        if (PROVIDERS_LOADER.contains(provider)) %7B%0A            // providers from ServiceLoader take a location (endpoint already configured)%0A            return new JcloudsLocationFactory(jcloudsProperties).newLocation(region);%0A        %7D else %7B%0A            // other %22providers%22 are APIs (jclouds 1.4 way of detecting, there's an Apis class is 1.5)%0A            // and so take an _endpoint_ (but not a location)%0A            jcloudsProperties.put(Constants.PROPERTY_ENDPOINT, region);%0A            return new JcloudsLocationFactory(jcloudsProperties).newLocation(null);          %0A        %7D
 %0A   

support API providers with parameter as the endpoint