/*
 * Copyright 2017 The RoboZonky Project
 *
 * 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 com.github.robozonky.notifications.email;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;

import com.github.robozonky.internal.api.Defaults;
import com.github.robozonky.internal.api.Settings;
import com.github.robozonky.util.Refreshable;
import com.github.robozonky.util.Scheduler;

public class RefreshableNotificationProperties extends Refreshable<NotificationProperties> {

    public static final String CONFIG_FILE_LOCATION_PROPERTY = "robozonky.notifications.email.config.file";
    static final File DEFAULT_CONFIG_FILE_LOCATION = new File("robozonky-notifications-email.cfg");

    RefreshableNotificationProperties() {
        Scheduler.inBackground().submit(this, Settings.INSTANCE.getRemoteResourceRefreshInterval());
    }

    private static String readUrl(final URL url) throws IOException {
        try (final BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream(), Defaults.CHARSET))) {
            return r.lines().collect(Collectors.joining(System.lineSeparator()));
        }
    }

    @Override
    protected Optional<NotificationProperties> transform(final String source) {
        try (final InputStream baos = new ByteArrayInputStream(source.getBytes(Defaults.CHARSET))) {
            final Properties p = new Properties();
            p.load(baos);
            return Optional.of(new NotificationProperties(p));
        } catch (final IOException ex) {
            LOGGER.warn("Failed transforming source.", ex);
            return Optional.empty();
        }
    }

    @Override
    protected Optional<String> getLatestSource() {
        final String propValue =
                Settings.INSTANCE.get(RefreshableNotificationProperties.CONFIG_FILE_LOCATION_PROPERTY, (String) null);
        if (propValue != null) { // attempt to read from the URL specified by the property
            LOGGER.debug("Reading notification configuration from {}.", propValue);
            try {
                return Optional.of(RefreshableNotificationProperties.readUrl(new URL(propValue)));
            } catch (final IOException ex) {
                // fall back to the property file
                LOGGER.debug("Failed reading configuration from {}.", propValue);
            }
        }
        final File defaultConfigFile = RefreshableNotificationProperties.DEFAULT_CONFIG_FILE_LOCATION;
        LOGGER.debug("Read config file {}.", defaultConfigFile.getAbsolutePath());
        try {
            final URL u = defaultConfigFile.toURI().toURL();
            final String content = RefreshableNotificationProperties.readUrl(u);
            return Optional.of(content);
        } catch (final IOException ex) {
            LOGGER.debug("Failed reading configuration file {}.", defaultConfigFile);
            return Optional.empty();
        }
    }
}

@@ -2453,24 +2453,21 @@
  String 
-propValu
+sourc
 e =%0A    
@@ -2593,24 +2593,21 @@
     if (
-propValu
+sourc
 e != nul
@@ -2669,16 +2669,134 @@
 roperty%0A
+            // will read user-provided config file and log a warning if missing, since the user actually requested it%0A
         
@@ -2849,38 +2849,37 @@
 ration from 
+'
 %7B%7D
+'
 .%22, 
-propValu
+sourc
 e);%0A        
@@ -2973,24 +2973,21 @@
 new URL(
-propValu
+sourc
 e)));%0A  
@@ -3028,32 +3028,16 @@
 on ex) %7B
-%0A               
  // fall
@@ -3078,37 +3078,36 @@
          LOGGER.
-debug
+warn
 (%22Failed reading
@@ -3130,49 +3130,188 @@
 rom 
+'
 %7B%7D
-.%22, propValue);%0A            %7D%0A        %7D
+' due to '%7B%7D'.%22, source, ex.getMessage());%0A            %7D%0A        %7D%0A        // will read the default source file and silently ignore if missing, as this config is purely optional
 %0A   
@@ -3445,26 +3445,28 @@
 config file 
+'
 %7B%7D
+'
 .%22, defaultC
@@ -3586,31 +3586,27 @@
     
-final String content = 
+return Optional.of(
 Refr
@@ -3649,48 +3649,8 @@
 l(u)
-;%0A            return Optional.of(content
 );%0A 
@@ -3749,18 +3749,32 @@
 on file 
+'
 %7B%7D
+' due to '%7B%7D'
 .%22, defa
@@ -3786,16 +3786,33 @@
 nfigFile
+, ex.getMessage()
 );%0A     

Improve logging around notifications configuration