// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationChangeListener.java
// public interface ConfigurationChangeListener extends MonitorListener<ConfigurationChangedEvent> {}
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationChangedEvent.java
// @Value
// public class ConfigurationChangedEvent {
//     private final Optional<PluginConfiguration> pluginConfiguration;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationMonitor.java
// public class ConfigurationMonitor implements ChangeMonitorDelegate<ConfigurationChangedEvent, PluginConfiguration> {
// 
//     private final GoAPI goAPI;
//     private ChangeMonitor<ConfigurationChangedEvent, PluginConfiguration> changeMonitor;
// 
//     public ConfigurationMonitor(
//             final GoAPI goAPI
//     ) {
//         this.goAPI = goAPI;
//         this.changeMonitor = new ChangeMonitor<>(this);
//     }
// 
//     public void start() {
//         this.changeMonitor.start();
//     }
// 
//     public void addConfigurationChangeListener(ConfigurationChangeListener listener) {
//         this.changeMonitor.addChangeListener(listener);
//     }
// 
//     @Override
//     public ConfigurationChangedEvent createNotifyEvent(Optional<PluginConfiguration> newMaybeValue, Optional<PluginConfiguration> oldMaybeValue) {
//         return new ConfigurationChangedEvent(newMaybeValue);
//     }
// 
//     @Override
//     public Optional<PluginConfiguration> newValue() {
//         return currentConfiguration();
//     }
// 
//     public Optional<PluginConfiguration> currentConfiguration() {
//         return Optional.of(goAPI.getPluginConfiguration());
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/PluginConfiguration.java
// @Value
// public class PluginConfiguration {
// 
//     public static final String DEFAULT_SOURCE_FILE_PATH = "/etc/go/passwd";
//     private final File principalSourceFile;
// 
//     public PluginConfiguration() {
//         this(DEFAULT_SOURCE_FILE_PATH);
//     }
// 
//     public PluginConfiguration(final String principalSourceFilePath) {
//         this.principalSourceFile = principalSourceFilePath != null ?
//                 new File(principalSourceFilePath) :
//                 new File(DEFAULT_SOURCE_FILE_PATH);
//     }
// 
//     @Override
//     public String toString() {
//         return "PluginConfiguration{" +
//                 "principalSourceFilePath='" + principalSourceFile + '\'' +
//                 '}';
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/InputStreamSource.java
// public interface InputStreamSource {
// 
//     void addChangeListener(SourceChangeListener sourceChangeListener);
// 
//     InputStream inputStream() throws IOException;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/FileChangeMonitor.java
// public class FileChangeMonitor implements InputStreamSource, ChangeMonitorDelegate<SourceChangeEvent, String> {
// 
//     private final File file;
// 
//     private ChangeMonitor<SourceChangeEvent, String> changeMonitor;
// 
//     public FileChangeMonitor(final File file) {
//         this.file = file;
//         this.changeMonitor = new ChangeMonitor<>(this);
//     }
// 
//     public SourceChangeEvent createNotifyEvent(Optional<String> newMaybeValue, Optional<String> oldMaybeValue) {
//         return new SourceChangeEvent(contents(), file.getAbsolutePath());
//     }
// 
//     private InputStream contents() {
//         try {
//             return new FileInputStream(file);
//         } catch (FileNotFoundException e) {
//             return new ByteArrayInputStream(new byte[0]);
//         }
//     }
// 
//     public Optional<String> newValue() {
//         try {
//             return Optional.of(md5Hex(new FileInputStream(file)));
//         } catch (IOException e) {
//             return Optional.absent();
//         }
//     }
// 
//     public void start() {
//         this.changeMonitor.start();
//     }
// 
//     public void stop() {
//         this.changeMonitor.stop();
//     }
// 
//     @Override
//     public void addChangeListener(final SourceChangeListener sourceChangeListener) {
//         this.changeMonitor.addChangeListener(new MonitorListener<SourceChangeEvent>() {
//             @Override
//             public void changed(SourceChangeEvent event) {
//                 sourceChangeListener.sourceChanged(event);
//             }
//         });
//     }
// 
//     @Override
//     public InputStream inputStream() throws IOException {
//         return new FileInputStream(file);
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/SourceChangeListener.java
// public interface SourceChangeListener {
//     void sourceChanged(final SourceChangeEvent event);
// }


