content: /**
   * Copyright 2000-2006 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, version 3 of the License.
   * <p/>
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package marytts.server;
  
  import android.util.Log;
  
  import com.marytts.android.link.MaryLink;
  
  import org.apache.commons.lang.StringUtils;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.Locale;
  import java.util.Vector;
  
  import marytts.config.MaryConfig;
  import marytts.exceptions.MaryConfigurationException;
  import marytts.exceptions.NoSuchPropertyException;
  
  
  /**
   * A static class reading once, at program start, properties
   * from a number of external property files,
   * and providing them via static
   * getter methods to anyone wishing to read them.
   * At program start, this will read all the config files in the MARY_BASE/conf
   * directory that end in *.config. See the config files for more information.
   *
   * @author Marc Schr&ouml;derfeatures
   */
  
  public class MaryProperties {
      /**
       * The mary base directory, e.g. /usr/local/mary
       */
      public static String maryBase() {
          return getFilename("mary.base", ".");
      }
  
  
      public static List<String> getList(String propName) {
          //  Log.d(Mary.LOG,"getList, propName="+propName);
          assert propName.endsWith(".list");
          List<String> vals = new ArrayList<String>();
  
          // First, anything from system properties:
          String val = MaryLink.getProperties().get(propName);
          if (val != null) {
              for (String a : Arrays.asList(StringUtils.split(val, "\\"))) {
                  String b = a.trim();
                  if (!b.isEmpty())
                      vals.add(b);
              }
          }
  
          //  Log.d(Mary.LOG,"getList, from system properties, propName="+propName+" vals.count="+vals.size()+" vals="+vals);
          // Log.d("test", "setupFeatureProcessors getList "+MaryConfig.getConfigs().toString());
  //
  //        // Then, anything from the configs:
  //        for (MaryConfig mc : MaryConfig.getConfigs()) {
  //            // Log.i("test", "setupFeatureProcessors getConfigs"+mc.toString());
  //
  //          //  Log.d("test", "setupFeatureProcessors getConfigs : "+mc.toString() );
  //
  //            vals.addAll(mc.getList(propName));
  //        }
          //    Log.d("test", "setupFeatureProcessors getList FINISHED");
          return vals;
      }
  
  
      /**
       * Get a property from the underlying config files.
       *
       * @param property     the property requested
       * @param defaultValue the value to return if the property is not defined
       * @return the property value if found, defaultValue otherwise.
       */
      public static String getProperty(String property, String defaultValue) {
  
  
  //        for (String key:
  //             MainActivity.properties.keySet()) {
  //            Log.d(Mary.LOG,"key="+key+" value="+MainActivity.properties.get(key));
  //        }
  
          // First, try system properties:
          String val = MaryLink.getProperties().get(property);
          if (val != null) {
              return val;
          }
          // Then, try the configs. First one wins:
          for (MaryConfig mc : MaryConfig.getConfigs()) {
              val = mc.getProperties().getProperty(property);
              if (val != null) {
                  return val;
              }
          }
          return defaultValue;
      }
  
      /**
       * Names of the classes to use as modules, plus optional parameter info.
       *
       * @see marytts.modules.ModuleRegistry#instantiateModule(String) for details on expected format.
       */
      public static List<String> moduleInitInfo() {
          return getList("modules.classes.list");
      }
  
      /**
       * Names of the classes to use as waveform synthesizers.
       */
      public static List<String> synthesizerClasses() {
          return getList("synthesizers.classes.list");
      }
  
      /**
       * Names of the classes to use as audio effects.
       */
      public static Vector<String> effectClasses() {
          return new Vector<String>(getList("audioeffects.classes.list"));
      }
  
  
      /**
       * From a path entry in the properties, create an expanded form.
       * Replace the string MARY_BASE with the value of property "mary.base";
       * replace all "/" and "\\" with the platform-specific file separator.
       */
      private static String expandPath(String path) {
          final String MARY_BASE = "MARY_BASE";
          StringBuilder buf = null;
          if (path.startsWith(MARY_BASE)) {
              buf = new StringBuilder(maryBase());
              buf.append(path.substring(MARY_BASE.length()));
          } else {
              buf = new StringBuilder(path);
          }
          if (File.separator.equals("/")) {
              int i = -1;
              while ((i = buf.indexOf("\\")) != -1)
                  buf.replace(i, i + 1, "/");
          } else if (File.separator.equals("\\")) {
              int i = -1;
              while ((i = buf.indexOf("/")) != -1)
                  buf.replace(i, i + 1, "\\");
          } else {
              throw new Error("Unexpected File.separator: `" + File.separator + "'");
          }
          return buf.toString();
      }
  
      /**
       * Get a property from the underlying properties.
       *
       * @param property the property requested
       * @return the property value if found, null otherwise.
       */
      public static String getProperty(String property) {
          return getProperty(property, null);
      }
  
      /**
       * Get a boolean property from the underlying properties.
       *
       * @param property the property requested
       * @return the boolean property value if found, false otherwise.
       */
      public static boolean getBoolean(String property) {
          return getBoolean(property, false);
      }
  
      /**
       * Get or infer a boolean property from the underlying properties.
       * Apart from the values "true"and "false", a value "auto" is permitted;
       * it will resolve to "true" in server mode and to "false" in non-server mode.
       *
       * @param property the property requested
       * @return the boolean property value if found, false otherwise.
       */
      public static boolean getAutoBoolean(String property) {
          return getAutoBoolean(property, false);
      }
  
      /**
       * Get an integer property from the underlying properties.
       *
       * @param property the property requested
       * @return the integer property value if found, -1 otherwise.
       */
      public static int getInteger(String property) {
          return getInteger(property, -1);
      }
  
      /**
       * Get a filename property from the underlying properties. The string MARY_BASE is
       * replaced with the value of the property mary.base, and path separators are adapted
       * to the current platform.
       *
       * @param property the property requested
       * @return the filename corresponding to the property value if found, null otherwise.
       */
      public static String getFilename(String property) {
          return getFilename(property, null);
      }
  
  
      /**
       * Get a boolean property from the underlying properties.
       *
       * @param property     the property requested
       * @param defaultValue the value to return if the property is not defined
       * @return the boolean property value if found and valid, defaultValue otherwise.
       */
      public static boolean getBoolean(String property, boolean defaultValue) {
          String value = getProperty(property);
          if (value == null)
              return defaultValue;
          try {
              return Boolean.valueOf(value).booleanValue();
          } catch (NumberFormatException e) {
              return defaultValue;
          }
      }
  
      /**
       * Get or infer a boolean property from the underlying properties.
       * Apart from the values "true"and "false", a value "auto" is permitted;
       * it will resolve to "true" in server mode and to "false" in non-server mode.
       *
       * @param property     the property requested
       * @param defaultValue the value to return if the property is not defined
       * @return the boolean property value if found and valid, false otherwise.
       */
      public static boolean getAutoBoolean(String property, boolean defaultValue) {
          String value = getProperty(property);
          if (value == null)
              return defaultValue;
          if (value.equals("auto")) {
              return (getProperty("server").equals("commandline") ? false : true);
          } else {
              return getBoolean(property, defaultValue);
          }
      }
  
      /**
       * Get a property from the underlying properties.
       *
       * @param property     the property requested
       * @param defaultValue the value to return if the property is not defined
       * @return the integer property value if found and valid, defaultValue otherwise.
       */
      public static int getInteger(String property, int defaultValue) {
          String value = getProperty(property);
          if (value == null) {
              return defaultValue;
          }
          try {
              return Integer.decode(value).intValue();
          } catch (NumberFormatException e) {
              return defaultValue;
          }
      }
  
      /**
       * Get a filename property from the underlying properties. The string MARY_BASE is
       * replaced with the value of the property mary.base, and path separators are adapted
       * to the current platform.
       *
       * @param property     the property requested
       * @param defaultValue the value to return if the property is not defined
       * @return the filename corresponding to the property value if found, defaultValue otherwise.
       */
      public static String getFilename(String property, String defaultValue) {
          String filename = getProperty(property);
          if (filename == null) {
              return defaultValue;
          }
          return expandPath(filename);
      }
  
  
      /**
       * Get a property from the underlying properties, throwing an exception if
       * it is not defined.
       *
       * @param property the property required
       * @return the property value
       * @throws NoSuchPropertyException if the property is not defined.
       */
      public static String needProperty(String property) throws NoSuchPropertyException {
          String value = getProperty(property);
          if (value == null) {
              throw new NoSuchPropertyException("Missing value `" + property + "' in configuration files");
          }
          return value;
      }
  
      /**
       * Get a boolean property from the underlying properties, throwing an exception if
       * it is not defined.
       *
       * @param property the property requested
       * @return the boolean property value
       * @throws NoSuchPropertyException if the property is not defined.
       */
      public static boolean needBoolean(String property) throws NoSuchPropertyException {
          String value = getProperty(property);
          if (value == null) {
              throw new NoSuchPropertyException("Missing property `" + property + "' in configuration files");
          }
          try {
              return Boolean.valueOf(value).booleanValue();
          } catch (NumberFormatException e) {
              throw new NoSuchPropertyException("Boolean property `" + property + "' in configuration files has wrong value `" + value + "'");
          }
      }
  
      /**
       * Get or infer a boolean property from the underlying properties, throwing an exception if
       * it is not defined.
       * Apart from the values "true"and "false", a value "auto" is permitted;
       * it will resolve to "true" in server mode and to "false" in non-server mode.
       *
       * @param property the property requested
       * @return the boolean property value
       * @throws NoSuchPropertyException if the property is not defined.
       */
      public static boolean needAutoBoolean(String property)
              throws NoSuchPropertyException {
          String value = getProperty(property);
          if (value == null) {
              throw new NoSuchPropertyException("Missing property `" + property + "' in configuration files");
          }
          if (value.equals("auto")) {
              return (needProperty("server").equals("commandline") ? false : true);
          } else {
              return needBoolean(property);
          }
      }
  
  
      /**
       * Get an integer property from the underlying properties, throwing an exception if
       * it is not defined.
       *
       * @param property the property requested
       * @return the integer property value
       * @throws NoSuchPropertyException if the property is not defined.
       */
      public static int needInteger(String property) throws NoSuchPropertyException {
          String value = getProperty(property);
          if (value == null) {
              throw new NoSuchPropertyException("Missing property `" + property + "' in configuration files");
          }
          try {
              return Integer.decode(value).intValue();
          } catch (NumberFormatException e) {
              throw new NoSuchPropertyException("Integer property `" + property + "' in configuration files has wrong value `" + value + "'");
          }
      }
  
      /**
       * Get a filename property from the underlying properties, throwing an exception if
       * it is not defined. The string MARY_BASE is
       * replaced with the value of the property mary.base, and path separators are adapted
       * to the current platform.
       *
       * @param property the property requested
       * @return the filename corresponding to the property value
       * @throws NoSuchPropertyException if the property is not defined or the value is not a valid filename
       */
      public static String needFilename(String property) throws NoSuchPropertyException {
          String filename = expandPath(needProperty(property));
          if (!new File(filename).canRead()) {
              throw new NoSuchPropertyException("Cannot read file `" + filename +
                      "'. Check property `" + property +
                      "' in configuration files");
          }
          return filename;
      }
  
      /**
       * For the named property, attempt to get an open input stream.
       * If the property value starts with "jar:", the remainder of the value is interpreted
       * as an absolute path in the classpath. Otherwise it is interpreted as a file name.
       *
       * @param propertyName the name of a property defined in one of the mary config files.
       * @return an InputStream representing the given resource
       * @throws NoSuchPropertyException    if the property is not defined
       * @throws FileNotFoundException      if the property value is a file name and the file cannot be opened
       * @throws MaryConfigurationException if the property value is a classpath entry which cannot be opened
       */
      public static InputStream needStream(String propertyName)
              throws NoSuchPropertyException, FileNotFoundException, MaryConfigurationException {
  
  
          MaryProperties.needProperty(propertyName); // to throw exceptions if not defined
  
  
          return getStream(propertyName);
      }
  
      /**
       * For the named property, attempt to get an open input stream.
       * If the property value starts with "jar:", the remainder of the value is interpreted
       * as an absolute path in the classpath. Otherwise it is interpreted as a file name.
       *
       * @param propertyName the name of a property defined in one of the mary config files.
       * @return an InputStream representing the given resource, or null if the property was not defined.
       * @throws FileNotFoundException      if the property value is a file name and the file cannot be opened
       * @throws MaryConfigurationException if the property value is a classpath entry which cannot be opened
       */
      public static InputStream getStream(String propertyName)
              throws FileNotFoundException, MaryConfigurationException {
          InputStream stream = null;
  
          String propertyValue = getProperty(propertyName).trim();
          if (propertyName.equals("en.pos.model"))
              Log.d(Mary.LOG, "getStream : propertyName=" + propertyName + " propertyValue=" + propertyValue);
          if (propertyValue == null) {
              return null;
          } else if (propertyValue.startsWith("jar:")) { // read from classpath
              String classpathLocation = propertyValue.substring("jar:".length());
              classpathLocation = classpathLocation.substring(1, classpathLocation.length());
              //MainActivity.getContext().getAssets().open("marytts/config/marybase.config")
              try {
  
                  stream = MaryLink.getContext().getAssets().open(classpathLocation);
              } catch (Throwable e) {
                  // TODO Auto-generated catch block
                  Log.d(Mary.LOG, "sehvvvv " + e.getMessage());
                  // e.printStackTrace();
              }
              if (stream == null) {
                  Log.d(Mary.LOG, "For property '" + propertyName + "', no classpath resource available at '" + classpathLocation + "'");
                  throw new MaryConfigurationException("For property '" + propertyName + "', no classpath resource available at '" + classpathLocation + "'");
              }
          } else {
              String fileName = MaryProperties.getFilename(propertyName);
              stream = new FileInputStream(fileName);
          }
          return stream;
  
      }
  
      /**
       * Get a Class property from the underlying properties, throwing an exception if
       * it is not defined.
       *
       * @param property the property requested
       * @return the Class corresponding to the property value
       * @throws NoSuchPropertyException if the property is not defined or the value is not a valid class
       */
      public static Class needClass(String property)
              throws NoSuchPropertyException {
          String value = needProperty(property);
          Class c = null;
          try {
              c = Class.forName(value);
          } catch (ClassNotFoundException e) {
              throw new NoSuchPropertyException("Cannot find class `" + value +
                      "'. Check property `" + property +
                      "' in configuration files");
          }
          return c;
      }
  
      /**
       * Provide the config file prefix used for different locales in the
       * config files. Will return the string representation of the locale
       * as produced by locale.toString(), e.g. "en_GB";
       * if locale is null, return null.
       *
       * @param locale
       * @return
       */
      public static String localePrefix(Locale locale) {
          if (locale == null) return null;
          return locale.toString();
      }
  
  }
  
  