#!/bin/sh

dump_ansi_colors ()
{
    for attr in 0 1 4 5 7 ; do
        echo "----------------------------------------------------------------"
        printf "ESC[%s;Foreground;Background - \n" $attr
        for fore in 30 31 32 33 34 35 36 37; do
            for back in 40 41 42 43 44 45 46 47; do
                printf '\033[%s;%s;%sm %02s;%02s  ' $attr $fore $back $fore $back
            done
        printf '\n'
        done
        printf '\033[0m'
    done
}

ansi_red()
{
    printf '\033[1;31;40m'
}

ansi_purple()
{
    printf '\033[1;34;40m'
}

ansi_clear()
{
    printf '\033[0m'
}

try_run ()
{
    echo `ansi_purple` "[RUN]" `ansi_clear` " $@"
    if ! "$@"; then
        echo `ansi_red` "[ERR]" `ansi_clear` " $@"
    fi
}

run ()
{
    echo `ansi_purple` "[RUN]" `ansi_clear` " $@"
    if ! "$@"; then
        echo `ansi_red` "[ERR]" `ansi_clear` " $@"
        exit 1
    fi
}

dbg_vars () # name
{
    for name in $@; do
        echo "[DBG] $name=\"${!name}\""
    done
}

#-------------------------------------------------------------------------------

product () # NAME VERSION PLATFORM
{
    NAME=$1
    VERSION=$2
    PLATFORM=$3

    PRODUCT=$NAME-$VERSION-$PLATFORM

    HERE_DIR="$(pwd)"

    SOURCES_DIR="$HERE_DIR"
    RELEASE_DIR="$HERE_DIR/release"
    BUILD_DIR="$RELEASE_DIR/builds/$PRODUCT"
    PACKAGES_DIR="$RELEASE_DIR/packages"

    PRODUCT_DIR="$RELEASE_DIR/products/$PRODUCT"
    PRODUCT_INCLUDE_DIR="$PRODUCT_DIR/include"
    PRODUCT_LIBRARY_DIR="$PRODUCT_DIR/lib/$PLATFORM"
    PRODUCT_EXECUTABLE_DIR="$PRODUCT_DIR/bin/$PLATFORM"

    dbg_vars                 \
    NAME                     \
    VERSION                  \
    PRODUCT                  \
    SOURCES_DIR              \
    RELEASE_DIR              \
    BUILD_DIR                \
    PRODUCT_DIR              \
    PRODUCT_INCLUDE_DIR      \
    PRODUCT_LIBRARY_DIR      \
    PRODUCT_EXECUTABLE_DIR
}

build_cleanup ()
{
    run rm -rf "$BUILD_DIR"
}

product_cleanup ()
{
    run rm -rf "$PRODUCT_DIR"
}

product_configuration () # CMAKE_ARG ...
{
    run mkdir -p "$BUILD_DIR"
    run cd       "$BUILD_DIR"

    run cmake "$@" "$SOURCES_DIR"
    run cmake .

    run cd -
}

product_targets () # TARGET ...
{
    run cd  "$BUILD_DIR"

    run make "$@"

    run cd -
}

# FIXME: Make this work. Try and let CMake spit target paths.
cmake_target_path () # TARGET
{
    TARGET=$1
    CMAKE_PATH_SCRIPT="$(mktemp -t $PRODUCT-$TARGET-path.cmake)"

    CAT << EOF > "$CMAKE_PATH_SCRIPT"
get_property(TARGET_LOCATION TARGET ${TARGET} PROPERTY LOCATION)
message("\${TARGET_LOCATION}")
EOF

    CMAKE_CACHE_SCRIPT="$(mktemp -t $PRODUCT-$TARGET-cache.cmake)"

    cat "$BUILD_DIR/CMakeCache.txt" \
    | awk 'BEGIN { FS = "[=:]" } ; /^[-_[:alnum:]]+:[-_[:alnum:]]+=.*$/ { print "SET(" $1 " \"" $3 "\" CACHE " $2 " \"\")" }' \
    > "$CMAKE_CACHE_SCRIPT"

#    cat "${CMAKE_CACHE_SCRIPT}"
#    exit

    run cmake -C "$CMAKE_CACHE_SCRIPT" -P "$CMAKE_PATH_SCRIPT" "$BUILD_DIR"
}

product_libraries () # LIBRARY ...
{
    run mkdir -p "$PRODUCT_LIBRARY_DIR"

    for LIBRARY in "$@"; do
        run cp -a "$LIBRARY" "$PRODUCT_LIBRARY_DIR"
    done
}

