/*
 * Copyright (c) 2012-2014, Luigi R. Viggiano
 * All rights reserved.
 *
 * This software is distributable under the BSD license.
 * See the terms of the BSD license in the documentation provided with this software.
 */

package org.aeonbits.owner;

import org.aeonbits.owner.Config.HotReload;
import org.aeonbits.owner.Config.HotReloadType;

import java.io.File;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import static org.aeonbits.owner.Config.HotReloadType.ASYNC;
import static org.aeonbits.owner.Config.HotReloadType.SYNC;
import static org.aeonbits.owner.Util.fileFromURI;
import static org.aeonbits.owner.Util.now;

/**
 * @author Luigi R. Viggiano
 */
class HotReloadLogic implements Serializable {

    private final PropertiesManager manager;
    private final long interval;
    private final HotReloadType type;
    private volatile long lastCheckTime = now();
    private final List<WatchableFile> watchableFiles = new ArrayList<WatchableFile>();

    private static class WatchableFile implements Serializable {
        private final File file;
        private long lastModifiedTime;

        WatchableFile(File file) {
            this.file = file;
            this.lastModifiedTime = file.lastModified();
        }

        public boolean isChanged() {
            long lastModifiedTimeNow = file.lastModified();
            boolean changed = lastModifiedTime != lastModifiedTimeNow;
            if (changed)
                lastModifiedTime = lastModifiedTimeNow;
            return changed;
        }
    }

    public HotReloadLogic(HotReload hotReload, List<URI> uris, PropertiesManager manager) {
        this.manager = manager;
        type = hotReload.type();
        interval = hotReload.unit().toMillis(hotReload.value());
        setupWatchableResources(uris);
    }

    private void setupWatchableResources(List<URI> uris) {
        for (URI uri : uris) {
            File file = fileFromURI(uri);
            if (file != null)
                watchableFiles.add(new WatchableFile(file));
        }
    }

    synchronized void checkAndReload() {
        if (needsReload())
            manager.reload();
    }

    private boolean needsReload() {
        if (manager.isLoading()) return false;

        long now = now();
        if (now < lastCheckTime + interval)
            return false;

        try {
            for (WatchableFile resource : watchableFiles)
                if (resource.isChanged())
                    return true;
            return false;
        } finally {
            lastCheckTime = now;
        }
    }

    boolean isAsync() {
        return type == ASYNC;
    }

    boolean isSync() {
        return type == SYNC;
    }

}

@@ -457,17 +457,71 @@
 .util.Li
-s
+nkedHashSet;%0Aimport java.util.List;%0Aimport java.util.Se
 t;%0A%0Aimpo
@@ -1954,32 +1954,85 @@
 st%3CURI%3E uris) %7B%0A
+        Set%3CFile%3E files = new LinkedHashSet%3CFile%3E();%0A
         for (URI
@@ -2118,24 +2118,95 @@
 = null)%0A    
+            files.add(file);%0A        %7D%0A        for (File file : files)%0A
             
@@ -2250,26 +2250,16 @@
 file));%0A
-        %7D%0A
     %7D%0A%0A 

improved file changes watch