package org.karmaexchange.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.servlet.ServletContext;

import lombok.AccessLevel;
import lombok.Getter;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.karmaexchange.resources.msg.ErrorResponseMsg;
import org.karmaexchange.resources.msg.ErrorResponseMsg.ErrorInfo;

import com.google.appengine.api.utils.SystemProperty;

@ThreadSafe
public class Properties {

  private static final String CONFIG_FILE_PATH = "/WEB-INF/server_properties.txt";
  private static final String TEST_PROPERTY_PREFIX = "test-";

  @GuardedBy("Properties.class")
  private static PropertiesConfiguration config;

  public enum Property {
    FACEBOOK_APP_SECRET("facebook-app-secret");

    private final String propertyName;

    private Property(String propertyName) {
      this.propertyName = propertyName;
    }

    private String getPropertyName() {
      if (isProductionDeployment()) {
        return propertyName;
      } else {
        return TEST_PROPERTY_PREFIX + propertyName;
      }
    }
  }

  private static synchronized PropertiesConfiguration getConfig(ServletContext context) {
    if (config == null) {
      PropertiesConfiguration configToInit = new PropertiesConfiguration();
      BufferedReader in = new BufferedReader(
        new InputStreamReader(context.getResourceAsStream(CONFIG_FILE_PATH)));
      try {
        configToInit.load(in);
      } catch (ConfigurationException e) {
        throw ErrorResponseMsg.createException(e, ErrorInfo.Type.BACKEND_SERVICE_FAILURE);
      }
      configToInit.setThrowExceptionOnMissing(true);
      config = configToInit;
    }
    return config;
  }

  public static String get(ServletContext context, Property property) {
    // TODO(avaliani): low-pri: see if I can optimize the unconditional lock on getConfig.
    return getConfig(context).getString(property.getPropertyName());
  }

  private static boolean isProductionDeployment() {
    return SystemProperty.environment.value() == SystemProperty.Environment.Value.Production;
  }
}

@@ -26,16 +26,121 @@
 .util;%0A%0A
+import static com.google.common.base.Preconditions.checkNotNull;%0Aimport static java.lang.String.format;%0A%0A
 import j
@@ -162,16 +162,16 @@
 Reader;%0A
-
 import j
@@ -1029,16 +1029,28 @@
 ret%22);%0A%0A
+    @Getter%0A
     priv
@@ -1181,54 +1181,29 @@
    p
-rivate String getPropertyName() %7B%0A      if (is
+ublic boolean testAnd
 Prod
@@ -1213,20 +1213,17 @@
 ionD
-eploymen
+istinc
 t()
-)
  %7B%0A 
@@ -1231,105 +1231,20 @@
     
- 
- 
 return 
-propertyName;%0A      %7D else %7B%0A        return TEST_PROPERTY_PREFIX + propertyName;%0A      %7D
+true;
 %0A   
@@ -1757,61 +1757,8 @@
   %7D%0A
-      configToInit.setThrowExceptionOnMissing(true);%0A
     
@@ -1892,135 +1892,764 @@
     
-// TODO(avaliani): low-pri: see if I can optimize the unconditional lock on getConfig.%0A    return getConfig(context).getString(
+PropertiesConfiguration propConfig = getConfig(context);%0A    String value;%0A    if (!isProductionDeployment()) %7B%0A      value = propConfig.getString(getTestPropertyName(property));%0A      if (value != null) %7B%0A        return value;%0A      %7D%0A      if (property.testAndProductionDistinct()) %7B%0A        throw new NullPointerException(%0A          format(%22property '%25s' not specified in '%25s'%22, getTestPropertyName(property),%0A            CONFIG_FILE_PATH));%0A      %7D%0A    %7D%0A    value = propConfig.getString(property.getPropertyName());%0A    return checkNotNull(value,%0A      format(%22property '%25s' not specified in '%25s'%22, property.getPropertyName(), CONFIG_FILE_PATH));%0A  %7D%0A%0A  private static String getTestPropertyName(Property property) %7B%0A    return TEST_PROPERTY_PREFIX + 
 prop
@@ -2666,25 +2666,24 @@
 opertyName()
-)
 ;%0A  %7D%0A%0A  pri

Improve test property support.