#! /bin/sh
#   Copyright (c) 2015 Nat! - Mulle kybernetiK
#   All rights reserved.
#
#   Redistribution and use in source and binary forms, with or without
#   modification, are permitted provided that the following conditions are met:
#
#   Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
#   Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
#   Neither the name of Mulle kybernetiK nor the names of its contributors
#   may be used to endorse or promote products derived from this software
#   without specific prior written permission.
#
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
#   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#

# this script patches the xcodeproj so that the headers and
# lib files can be added in a sensible order
#

. mulle-bootstrap-local-environment.sh
. mulle-bootstrap-brew.sh


usage()
{
   cat <<EOF
xcode <add|remove> [xcodeproj]

   add      : add settings to Xcode project (default)
   remove   : remove settings from Xcode project
EOF
}


check_and_usage_and_help()
{
case "$COMMAND" in
   add)
   ;;
   remove)
   ;;
   *)
   usage >&2
   exit 1
   ;;
esac
}


COMMAND="${1:-add}"
shift
PROJECT="$1"
shift


check_and_usage_and_help


list_configurations()
{
   local project

   project="${1}"
  #
  # Figure out all configuration
  #
   xcodebuild -list -project "${project}" 2> /dev/null | \
   grep -A100 'Build Configurations' | \
   grep -B100 'Schemes' | \
   egrep -v 'Configurations:|Schemes:' | \
   grep -v 'If no build' | \
   sed 's/^[ \t]*\(.*\)/\1/' | \
   sed '/^$/d'
}


#
# Figure out default configuration
#
list_default_configuration()
{
   xcodebuild -list 2> /dev/null | grep 'If no build configuration' | sed 's/^.*\"\(.*\)\".*$/\1/g'
}


check_for_mulle_xcode_settings()
{
   local installed

   #
   # OK
   #
   installed=`which mulle-xcode-settings`
   if [ "$installed" = "" ]
   then
      user_say_yes "Need to install mulle-xcode-settings (via brew)
   Install mulle-xcode-settings now ?"
      [ $? -eq 0 ] || exit 1

      brew_update_if_needed

      log_info "Tapping mulle-kybernetik/software"
      brew tap "mulle-kybernetik/software"

      log_info "Installing mulle-xcode-settings"
      brew install "mulle-xcode-settings" || fail "failed to install \"mulle-xcode-settings\""
   fi
}


map_configuration()
{
   local xcode_configuration
   local configurations
   local mapped
   local i

   configurations="$1"
   xcode_configuration="$2"

   mapped=""

   local old

   old="${IFS:-" "}"
   IFS="
"
   for i in ${configurations}
   do
      if [ "$i" = "$xcode_configuration" ]
      then
         mapped="${xcode_configuration}"
      fi
   done
   IFS="${old}"

   if [ "$mapped" = "" ]
   then
   case i in
      *ebug*)
         mapped="Debug"
         ;;
      *rofile*)
         mapped="Release"
         ;;
      *eleas*)
         mapped="Release"
         ;;
      *)
         mapped="${default}"
         ;;
   esac
   fi
   echo "${mapped}"
}


patch_library_configurations()
{
   local xcode_configurations
   local configurations
   local i
   local mapped

   xcode_configurations="$1"
   configurations="$2"
   project="$3"
   flag="$4"

   local old

   old="${IFS:-" "}"
   IFS="
"
   for i in ${xcode_configurations}
   do
      mapped=`map_configuration "${configurations}" "${i}"`
      exekutor mulle-xcode-settings -configuration "${i}" "${flag}" "LIBRARY_CONFIGURATION" "${mapped}" "${project}" || exit 1
   done
   IFS="${old}"
}


