/*
Copyright 2011-2016 Google Inc. All Rights Reserved.

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.google.security.zynamics.zylib.system;

import com.google.security.zynamics.zylib.io.FileUtils;

import java.io.File;

/**
 * Contains a few simple methods that are useful for determining information about the underlying
 * operating system in a platform-independent way.
 */
// TODO(cblichmann): Replace this class with Google3/GoogleClient utility code.
public final class SystemHelpers {

  /**
   * Determines the machine-wide application data directory in a platform-independent way. Note that
   * the directory returned by this method is usually not writable for users without administrative
   * privileges (yes, even on Windows). The path returned by this method always contains a trailing
   * path separator.
   *
   * @return the machine-wide application data directory
   */
  public static String getAllUsersApplicationDataDirectory() {
    String result;
    if (isRunningWindows()) {
      // This should be the same as passing CSIDL_COMMON_APPDATA to the
      // native SHGetFolderPath() Win32 function.
      result = System.getenv("ProgramData");
      if (result == null) {
        // ProgramData should be unset on XP or lower, so the code
        // below assumes we're running on Vista or higher. To find the
        // "Application Data" folder for all users, we first determine
        // the localized folder name and append that to the
        // ALLUSERSPROFILE path.
        final String appData = System.getenv("APPDATA");

        result =
            System.getenv("ALLUSERSPROFILE")
                + (appData != null ? appData.substring(appData.lastIndexOf('\\'))
                    : "\\Application Data");
      }
    } else if (isRunningLinux()) {
      result = "/etc/opt";
    } else if (isRunningMacOSX()) {
      // TODO(cblichmann): Change to "/Library/Application Support".
      // For now, be consistent with the the CLI
      // versions of BinDiff/BinDetego
      result = "/etc/opt"; // Resolves to "/private/etc/opt"
    } else {
      // Fallback to local user directory
      result = System.getProperty("user.home");
    }

    return FileUtils.ensureTrailingSlash(result);
  }

  /**
   * Determines the machine-wide application data directory for the specified product in a
   * platform-independent way. Note that the directory returned by this method is usually not
   * writable for users without administrative privileges (yes, even on Windows). The path returned
   * by this method always contains a trailing path separator.
   *
   * @param product the product name to use when building the directory name
   * @return the machine-wide application data directory
   */
  public static String getAllUsersApplicationDataDirectory(final String product) {
    return getAllUsersApplicationDataDirectory() + "zynamics" + File.separator + product
        + File.separator;
  }

  /**
   * Determines the application data directory in a platform-independent way. The path returned by
   * this method always contains a trailing path separator.
   *
   * @return the application data directory for the current platform.
   */
  public static String getApplicationDataDirectory() {
    return FileUtils.ensureTrailingSlash(isRunningWindows() ? System.getenv("APPDATA") : System
        .getProperty("user.home"));
  }

  /**
   * Determines the application data directory for the specified product in a platform-independent
   * way. The path returned by this method always contains a trailing path separator.
   *
   * @param product the product name to use when building the directory name
   * @return the application data directory for the current platform.
   */
  public static String getApplicationDataDirectory(final String product) {
    return getApplicationDataDirectory() + (isRunningWindows() ? "" : ".") + "zynamics"
        + File.separator + product + File.separator;
  }

  /**
   * Determines the system temporary directory. The path returned by this method always contains a
   * trailing path separator.
   *
   * @return The directory where to save temporary files in.
   */
  public static String getTempDirectory() {
    return FileUtils.ensureTrailingSlash(System.getProperty("java.io.tmpdir"));
  }

  /**
   * Determines the system temporary directory for the specified product. The path returned by this
   * method always contains a trailing path separator.
   *
   * @param product the product name to use when building the directory name
   * @return The directory where to save temporary files in.
   */
  public static String getTempDirectory(final String product) {
    return getTempDirectory() + "zynamics" + File.separator + product + File.separator;
  }

  /**
   * Returns the user's home directory. The path returned by this method always contains a trailing
   * path separator.
   *
   * @return the full path to the user's home directory.
   */
  public static String getUserDirectory() {
    return FileUtils.ensureTrailingSlash(System.getProperty("user.home"));
  }

  /**
   * Determines whether the program is running in Linux
   *
   * @return true, if the program is running in Linux, false otherwise.
   */
  public static boolean isRunningLinux() {
    return System.getProperty("os.name").startsWith("Linux");
  }

  /**
   * Determines whether the program is running in Windows.
   *
   * @return true, if the program is running in Windows, false otherwise.
   */
  public static boolean isRunningMacOSX() {
    return System.getProperty("os.name").startsWith("Mac");
  }

  /**
   * Determines whether the program is running in Windows.
   *
   * @return true, if the program is running in Windows, false otherwise.
   */
  public static boolean isRunningWindows() {
    return System.getProperty("os.name").startsWith("Windows");
  }

  /**
   * Returns true if the current system has a 64bit architecture.
   */
  public static boolean is64BitArchitecture() {
    if (isRunningWindows()) {
      return "AMD64".equals(System.getenv("PROCESSOR_ARCHITECTURE"))
          || "AMD64".equals(System.getenv("PROCESSOR_ARCHITEW6432"));
    }

    throw new RuntimeException("Not implememted for Linux or Mac yet.");
  }
}
