#!/bin/bash
# Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


# Tell bash that we want the whole script to fail if any part fails.
set -e

# We require a parameter for where to put the results and the test script
destination="$1"
ui_script="$2"

function main {
  # Load configuration
  # Not in a separate function because you can't exort arrays
  # https://stackoverflow.com/questions/5564418/exporting-an-array-in-bash-script
  # Will export languages and simulators bash variables
  export UISS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  if [ -f "$UISS_DIR"/config-screenshots.sh ]; then
    source "$UISS_DIR"/config-screenshots.sh
  else
    if [ -f "$UISS_DIR"/config-screenshots.example.sh ]; then
      source "$UISS_DIR"/config-screenshots.example.sh
      echo "WARNING: Using example config-screenshots file, you should create your own"
    else
      echo "Configuration \"config-screenshots.sh\" does not exist! Aborting."
      exit 1
    fi
  fi

  _check_destination
  _check_ui_script
  _close_sim
  _reset_all_sim
  _xcode clean build

  for simulator in "${simulators[@]}"; do
    for language in $languages; do
      _clean_trace_results_dir
      _run_automation "$ui_script" "$language" "$simulator"
      _copy_screenshots "$language"
    done
  done

  _close_sim

  _remove_alpha_from_screenshots

  echo
  echo "Screenshots complete!"
}

# Global variables to keep track of where everything goes
tmp_dir="/tmp"
build_dir="$tmp_dir/screen_shooter"
bundle_dir="$build_dir/app.app"
trace_results_dir="$build_dir/traces"

function _check_destination {
  # Abort if the destination directory already exists. Better safe than sorry.

  if [ -z "$destination" ]; then
    destination="$HOME/Desktop/screenshots"
  fi
  if [ -d "$destination" ]; then
    echo "Destination directory \"$destination\" already exists! Aborting."
    exit 1
  fi
}

function _check_ui_script {
  # Abort if the UI script does not exist.

  if [ -z "$ui_script" ]; then
    ui_script="./config-automation.js"
  fi
  if [ ! -f "$ui_script" ]; then
    if [ -f "./config-automation.example.js" ]; then
      ui_script="./config-automation.js"
      echo "WARNING: Using example config-automation, please create your own"
    else
      echo "Config-automation does not exist! Aborting."
      exit 1
    fi
  fi
}

function _xcode {
  # A wrapper around `xcodebuild` that tells it to build the app in the temp
  # directory. If your app uses workspaces or special schemes, you'll need to
  # specify them here.
  #
  # Use `man xcodebuild` for more information on how to build your project.
  if test -n "$(find . -maxdepth 1 -name '*.xcworkspace' -print -quit)"
  then
    base=$(basename *.xcworkspace .xcworkspace)
    # First build omits PRODUCT_NAME
    # Do NOT ask me why you need to build this twice for it to work
    # or how I became to know this fact
    xcodebuild -sdk "iphonesimulator$ios_version" \
      CONFIGURATION_BUILD_DIR="$build_dir/build" \
      -workspace "$base.xcworkspace" -scheme "$base" -configuration Debug \
      DSTROOT=$build_dir \
      OBJROOT=$build_dir \
      SYMROOT=$build_dir \
      GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS SCREENSHOTS=1' \
      ONLY_ACTIVE_ARCH=NO \
    "$@"
    xcodebuild -sdk "iphonesimulator$ios_version" \
      CONFIGURATION_BUILD_DIR="$build_dir/build" \
      -workspace "$base.xcworkspace" -scheme "$base" -configuration Debug \
      DSTROOT=$build_dir \
      OBJROOT=$build_dir \
      SYMROOT=$build_dir \
      GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS SCREENSHOTS=1' \
      ONLY_ACTIVE_ARCH=NO \
    "$@"
    cp -r "$build_dir/build/$base.app" "$build_dir"
    bundle_dir="$build_dir/$base.app"
  else
    xcodebuild -sdk "iphonesimulator$ios_version" \
      CONFIGURATION_BUILD_DIR=$build_dir \
      PRODUCT_NAME=app \
    "$@"
  fi
}

function _clean_trace_results_dir {
  # Removes the trace results directory. We need to do this because Instruments
  # keeps appending new trace runs and it's simpler for us to always assume
  # there's just one run recorded where we look for screenshots.

  rm -rf "$trace_results_dir"
  mkdir -p "$trace_results_dir"
}

function _run_automation {
  # Runs the UI Automation JavaScript file that actually takes the screenshots.

  automation_script="$1"
  language="$2"
  simulator="$3"

  echo "Running automation script \"$automation_script\"
          for \"$simulator\"
          in language \"${language}\"..."

  dev_tools_dir=`xcode-select -print-path`
  tracetemplate="Automation"

  # Check out the `unix_instruments.sh` script to see why we need this wrapper.
  DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  until "$DIR"/unix_instruments.sh \
    -w "$simulator" \
    -D "$trace_results_dir/trace" \
    -t "$tracetemplate" \
    "$bundle_dir" \
    -e UIARESULTSPATH "$trace_results_dir" \
    -e UIASCRIPT "$automation_script" \
    -AppleLanguages "($language)" \
    -AppleLocale "$language"
   do
    echo Instruments failed to start up... retrying in 2 seconds
    sleep 2
  done

  find $trace_results_dir/Run\ 1/ -name *landscape*png -type f -exec sips -r -90 \{\} \;
}

function _copy_screenshots {
  # Since we're always clearing out the trace results before every run, we can
  # assume that any screenshots were saved in the "Run 1" directory. Copy them
  # to the destination's language folder!

  language="$1"

  mkdir -p "$destination/$language"
  cp $trace_results_dir/Run\ 1/*.png "$destination/$language"
}

function _reset_all_sim {
  # Reset all apps and data on from all iOS Simulators
  # Attention: Simulator can only be reset if it is not opend
  instruments -s devices \
   | grep Simulator \
   | grep -o "[0-9A-F]\{8\}-[0-9A-F]\{4\}-[0-9A-F]\{4\}-[0-9A-F]\{4\}-[0-9A-F]\{12\}" \
   | while read -r line ; do
      echo "Resetting Simulator with UDID: $line"
      xcrun simctl erase $line
  done
}

function _close_sim {
  # I know, I know. It says "iOS Simulator". For some reason,
  # that's the only way Applescript can identify it.
  osascript -e "tell application \"iOS Simulator\" to quit"
}

function _remove_alpha_from_screenshots {
  if ! type "convert" &> /dev/null; then
    echo -e "\nCannot remove alpha channel because ImageMagick is not installed. You need to remove alpha before you can upload to iTunes Connect."
  else
    language="$1"
    for entry in $(ls $destination/*/iOS*.png); do
    convert "$entry" -background white -alpha off "$entry"
    done
    echo -e "\nScreenshots' alpha channel removed."
  fi
}

main

