/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.ivory.util;

import org.apache.log4j.Logger;

import java.io.*;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class ApplicationProperties extends Properties {

  private static Logger LOG = Logger.getLogger(ApplicationProperties.class);

  protected enum LocationType {FILE, HOME, CLASSPATH}

  protected abstract String getPropertyFile();

  private final String propertyFile;
  private final LocationType location;

  private Pattern sysPropertyPattern = Pattern.compile("\\$\\{[A-Za-z0-9_.]+\\}");

  protected ApplicationProperties() throws IOException {
    propertyFile = getPropertyFile();
    location = getPropertyFileLocation();
    loadProperties();
  }

  protected LocationType getPropertyFileLocation() {
    String userHome = System.getProperty("user.home");
    String confDir = System.getProperty("config.location");
    if (confDir == null && new File(userHome, propertyFile).exists()) {
      LOG.info("config.location is not set, and property file found in home dir" +
              userHome + "/" + propertyFile);
      return LocationType.HOME;
    } else if (confDir != null) {
      LOG.info("config.location is set, using " + confDir + "/" + propertyFile);
      return LocationType.FILE;
    } else {
      LOG.info("config.location is not set, properties file not present in " +
              "user home dir, falling back to classpath for " + propertyFile);
      return LocationType.CLASSPATH;
    }
  }

  protected void loadProperties() throws IOException {
    InputStream resource;

    if (location == LocationType.CLASSPATH) {
      resource = getClass().getResourceAsStream("/" + propertyFile);
    } else {
      resource = new FileInputStream(propertyFile);
    }

    if (resource == null) {
      throw new FileNotFoundException(propertyFile +
          " not found in " + location);
    } else {
        try {
          //TODO:: Should we clear and reload? In which case we need to lock
          //TODO:: down the object.
          LOG.info("Loading properties from " + propertyFile);
          load(resource);
          for (Object key : keySet()) {
            put(key, substitute(getProperty((String)key)));
          }
        } finally {
          resource.close();
        }
    }
  }

  private String substitute(String originalValue) {
    Matcher envVarMatcher = sysPropertyPattern.matcher(originalValue);
    while (envVarMatcher.find()) {
      String envVar = originalValue.substring(envVarMatcher.start() + 2,
          envVarMatcher.end() - 1);
      String envVal = System.getProperty(envVar, System.getenv(envVar));

      envVar = "\\$\\{" + envVar + "\\}";
      if (envVal != null) {
        originalValue = originalValue.replaceAll(envVar, envVal);
        envVarMatcher = sysPropertyPattern.matcher(originalValue);
      }
    }
    return originalValue;
  }

}

@@ -1234,22 +1234,16 @@
 private 
-final 
 String p
@@ -1269,14 +1269,8 @@
 ate 
-final 
 Loca
@@ -1438,80 +1438,18 @@
     
-propertyFile = getPropertyFile();%0A    location = getPropertyFileLocation
+initialize
 ();%0A
@@ -1487,28 +1487,57 @@
 otected 
-LocationType
+void initialize() %7B%0A    String propFile =
  getProp
@@ -1548,20 +1548,11 @@
 File
-Location() %7B
+();
 %0A   
@@ -1709,28 +1709,24 @@
 erHome, prop
-erty
 File).exists
@@ -1841,36 +1841,32 @@
 ome + %22/%22 + prop
-erty
 File);%0A      ret
@@ -1854,38 +1854,42 @@
 ropFile);%0A      
-return
+location =
  LocationType.HO
@@ -1892,16 +1892,85 @@
 e.HOME;%0A
+      propertyFile = new File(userHome, propFile).getAbsolutePath();%0A
     %7D el
@@ -2057,36 +2057,32 @@
 Dir + %22/%22 + prop
-erty
 File);%0A      ret
@@ -2070,38 +2070,42 @@
 ropFile);%0A      
-return
+location =
  LocationType.FI
@@ -2108,16 +2108,86 @@
 e.FILE;%0A
+        propertyFile = new File(confDir, propFile).getAbsolutePath();%0A
     %7D el
@@ -2330,36 +2330,32 @@
 ath for %22 + prop
-erty
 File);%0A      ret
@@ -2351,22 +2351,26 @@
 ;%0A      
-return
+location =
  Locatio
@@ -2386,16 +2386,47 @@
 SSPATH;%0A
+      propertyFile = propFile;%0A
     %7D%0A  

Fix issues with startup properties load