product_executables () # EXECUTABLE ...
{
    run mkdir -p "$PRODUCT_EXECUTABLE_DIR"

    for EXECUTABLE in "$@"; do
        run cp -a "$EXECUTABLE" "$PRODUCT_EXECUTABLE_DIR"
    done
}

product_applications () # APPLICATION ...
{
    run mkdir -p "$PRODUCT_DIR"

    for APPLICATION in "$@"; do
        name="$(basename $APPLICATION)"
        run rsync -avL "$APPLICATION/" "$PRODUCT_DIR/$name/"
    done
}

product_dmg ()
{
    run rm -rf "$PACKAGES_DIR/$PRODUCT"
    run mkdir -p "$PACKAGES_DIR/$PRODUCT/$NAME"
    run rsync -avl "$PRODUCT_DIR/" "$PACKAGES_DIR/$PRODUCT/$NAME"
    run cd "$PACKAGES_DIR/$PRODUCT"
    run ln -s /Applications .
    run cd "$PACKAGES_DIR"
    run zip --symlinks -r "${PRODUCT}.zip" "$PRODUCT"
}

product_zip ()
{
    run mkdir -p "$PACKAGES_DIR"

    run rm -f $PRODUCT.zip
    run cd "$PRODUCT_DIR"
    run zip -r "$RELEASE_DIR"/$PRODUCT.zip .
    run cd -
}

#-------------------------------------------------------------------------------

