/*
 * Copyright 2016 52°North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * 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.n52.javaps.annotation;

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.configuration2.io.ClasspathLocationStrategy;
import org.apache.commons.configuration2.io.CombinedLocationStrategy;
import org.apache.commons.configuration2.io.DefaultFileSystem;
import org.apache.commons.configuration2.io.FileLocationStrategy;
import org.apache.commons.configuration2.io.FileLocator;
import org.apache.commons.configuration2.io.FileLocatorUtils;
import org.apache.commons.configuration2.io.FileSystem;
import org.apache.commons.configuration2.io.FileSystemLocationStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.n52.iceland.util.JSONUtils;
import org.n52.iceland.util.Optionals;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;

/**
 * TODO JavaDoc
 * @author Christian Autermann
 */
public class ConfigurableClasses {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurableClasses.class);
    private static final Map<Class<?>, Optional<JsonNode>> CONFIGURATIONS = new ConcurrentHashMap<>();

    public static Optional<JsonNode> get(Class<?> clazz) {
        return CONFIGURATIONS.computeIfAbsent(clazz, ConfigurableClasses::load);
    }

    private static Optional<JsonNode> load(Class<?> clazz) {
        Properties annotation = clazz.getAnnotation(Properties.class);
        if (annotation == null) {
            LOGGER.warn("Class extends {}, but is not annotated with {} annotation.", clazz.getName(), Properties.class.getName());
        } else {
            Optional<String> fileName = getPropertiesFileName(annotation);
            if (!fileName.isPresent()) {
                LOGGER.warn("Class {} is annotated with {} annotation, but the annotation is empty.", clazz.getName(), Properties.class.getName());
            } else {
                URL fileURL = locateFile(fileName.get());
                try {
                    return Optional.of(JSONUtils.loadURL(fileURL));
                } catch (IOException e) {
                    LOGGER.error("Could not read property file for class " + clazz.getName(), e);
                }
            }
        }
        return Optional.empty();
    }

    private static URL locateFile(String fileName) {
        FileLocationStrategy strategy = new CombinedLocationStrategy(Arrays.asList(new FileSystemLocationStrategy(),
                                                                                   new ClasspathLocationStrategy()));
        FileSystem fileSystem = new DefaultFileSystem();
        FileLocator locator = FileLocatorUtils.fileLocator().locationStrategy(strategy).fileName(fileName).create();
        return strategy.locate(fileSystem, locator);
    }

    private static Optional<String> getPropertiesFileName(Properties annotation) {
        return Optionals.or(Optional.ofNullable(annotation.propertyFileName()).map(Strings::emptyToNull),
                            Optional.ofNullable(annotation.defaultPropertyFileName()).map(Strings::emptyToNull));
    }

}

@@ -675,16 +675,37 @@
 ation;%0A%0A
+import java.io.File;%0A
 import j
@@ -1376,32 +1376,71 @@
 cationStrategy;%0A
+import org.n52.iceland.util.JSONUtils;%0A
 import org.slf4j
@@ -1485,87 +1485,8 @@
 y;%0A%0A
-import org.n52.iceland.util.JSONUtils;%0Aimport org.n52.iceland.util.Optionals;%0A%0A
 impo
@@ -1581,19 +1581,365 @@
  * T
-ODO JavaDoc
+his class searches for a %3Ccode%3EProperties%3C/code%3E annotation and tries to parse%0A * the properties to a JSON object. First it checks, if the propertyFilename of the%0A * annotation leads to a existing file. If this is the case, the properties are parsed.%0A * If the propertyFilename doesn't lead to an existing file, the defaultPropertyFilename%0A * is checked.%0A *
 %0A * 
@@ -2756,14 +2756,135 @@
     
-if (!f
+Optional%3CString%3E defaultFileName = getDefaultPropertiesFileName(annotation);%0A            if (!fileName.isPresent() && !defaultF
 ileN
@@ -3067,44 +3067,270 @@
    %7D
- else %7B%0A                URL 
+%0A%0A            URL fileURL = null;%0A            //always check propertyFilename first%0A            if(fileName.isPresent())%7B%0A                fileURL = locateFile(fileName.get());%0A                //check if the strategies found something%0A                if (
 fileURL 
 = lo
@@ -3321,38 +3321,425 @@
 if (fileURL 
+!
 = 
-locateFile(f
+null) %7B%0A                    try %7B%0A                        return Optional.of(JSONUtils.loadURL(fileURL));%0A                    %7D catch (IOException e) %7B%0A                        LOGGER.error(%22Could not read property file for class %22 + clazz.getName(), e);%0A                    %7D%0A                %7D%0A            %7D%0A            if(defaultFileName.isPresent())%7B%0A                fileURL = locateFile(defaultF
 ileName.get(
@@ -4678,21 +4678,8 @@
 urn 
-Optionals.or(
 Opti
@@ -4754,37 +4754,115 @@
 ull)
-,
+;
 %0A    
+%7D%0A%0A
     
-           
+private static Optional%3CString%3E getDefaultPropertiesFileName(Properties annotation) %7B%0A
         
  Opt
@@ -4849,32 +4849,38 @@
 tion) %7B%0A        
+return
  Optional.ofNull
@@ -4947,17 +4947,16 @@
 yToNull)
-)
 ;%0A    %7D%0A

Change property functionality. First, search for custom property-file. If not present, use default properties.