package org.togglz.core.repository.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.togglz.core.logging.Log;
import org.togglz.core.logging.LogFactory;
import org.togglz.core.util.IOUtils;

/**
 * Please note that this class is NOT thread-safe.
 */
class ReloadablePropertiesFile {

    private final Log log = LogFactory.getLog(ReloadablePropertiesFile.class);

    private final File file;

    private final int minCheckInterval;

    private Properties values = new Properties();

    private long lastRead = 0;

    private long lastCheck = 0;

    public ReloadablePropertiesFile(File file) {
        this(file, 1000);
    }

    public ReloadablePropertiesFile(File file, int minCheckInterval) {
        this.file = file;
        this.minCheckInterval = minCheckInterval;
    }

    public synchronized void reloadIfUpdated() {

        long now = System.currentTimeMillis();
        if (now - lastCheck > minCheckInterval) {

            lastCheck = now;

            if (file.lastModified() > lastRead) {

                FileInputStream stream = null;

                try {

                    // read new values
                    stream = new FileInputStream(file);
                    Properties newValues = new Properties();
                    newValues.load(stream);

                    // update state
                    values = newValues;
                    lastRead = System.currentTimeMillis();

                    log.info("Reloaded file: " + file.getCanonicalPath());

                } catch (FileNotFoundException e) {
                    log.debug("File not found: " + file);
                } catch (IOException e) {
                    log.error("Failed to read file", e);
                } finally {
                    IOUtils.close(stream);
                }

            }
        }

    }

    public String getValue(String key, String defaultValue) {
        return values.getProperty(key, defaultValue);
    }

    public Set<String> getKeysStartingWith(String prefix) {

        Set<String> result = new HashSet<String>();

        Enumeration<?> keys = values.propertyNames();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement().toString();
            if (key.startsWith(prefix)) {
                result.add(key);
            }
        }

        return result;

    }

    public Editor getEditor() {
        return new Editor(values);
    }

    private void write(Properties newValues) {

        try {

            FileOutputStream fos = new FileOutputStream(file);
            newValues.store(fos, null);
            fos.flush();
            fos.close();

        } catch (IOException e) {
            log.error("Failed to persist feature state", e);
            throw new IllegalStateException("Failed to persist feature state", e);
        }
        lastRead = 0;
        lastCheck = 0;

    }

    public class Editor {

        private Properties newValues;

        private Editor(Properties props) {
            newValues = new Properties();
            newValues.putAll(props);
        }

        public void setValue(String key, String value) {
            if (value != null) {
                newValues.setProperty(key, value);
            }
            else {
                newValues.remove(key);
            }
        }

        public void removeKeysStartingWith(String prefix) {
            Iterator<Entry<Object, Object>> iterator = newValues.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<Object, Object> entry = iterator.next();
                if (entry.getKey().toString().startsWith(prefix)) {
                    iterator.remove();
                }
            }
        }

        public void commit() {
            write(newValues);
        }

    }

}

@@ -2955,69 +2955,8 @@
 ) %7B%0A
-            log.error(%22Failed to persist feature state%22, e);%0A
     
@@ -3010,29 +3010,24 @@
  to 
-persist feature state
+write new values
 %22, e

Revert "Log failures when persisting new feature state using the FileBasedStateRepository (fixes #87)"