/**
 * Copyright (C) FuseSource, Inc.
 * http://fusesource.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fusesource.fabric.fab.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashSet;

/**
 */
public class Files {

    
    private static class DownloadKey {
        private final URL url;
        private final String tempFilePrefix;
        private final String tempFilePostfix;

        DownloadKey(URL url, String tempFilePrefix, String tempFilePostfix) {
            this.url = url;
            this.tempFilePrefix = tempFilePrefix;
            this.tempFilePostfix = tempFilePostfix;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            DownloadKey that = (DownloadKey) o;

            if (tempFilePostfix != null ? !tempFilePostfix.equals(that.tempFilePostfix) : that.tempFilePostfix != null)
                return false;
            if (tempFilePrefix != null ? !tempFilePrefix.equals(that.tempFilePrefix) : that.tempFilePrefix != null)
                return false;
            if (url != null ? !url.equals(that.url) : that.url != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = url != null ? url.hashCode() : 0;
            result = 31 * result + (tempFilePrefix != null ? tempFilePrefix.hashCode() : 0);
            result = 31 * result + (tempFilePostfix != null ? tempFilePostfix.hashCode() : 0);
            return result;
        }
    }
    
    private static final ThreadLocal<HashSet<DownloadKey>> ACTIVE_DOWNLOADS = new ThreadLocal<HashSet<DownloadKey>>();



    public static File urlToFile(String url, String tempFilePrefix, String tempFilePostfix) throws IOException {
        File file = new File(url);
        if (file.exists()) {
            return file;
        } else {
            return urlToFile(new URL(url), tempFilePrefix, tempFilePostfix);
        }
    }

    /**
     * Attempts to convert a URL to a file or copies the URL to a temporary file if it can't be easily converted
     */
    public static File urlToFile(URL url, String tempFilePrefix, String tempFilePostfix) throws IOException {
        HashSet<DownloadKey> original = ACTIVE_DOWNLOADS.get();
        HashSet<DownloadKey> downloads = original;
        if( downloads ==null ) {
            downloads = new HashSet<DownloadKey>();
            ACTIVE_DOWNLOADS.set(downloads);
        }
        try {
            DownloadKey key = new DownloadKey(url, tempFilePrefix, tempFilePostfix);
            if(downloads.contains(key)) {
                throw new IOException("The URL is being recursively downloaded: "+url);
            }
            downloads.add(key);
            try {
                String fileName = url.getFile();
                File file = new File(fileName);
                if (!file.exists()) {
                    // we need to copy the URL to a new temp file for now...
                    file = File.createTempFile(tempFilePrefix, tempFilePostfix);
                    InputStream in = url.openStream();
                    IOHelpers.writeTo(file, in);
                }
                return file;
            } finally {
                downloads.remove(key);
            }
        } finally {
            if(original==null) {
                ACTIVE_DOWNLOADS.remove();
            }
        }

    }
}

@@ -773,16 +773,22 @@
 va.util.
+Linked
 HashSet;
@@ -847,1411 +847,43 @@
 tic 
-class DownloadKey %7B%0A        private final URL url;%0A        private final String tempFilePrefix;%0A        private final String tempFilePostfix;%0A%0A        DownloadKey(URL url, String tempFilePrefix, String tempFilePostfix) %7B%0A            this.url = url;%0A            this.tempFilePrefix = tempFilePrefix;%0A            this.tempFilePostfix = tempFilePostfix;%0A        %7D%0A%0A        @Override%0A        public boolean equals(Object o) %7B%0A            if (this == o) return true;%0A            if (o == null %7C%7C getClass() != o.getClass()) return false;%0A%0A            DownloadKey that = (DownloadKey) o;%0A%0A            if (tempFilePostfix != null ? !tempFilePostfix.equals(that.tempFilePostfix) : that.tempFilePostfix != null)%0A                return false;%0A            if (tempFilePrefix != null ? !tempFilePrefix.equals(that.tempFilePrefix) : that.tempFilePrefix != null)%0A                return false;%0A            if (url != null ? !url.equals(that.url) : that.url != null) return false;%0A%0A            return true;%0A        %7D%0A%0A        @Override%0A        public int hashCode() %7B%0A            int result = url != null ? url.hashCode() : 0;%0A            result = 31 * result + (tempFilePrefix != null ? tempFilePrefix.hashCode() : 0);%0A            result = 31 * result + (tempFilePostfix != null ? tempFilePostfix.hashCode() : 0);%0A            return result;%0A        %7D%0A    %7D%0A    %0A    private static final ThreadLocal%3CHashSet%3CDownloadKey
+final ThreadLocal%3CLinkedHashSet%3CURL
 %3E%3E A
@@ -916,24 +916,30 @@
 adLocal%3C
+Linked
 HashSet%3C
 Download
@@ -934,28 +934,18 @@
 Set%3C
-DownloadKey
+URL
 %3E%3E();%0A%0A
-%0A%0A
     
@@ -1496,32 +1496,38 @@
 n %7B%0A        
+Linked
 HashSet%3C
 DownloadKey%3E
@@ -1514,27 +1514,19 @@
 HashSet%3C
-DownloadKey
+URL
 %3E origin
@@ -1562,24 +1562,30 @@
         
+Linked
 HashSet%3C
 Download
@@ -1576,27 +1576,19 @@
 HashSet%3C
-DownloadKey
+URL
 %3E downlo
@@ -1664,24 +1664,30 @@
 s = new 
+Linked
 HashSet%3C
 Download
@@ -1678,27 +1678,19 @@
 HashSet%3C
-DownloadKey
+URL
 %3E();%0A   
@@ -1759,93 +1759,8 @@
 y %7B%0A
-            DownloadKey key = new DownloadKey(url, tempFilePrefix, tempFilePostfix);%0A
     
@@ -1789,19 +1789,19 @@
 ontains(
-key
+url
 )) %7B%0A   
@@ -1840,102 +1840,60 @@
 on(%22
-The URL is being recursively downloaded: %22+url);%0A            %7D%0A            downloads.add(key);
+Download cycle detected: %22+downloads);%0A            %7D
 %0A   
@@ -2412,11 +2412,11 @@
 ove(
-key
+url
 );%0A 

Simplify and add more diagnostics to the error message.