package org.torquebox.mojo.mavengem;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.NoSuchFileException;

import org.sonatype.nexus.ruby.GemArtifactFile;
import org.sonatype.nexus.ruby.RubygemsFile;

public class MavenGemURLConnection extends URLConnection {

    public static final String MAVEN_RELEASES = "/maven/releases";
    public static final String PING = MAVEN_RELEASES + "/ping";

    private static final RubygemsFactory NO_RUBYGEMS_FACTORY = null;

    private final Proxy proxy;

    private InputStream in;
    private long timestamp = -1;

    // package private for testing
    final URL baseurl;
    final String path;
    final RubygemsFactory factory;

    public static MavenGemURLConnection create(String uri) throws MalformedURLException {
        return create(NO_RUBYGEMS_FACTORY, uri, Proxy.NO_PROXY);
    }

    public static MavenGemURLConnection create(String uri, Proxy proxy) throws MalformedURLException {
        return create(NO_RUBYGEMS_FACTORY, uri, proxy);
    }

    public static MavenGemURLConnection create(RubygemsFactory factory, String uri)
        throws MalformedURLException {
        return create(factory, uri, Proxy.NO_PROXY);
    }

    public static MavenGemURLConnection create(RubygemsFactory factory, String uri, Proxy proxy)
	     throws MalformedURLException {
	int index = uri.indexOf(MAVEN_RELEASES);
        String path = uri.substring(index);
        String baseurl = uri.substring(0, index);
	return new MavenGemURLConnection(factory, new URL(baseurl), path, proxy);
    }

    public MavenGemURLConnection(URL baseurl, String path)
        throws MalformedURLException {
        this(NO_RUBYGEMS_FACTORY, baseurl, path, Proxy.NO_PROXY);
    }

    public MavenGemURLConnection(URL baseurl, String path, Proxy proxy)
        throws MalformedURLException {
        this(NO_RUBYGEMS_FACTORY, baseurl, path, proxy);
    }

    public MavenGemURLConnection(RubygemsFactory factory, URL baseurl, String path)
        throws MalformedURLException {
        this(factory, baseurl, path, Proxy.NO_PROXY);
    }

    public MavenGemURLConnection(RubygemsFactory factory, URL baseurl, String path, Proxy proxy)
	    throws MalformedURLException {
        super(baseurl);
        this.proxy = proxy == null ? Proxy.NO_PROXY : proxy;
	this.factory = factory == null ? RubygemsFactory.defaultFactory() : factory;
        this.baseurl = baseurl;
        this.path = path.startsWith(MAVEN_RELEASES) ? path : MAVEN_RELEASES + path;
    }

    @Override
    synchronized public InputStream getInputStream() throws IOException {
        if (in == null) {
            connect();
        }
        return in;
    }

    synchronized public long getModified() throws IOException {
        if (timestamp == -1) {
            connect();
        }
        return timestamp;
    }

    private int counter = 12; // seconds
    @Override
    synchronized public void connect() throws IOException {
        connect(factory.getOrCreate(baseurl));
    }

    private void connect(Rubygems facade) throws IOException {
        RubygemsFile file = facade.get(path);
        switch( file.state() )
        {
        case FORBIDDEN:
            throw new IOException("forbidden: " + file + " on " + baseurl);
        case NOT_EXISTS:
            if (path.equals(PING)) {
                in = new ByteArrayInputStream("pong".getBytes());
                break;
            }
	    throw new FileNotFoundException(file.toString() + " on " + baseurl);
        case NO_PAYLOAD:
            switch( file.type() )
            {
            case GEM_ARTIFACT:
                // we can pass in null as dependenciesData since we have already the gem
                in = openInputStream(baseurl + "/gems/" + ((GemArtifactFile) file ).gem( null ).filename() + ".gem");
            case GEM:
		// TODO timestamp
                in = openInputStream(baseurl + "/" +  file.remotePath());
            default:
                throw new FileNotFoundException("view - not implemented. " + file + " on " + baseurl);
            }
        case ERROR:
	    if (file.getException() instanceof NoSuchFileException) {
		throw new FileNotFoundException(file.toString() + " on " + baseurl);
	    }
	    throw new IOException(file.toString() + " on " + baseurl, file.getException());
        case TEMP_UNAVAILABLE:
            try {
                Thread.sleep(1000);
            }
            catch(InterruptedException ignore) {
            }
            if (--counter > 0) {
                connect(facade);
            }
            break;
        case PAYLOAD:
            in = facade.getInputStream(file);
	    timestamp = facade.getModified(file);
            break;
        case NEW_INSTANCE:
        default:
            throw new RuntimeException("BUG: should never reach here. " + file + " on " + baseurl);
        }
    }

    private InputStream openInputStream(final String uri) throws IOException {
        if (proxy == Proxy.NO_PROXY) {
            return new URL(uri).openStream();
        }
        System.err.println(proxy);
        return new URL(uri).openConnection(proxy).getInputStream();
    }
}


@@ -769,16 +769,58 @@
  = -1;%0A%0A
+    private int counter = 12; // seconds%0A%0A
     // p
@@ -2909,24 +2909,38 @@
  in;%0A    %7D%0A%0A
+    @Override%0A
     synchron
@@ -2959,16 +2959,20 @@
 long get
+Last
 Modified
@@ -2973,35 +2973,16 @@
 dified()
- throws IOException
  %7B%0A     
@@ -3015,34 +3015,146 @@
             
-connect();
+try %7B%0A                connect();%0A            %7D%0A            catch (IOException e) %7B%0A                // ignore%0A            %7D
 %0A        %7D%0A 
@@ -3189,49 +3189,8 @@
  %7D%0A%0A
-    private int counter = 12; // seconds%0A
     

rename getModified to getLastModified to be part of the public interface