patch_xcode_project()
{
   local name
   local project
   local mapped
   local configurations
   local xcode_configurations
   local terse


   read_yes_no_config_setting "terse" "NO"
   terse=$?

   name=`basename "${PWD}"`

   if [ ! -z "${PROJECT}" ]
   then
      [ -d "${PROJECT}" ] || fail "xcodeproj ${PROJECT} not found"
      project="${PROJECT}"
   else
   project=`find_xcodeproj "${name}"`
      if [ "${project}" = "" ]
      then
         fail "no xcodeproj found"
      fi
   fi

   projectname="`basename "${project}"`"

   # mod_pbxproj can only do Debug/Release/All...

   check_for_mulle_xcode_settings

   configurations=`read_build_root_setting "configurations" "Debug
Release"`

   default=`echo "${configurations}" | tail -1 | sed 's/^[ \t]*//;s/[ \t]*$//'`

   #
   # Add LIBRARY_CONFIGURATION mapping
   #
   xcode_configurations=`list_configurations "${project}"`
   if [ "$xcode_configurations" = "" ]
   then
      xcode_configurations="Debug
Release"
   fi

   local flag

   if [ "$COMMAND" = "add" ]
   then
      flag="add"

      if [ $terse -ne 0 ]
      then
         #     012345678901234567890123456789012345678901234567890123456789
         echo "${C_WHITE}Settings will be added to ${C_MAGENTA}${projectname}${C_WHITE}." >&2
         echo "In the long term it may be more useful to copy/paste the following" >&2
         echo "lines into a local .xcconfig file, that is inherited by all configurations.${C_RESET}" >&2
      fi
   else
      flag="remove"

      if [ $terse -ne 0 ]
      then
         #     012345678901234567890123456789012345678901234567890123456789
         echo "${C_WHITE}Settings will be removed from ${projectname}." >&2
         echo "You may want to check afterwards, that this has worked out OK :).${C_RESET}" >&2
      fi
   fi

   local dependencies_dir
   local header_search_paths
   local library_search_paths
   local framework_search_paths

   #  figure out a way to make this nicer
   local absolute
   local absolute2
   local relative_subdir

   absolute="`realpath "${project}"`"
   absolute="`dirname "${absolute}"`"
   absolute2="`pwd -P`/${DEPENDENCY_SUBDIR}"
   relative_subdir="`relative_path_between "${absolute2}" "${absolute}" `"

   dependencies_dir='$(PROJECT_DIR)/'"${relative_subdir}"

   header_search_paths="\$(DEPENDENCIES_DIR)/${HEADER_DIR_NAME}"
   header_search_paths="${header_search_paths} /usr/local/include"
   header_search_paths="${header_search_paths} \$(inherited)"

   library_search_paths="\$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/\$(LIBRARY_CONFIGURATION)\$(EFFECTIVE_PLATFORM_NAME)"
   library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/\$(LIBRARY_CONFIGURATION)"
   library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/${default}\$(EFFECTIVE_PLATFORM_NAME)"
   library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/${default}"
   library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}"
   library_search_paths="${library_search_paths} /usr/local/lib"
   library_search_paths="${library_search_paths} \$(inherited)"


   framework_search_paths="\$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/\$(LIBRARY_CONFIGURATION)\$(EFFECTIVE_PLATFORM_NAME)"
   framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/\$(LIBRARY_CONFIGURATION)"
   framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/${default}\$(EFFECTIVE_PLATFORM_NAME)"
   framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/${default}"
   framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}"
   framework_search_paths="${framework_search_paths} \$(inherited)"

   local query

   if [ "$COMMAND" = "add" ]
   then
      if [ $terse -ne 0 ]
      then
         local mapped
         local i

         echo  "${C_WHITE}-----------------------------------------------------------"  >&2

         #  make these echos easily grabable by stdout
         #     012345678901234567890123456789012345678901234567890123456789
         echo "// Common.xcconfig:"
         echo "DEPENDENCIES_DIR=${dependencies_dir}"
         echo "HEADER_SEARCH_PATHS=${header_search_paths}"
         echo "LIBRARY_SEARCH_PATHS=${library_search_paths}"
         echo "FRAMEWORK_SEARCH_PATHS=${framework_search_paths}"

         local old

         old="${IFS:-" "}"
         IFS="
"
         for i in ${xcode_configurations}
         do
            mapped=`map_configuration "${configurations}" "${i}"`

            echo ""
            echo ""
            #     012345678901234567890123456789012345678901234567890123456789
            echo "// ${i}.xcconfig:"
            echo "#include \"Common.xcconfig\""
            echo "LIBRARY_CONFIGURATION=${mapped}"
         done

         IFS="${old}"
         echo  "-----------------------------------------------------------${C_RESET}"  >&2
      fi

      query="Add ${C_CYAN}\"${DEPENDENCY_SUBDIR}/${LIBRARY_DIR_NAME}\"${C_YELLOW}  and friends to search paths of ${C_MAGENTA}${projectname}${C_YELLOW} ?"
   else
      query="Remove ${C_CYAN}\"${DEPENDENCY_SUBDIR}/${LIBRARY_DIR_NAME}\"${C_YELLOW}  and friends from search paths of ${C_MAGENTA}${projectname}${C_YELLOW} ?"
   fi

   user_say_yes "$query"
   [ $? -eq 0 ] || exit 1


   patch_library_configurations "${xcode_configurations}" "${configurations}" "${project}" "${flag}"

   exekutor mulle-xcode-settings "${flag}" "DEPENDENCIES_DIR" "${dependencies_dir}" "${project}"  || exit 1
   exekutor mulle-xcode-settings "${flag}" "HEADER_SEARCH_PATHS" "${header_search_paths}" "${project}"  || exit 1
   exekutor mulle-xcode-settings "${flag}" "LIBRARY_SEARCH_PATHS" "${library_search_paths}" "${project}"  || exit 1
   exekutor mulle-xcode-settings "${flag}" "FRAMEWORK_SEARCH_PATHS" "${framework_search_paths}" "${project}" || exit 1


   if [ "$COMMAND" = "add" ]
   then
      if [ $terse -ne 0 ]
      then
         #     012345678901234567890123456789012345678901234567890123456789
         echo "${C_WHITE}"
         echo "Hint:"
         echo "If you add a configuration to your project, remember to edit" >&2
         echo "the LIBRARY_CONFIGURATION setting for that configuration." >&2
         echo "" >&2
         echo "You can rerun setup-xcode at later times and it should not" >&2
         echo "unduly duplicate setting contents." >&2
         echo "${C_RESET}" >&2
      fi
   fi
}


main()
{
   log_fluff "::: xcode :::"

   patch_xcode_project "$@"
}


main "$@"