import com.google.common.base.Optional;
import com.thoughtworks.go.strongauth.config.ConfigurationChangeListener;
import com.thoughtworks.go.strongauth.config.ConfigurationChangedEvent;
import com.thoughtworks.go.strongauth.config.ConfigurationMonitor;
import com.thoughtworks.go.strongauth.config.PluginConfiguration;
import com.thoughtworks.go.strongauth.util.InputStreamSource;
import com.thoughtworks.go.strongauth.util.io.FileChangeMonitor;
import com.thoughtworks.go.strongauth.util.io.SourceChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
package com.thoughtworks.go.strongauth.authentication.principalDetailSources;



public class ConfigFileMonitor implements InputStreamSource {

    private final ConfigurationMonitor configurationMonitor;
    private Optional<FileChangeMonitor> maybeFileChangeMonitor = Optional.absent();
    private SourceChangeListener sourceChangeListener;

    public ConfigFileMonitor(
            ConfigurationMonitor configurationMonitor

    ) {
        this.configurationMonitor = configurationMonitor;
        this.configurationMonitor.addConfigurationChangeListener(new ConfigurationChangeListener() {
            @Override
            public void changed(ConfigurationChangedEvent event) {
                final Optional<PluginConfiguration> maybePluginConfiguration = event.getPluginConfiguration();
                if (maybePluginConfiguration.isPresent()) {
                    registerMonitor(maybePluginConfiguration.get().getPrincipalSourceFile());
                }
            }
        });
        this.configurationMonitor.start();
    }

    private void registerMonitor(final File file) {
        if (maybeFileChangeMonitor.isPresent()) {
            maybeFileChangeMonitor.get().stop();
        }
        final FileChangeMonitor changeMonitor = new FileChangeMonitor(file);
        this.maybeFileChangeMonitor = Optional.of(changeMonitor);
        changeMonitor.addChangeListener(sourceChangeListener);
        changeMonitor.start();
    }