copy_rgbdemo_libraries()
{
    run mkdir -p "$PRODUCT_DIR"/Common/Contents/MacOS

    run cd "$PRODUCT_DIR"/Common/Contents/MacOS

    # FIXME: Do not blindly copy ALL of the built dynamic libraries, but only rgbdemo ones instead.
    # FIXME: OpenNI module paths are referenced from a dynamically generated configuration file and MUST be placed next to the program executable, (instead of in Contents/Plugins) for now.
    run cp -a "$BUILD_DIR"/lib/*.dylib .

    for bin in *.dylib; do
        for lib in *.dylib; do
            run install_name_tool -id @executable_path/$lib $bin
            run install_name_tool -change "$BUILD_DIR"/lib/$lib @executable_path/$lib $bin
            run install_name_tool -change                  $lib @executable_path/$lib $bin
            run install_name_tool -change /usr/local/Cellar/jpeg/8c/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
            run install_name_tool -change /usr/local/Cellar/jpeg/8b/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
        done
    done

    run cd -

    run mkdir -p "$PRODUCT_DIR"/Common/Contents/Frameworks

    run cd "$PRODUCT_DIR"/Common/Contents/Frameworks

    USR_LIBS="\
        libbz2.1.0.dylib \
        libz.1.dylib \
        libflann_cpp.1.6.dylib \
        libboost_date_time-mt.dylib \
        libboost_filesystem-mt.dylib \
        libboost_system-mt.dylib \
        libboost_thread-mt.dylib \
        libboost_iostreams-mt.dylib \
        libcminpack.1.1.3.dylib \
    "

    for usr_lib in $USR_LIBS; do
        run cp /usr/lib/$usr_lib .
    done

    OPENCV_VERSION=2.3

    USR_LOCAL_LIBS="\
        libjpeg.8.dylib \
        libqhull6.dylib \
        libpcl_io.1.4.dylib \
        libpcl_octree.1.4.dylib \
        libpcl_surface.1.4.dylib \
        libpcl_registration.1.4.dylib \
        libpcl_features.1.4.dylib \
        libpcl_filters.1.4.dylib \
        libpcl_segmentation.1.4.dylib \
        libpcl_kdtree.1.4.dylib \
        libpcl_sample_consensus.1.4.dylib \
        libpcl_keypoints.1.4.dylib \
        libpcl_range_image_border_extractor.1.4.dylib \
        libpcl_range_image.1.4.dylib \
        libpcl_common.1.4.dylib \
        libpcl_search.1.4.dylib \
        libpcl_visualization.1.4.dylib \
        libpcl_tracking.1.4.dylib \
        libopencv_calib3d.$OPENCV_VERSION.dylib \
        libopencv_contrib.$OPENCV_VERSION.dylib \
        libopencv_core.$OPENCV_VERSION.dylib \
        libopencv_features2d.$OPENCV_VERSION.dylib \
        libopencv_flann.$OPENCV_VERSION.dylib \
        libopencv_gpu.$OPENCV_VERSION.dylib \
        libopencv_highgui.$OPENCV_VERSION.dylib \
        libopencv_imgproc.$OPENCV_VERSION.dylib \
        libopencv_legacy.$OPENCV_VERSION.dylib \
        libopencv_ml.$OPENCV_VERSION.dylib \
        libopencv_objdetect.$OPENCV_VERSION.dylib \
        libopencv_video.$OPENCV_VERSION.dylib \
        vtk-5.8/libvtkHybrid.5.8.dylib \
        vtk-5.8/libvtkRendering.5.8.dylib \
        vtk-5.8/libvtkVolumeRendering.5.8.dylib \
        vtk-5.8/libvtkWidgets.5.8.dylib \
        vtk-5.8/libvtkGraphics.5.8.dylib \
        vtk-5.8/libvtkverdict.5.8.dylib \
        vtk-5.8/libvtkImaging.5.8.dylib \
        vtk-5.8/libvtkfreetype.5.8.dylib \
        vtk-5.8/libvtkIO.5.8.dylib \
        vtk-5.8/libvtkFiltering.5.8.dylib \
        vtk-5.8/libvtkCommon.5.8.dylib \
        vtk-5.8/libvtksys.5.8.dylib \
        vtk-5.8/libvtkDICOMParser.5.8.dylib \
        vtk-5.8/libvtkNetCDF.5.8.dylib \
        vtk-5.8/libvtkNetCDF_cxx.dylib \
        vtk-5.8/libvtkmetaio.5.8.dylib \
        vtk-5.8/libvtksqlite.5.8.dylib \
        vtk-5.8/libvtkpng.5.8.dylib \
        vtk-5.8/libvtkzlib.5.8.dylib \
        vtk-5.8/libvtkjpeg.5.8.dylib \
        vtk-5.8/libvtktiff.5.8.dylib \
        vtk-5.8/libvtkexpat.5.8.dylib \
        vtk-5.8/libvtkftgl.5.8.dylib \
        vtk-5.8/libvtkexoIIc.5.8.dylib \
    "

    for usr_local_lib in $USR_LOCAL_LIBS; do
        run cp /usr/local/lib/$usr_local_lib .
    done

    OTHER_LIBS="\
        /usr/X11/lib/libpng12.0.dylib \
        /usr/local/Cellar/libtiff/3.9.5/lib/libtiff.3.dylib \
        /usr/local/Cellar/jasper/1.900.1/lib/libjasper.1.dylib"

    for other_lib in $OTHER_LIBS; do
        run cp $other_lib .
    done

    run chmod -R u+w .

    # Boost and pcl libraries have braindead install names that requires fixing.
    for bin in *.dylib; do
        try_run install_name_tool -change /usr/local/Cellar/jpeg/8c/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
        try_run install_name_tool -change /usr/local/Cellar/jpeg/8b/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
	try_run install_name_tool -change /usr/local/lib/libqhull6.6.2.0.1385.dylib @executable_path/../Frameworks/libqhull6.dylib $bin
        try_run install_name_tool -change /usr/lib/libcminpack.1.1.3.dylib @executable_path/../Frameworks/libcminpack.1.1.3.dylib $bin

	for lib in QtGui QtCore QtNetwork QtOpenGL QtSvg QtXml QtTest; do
            try_run install_name_tool -change ${lib}.framework/Versions/4/${lib} @executable_path/../Frameworks/${lib}.framework/Versions/4/${lib} $bin
	done

        for lib in *.dylib; do
            try_run install_name_tool -id                         @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change $lib                @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change lib/$lib            @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /opt/local/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/lib/$lib       @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/vtk/5.8.0/lib/vtk-5.8/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/X11/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/libtiff/3.9.5/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/jasper/1.900.1/lib/$lib @executable_path/../Frameworks/$lib $bin
        done
    done

    # For some reasons QtOpenGL does not get copied by macdeployqt
    for lib in QtOpenGL QtSvg QtTest; do
	run mkdir -p ${lib}.framework/Versions/4
	run cp -r /Library/Frameworks/${lib}.framework/Versions/4/${lib} ${lib}.framework/Versions/4/${lib}
	run install_name_tool -id @executable_path/../Frameworks/${lib}.framework/Versions/4/${lib} ${lib}.framework/Versions/4/${lib}
    done

    for dest in QtOpenGL QtSvg QtTest; do
	for lib in QtCore QtGui; do
	    run install_name_tool -change ${lib}.framework/Versions/4/$lib @executable_path/../Frameworks/${lib}.framework/Versions/4/${lib} ${dest}.framework/Versions/4/${dest}
	done
    done

    run cd -
}

link_rgbdemo_libraries()
{
    run mkdir -p "$PRODUCT_DIR"/"$@".app/Contents/MacOS

    run cd "$PRODUCT_DIR"/"$@".app/Contents/MacOS

    for lib in ../../../Common/Contents/MacOS/*.dylib; do
	ln -s $lib .
    done

    for bin in ../MacOS/"$@"; do
        for lib in *.dylib; do
            run install_name_tool -change "$BUILD_DIR"/lib/$lib @executable_path/$lib $bin
            run install_name_tool -change                  $lib @executable_path/$lib $bin
        done
	run install_name_tool -change ../../Bin/x86-Release/libOpenNI.dylib @executable_path/libOpenNI.dylib $bin
    done

    run cd -

    run cd "$PRODUCT_DIR"/"$@".app/Contents

    run ln -s ../../Common/Contents/Frameworks .

    run cd Frameworks

    # Boost and pcl libraries have braindead install names that requires fixing.
    for bin in "$PRODUCT_DIR"/"$@".app/Contents/MacOS/"$@"; do
        try_run install_name_tool -change /usr/local/Cellar/jpeg/8c/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
        try_run install_name_tool -change /usr/local/Cellar/jpeg/8b/lib/libjpeg.8.dylib @executable_path/../Frameworks/libjpeg.8.dylib $bin
	try_run install_name_tool -change /usr/local/lib/libqhull6.6.2.0.1385.dylib @executable_path/../Frameworks/libqhull6.dylib $bin
        try_run install_name_tool -change /usr/lib/libcminpack.1.1.3.dylib @executable_path/../Frameworks/libcminpack.1.1.3.dylib $bin

	for lib in QtGui QtCore QtNetwork QtOpenGL QtSvg QtXml QtTest; do
            try_run install_name_tool -change ${lib}.framework/Versions/4/${lib} @executable_path/../Frameworks/${lib}.framework/Versions/4/${lib} $bin
	done

        for lib in *.dylib; do
            try_run install_name_tool -id                         @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change $lib                @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change lib/$lib            @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /opt/local/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/lib/$lib       @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/vtk/5.8.0/lib/vtk-5.8/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/X11/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/libtiff/3.9.5/lib/$lib @executable_path/../Frameworks/$lib $bin
            try_run install_name_tool -change /usr/local/Cellar/jasper/1.900.1/lib/$lib @executable_path/../Frameworks/$lib $bin
        done
    done

    run cd -
}

copy_rgbdemo_resources()
{
    run mkdir -p ${PRODUCT_DIR}/"$@".app/Contents/Resources

    run cd ${PRODUCT_DIR}/"$@".app/Contents/Resources

    # run cp ${SOURCES_DIR}/apps/skanect/skanect.icns .

    run cd -
}

#-------------------------------------------------------------------------------

product RGBDemo 0.7.0 Darwin

#skip()
{

#build_cleanup

# FIXME: When specifying explicit target universal binary architectures,
# CMake adds the -isysroot GCC flag for the current MacOSX SDK.
# This makes <SDK_PATH>/usr/include shadow /usr/include, thus removing
# custom-installed libraries (namely: pcl dependencies) from the include
# search paths.
# For now, just build for the default architecture.
#    -DCMAKE_OSX_ARCHITECTURES:STRING=i386;x86_64 \

products_configuration \
    -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_MACOSX_BUNDLE:BOOL=TRUE \
    -DNESTK_USE_PCL:BOOL=TRUE \

# FIXME: Because rgbdemo does not depend on dynamically loaded OpenNI modules, all targets must be built, so that the following copy operation can succeed:
# cp release/builds/rgbdemo-0.7.0-macosx-x64/bin/lib{nimCodecs,nimMockNodes,nimRecorder,XnDevicesSensorV2,XnDeviceFile,XnVFeatures,XnVHandGenerator}.dylib release/products/rgbdemo-0.7.0-macosx-x64/skanect.app/Contents/MacOS
product_targets       \
    all               \
    glew              \
    glview            \
    OpenNI            \
    nimCommon         \
    nimCodecs         \
    nimMockNodes      \
    nimRecorder       \
    XnCore            \
    XnFormats         \
    XnDDK             \
    XnDeviceFile      \
    XnDevicesSensorV2
}

product_cleanup

apps="rgbd-viewer \
      rgbd-reconstructor \
      rgbd-multikinect \
      rgbd-people-tracker \
      rgbd-scan-markers \
      rgbd-scan-topview \
      rgbd-skeletor \
      calibrate-kinect-ir \
      calibrate-openni-intrinsics \
      calibrate-projector \
      calibrate-multiple-kinects \
      "

copy_rgbdemo_libraries

for app in $apps; do 
    product_applications ${BUILD_DIR}/bin/${app}.app
    link_rgbdemo_libraries $app
    run macdeployqt ${PRODUCT_DIR}/${app}.app
done

copy_rgbdemo_resources

#product_zip

product_dmg