    @Override
// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationChangeListener.java
// public interface ConfigurationChangeListener extends MonitorListener<ConfigurationChangedEvent> {}
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationChangedEvent.java
// @Value
// public class ConfigurationChangedEvent {
//     private final Optional<PluginConfiguration> pluginConfiguration;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/ConfigurationMonitor.java
// public class ConfigurationMonitor implements ChangeMonitorDelegate<ConfigurationChangedEvent, PluginConfiguration> {
// 
//     private final GoAPI goAPI;
//     private ChangeMonitor<ConfigurationChangedEvent, PluginConfiguration> changeMonitor;
// 
//     public ConfigurationMonitor(
//             final GoAPI goAPI
//     ) {
//         this.goAPI = goAPI;
//         this.changeMonitor = new ChangeMonitor<>(this);
//     }
// 
//     public void start() {
//         this.changeMonitor.start();
//     }
// 
//     public void addConfigurationChangeListener(ConfigurationChangeListener listener) {
//         this.changeMonitor.addChangeListener(listener);
//     }
// 
//     @Override
//     public ConfigurationChangedEvent createNotifyEvent(Optional<PluginConfiguration> newMaybeValue, Optional<PluginConfiguration> oldMaybeValue) {
//         return new ConfigurationChangedEvent(newMaybeValue);
//     }
// 
//     @Override
//     public Optional<PluginConfiguration> newValue() {
//         return currentConfiguration();
//     }
// 
//     public Optional<PluginConfiguration> currentConfiguration() {
//         return Optional.of(goAPI.getPluginConfiguration());
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/config/PluginConfiguration.java
// @Value
// public class PluginConfiguration {
// 
//     public static final String DEFAULT_SOURCE_FILE_PATH = "/etc/go/passwd";
//     private final File principalSourceFile;
// 
//     public PluginConfiguration() {
//         this(DEFAULT_SOURCE_FILE_PATH);
//     }
// 
//     public PluginConfiguration(final String principalSourceFilePath) {
//         this.principalSourceFile = principalSourceFilePath != null ?
//                 new File(principalSourceFilePath) :
//                 new File(DEFAULT_SOURCE_FILE_PATH);
//     }
// 
//     @Override
//     public String toString() {
//         return "PluginConfiguration{" +
//                 "principalSourceFilePath='" + principalSourceFile + '\'' +
//                 '}';
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/InputStreamSource.java
// public interface InputStreamSource {
// 
//     void addChangeListener(SourceChangeListener sourceChangeListener);
// 
//     InputStream inputStream() throws IOException;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/FileChangeMonitor.java
// public class FileChangeMonitor implements InputStreamSource, ChangeMonitorDelegate<SourceChangeEvent, String> {
// 
//     private final File file;
// 
//     private ChangeMonitor<SourceChangeEvent, String> changeMonitor;
// 
//     public FileChangeMonitor(final File file) {
//         this.file = file;
//         this.changeMonitor = new ChangeMonitor<>(this);
//     }
// 
//     public SourceChangeEvent createNotifyEvent(Optional<String> newMaybeValue, Optional<String> oldMaybeValue) {
//         return new SourceChangeEvent(contents(), file.getAbsolutePath());
//     }
// 
//     private InputStream contents() {
//         try {
//             return new FileInputStream(file);
//         } catch (FileNotFoundException e) {
//             return new ByteArrayInputStream(new byte[0]);
//         }
//     }
// 
//     public Optional<String> newValue() {
//         try {
//             return Optional.of(md5Hex(new FileInputStream(file)));
//         } catch (IOException e) {
//             return Optional.absent();
//         }
//     }
// 
//     public void start() {
//         this.changeMonitor.start();
//     }
// 
//     public void stop() {
//         this.changeMonitor.stop();
//     }
// 
//     @Override
//     public void addChangeListener(final SourceChangeListener sourceChangeListener) {
//         this.changeMonitor.addChangeListener(new MonitorListener<SourceChangeEvent>() {
//             @Override
//             public void changed(SourceChangeEvent event) {
//                 sourceChangeListener.sourceChanged(event);
//             }
//         });
//     }
// 
//     @Override
//     public InputStream inputStream() throws IOException {
//         return new FileInputStream(file);
//     }
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/SourceChangeListener.java
// public interface SourceChangeListener {
//     void sourceChanged(final SourceChangeEvent event);
// }


// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/principalDetailSources/ConfigFileMonitor.java
import com.google.common.base.Optional;
import com.thoughtworks.go.strongauth.config.ConfigurationChangeListener;
import com.thoughtworks.go.strongauth.config.ConfigurationChangedEvent;
import com.thoughtworks.go.strongauth.config.ConfigurationMonitor;
import com.thoughtworks.go.strongauth.config.PluginConfiguration;
import com.thoughtworks.go.strongauth.util.InputStreamSource;
import com.thoughtworks.go.strongauth.util.io.FileChangeMonitor;
import com.thoughtworks.go.strongauth.util.io.SourceChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

package com.thoughtworks.go.strongauth.authentication.principalDetailSources;



public class ConfigFileMonitor implements InputStreamSource {

    private final ConfigurationMonitor configurationMonitor;
    private Optional<FileChangeMonitor> maybeFileChangeMonitor = Optional.absent();
    private SourceChangeListener sourceChangeListener;

    public ConfigFileMonitor(
            ConfigurationMonitor configurationMonitor

    ) {
        this.configurationMonitor = configurationMonitor;
        this.configurationMonitor.addConfigurationChangeListener(new ConfigurationChangeListener() {
            @Override
            public void changed(ConfigurationChangedEvent event) {
                final Optional<PluginConfiguration> maybePluginConfiguration = event.getPluginConfiguration();
                if (maybePluginConfiguration.isPresent()) {
                    registerMonitor(maybePluginConfiguration.get().getPrincipalSourceFile());
                }
            }
        });
        this.configurationMonitor.start();
    }

    private void registerMonitor(final File file) {
        if (maybeFileChangeMonitor.isPresent()) {
            maybeFileChangeMonitor.get().stop();
        }
        final FileChangeMonitor changeMonitor = new FileChangeMonitor(file);
        this.maybeFileChangeMonitor = Optional.of(changeMonitor);
        changeMonitor.addChangeListener(sourceChangeListener);
        changeMonitor.start();
    }

    @Override
    public void addChangeListener(SourceChangeListener sourceChangeListener) {