#!/bin/bash

# Copyright (C) 2009-2010 Nokia Corporation. All rights reserved.
#
# 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.


TOOLCHAIN_VERSION="0.2.6"
SELF=${0}
CMD=$( basename ${SELF} )
LOGFILE="/tmp/${CMD}.log"
MAX_WIDTH_DEFAULT=800
MAX_HEIGHT_DEFAULT=1200
MAX_DEPTH=2

YES="yes"
NO="no"
QUERY="query"

INKSCAPE="Inkscape"
INKSCAPE_CMD="inkscape"
IMAGICK="ImageMagick"
IMAGICK_CMD="convert"

VIEW_CMD[1]="eog"
VIEW_CMD[2]="gwenview"
VIEW_CMD[3]="ristretto"
VIEW_CMD[4]="xloadimage"
VIEWER=""

PNG="png"
EPS="eps"

CONVERTER=""
EXT=${PNG}

ROTATE="no"

IS_FILE="null"


function version() {
    echo "${TOOLCHAIN_VERSION}"
}


function usage() {
    [ -z "${1}" ] || (
	echo ${1}
	echo
	)
    cat <<EOF
MaemoDoc toolchain version ${TOOLCHAIN_VERSION} (c) 2009-2010 Nokia Corporation.

Usage:
        ${SELF}  

               --in <input_file>  -  Input filename; only convert a single file
           --inpath <input_path>  -  Input directory; do recursive conversion
                                     to a given depth (see maxdepth)

         --outpath <output_path>  -  Output directory; when doing recursive
                                     conversion, the directory structure
                                     under the input path is preserved

         [ --width <max_width> ]  -  The maximum allowed image width;
                                     defaults to ${MAX_WIDTH_DEFAULT} pixels

       [ --height <max_height> ]  -  The maximum allowed image height;
                                     defaults to ${MAX_HEIGHT_DEFAULT} pixels

              [ --query-rotate ]  -  Ask whether images that would need less
                                     scaling when rotated should be rotated 90 
                                     degrees anticlockwise; rotating images 
                                     works only if ImageMagick is available

                    [ --rotate ]  -  Always rotate images if it means less
                                     scaling

           [ --viewer <viewer> ]  -  Viewer for rotated image previews; tries
                                     to use Eye of Gnome or Gwenview by default

          [ --maxdepth <depth> ]  -  Maximum scan depth; 2 levels by default

             [ --eps ] [ --png ]  -  Convert to EPS, PNG; defaults to PNG

              [ --version | -V ]  -  Show version
                 [ --help | -H ]  -  Show this help

EOF

    exit 42
}


function install() {
    cat<<EOF
    Couldn't find ImageMagick or Inkscape!
    You should be able to install them with apt-get:
      \`apt-get install imagemagick' for ImageMagick and/or
      \`apt-get install inkscape' for Inkscape.
EOF
    exit 42
}


function check_bins() {
    if which ${IMAGICK_CMD} 2>&1 >/dev/null ; then
    # echo "${CMD}: Found ImageMagick."
	CONVERTER=${IMAGICK}
    elif which ${INKSCAPE_CMD} 2>&1 >/dev/null ; then
    # echo "${CMD}: Found Inkscape."
	CONVERTER=${INKSCAPE}
    else
	install
    fi

    if [ -z "${VIEWER}" ] ; then
	for viewer in ${VIEW_CMD[*]} ; do
	    which ${viewer} 2>&1 >/dev/null || continue
	    VIEWER=${viewer}
	    break
	done
    fi
}


function parse_args() {
    while [ ! -z "${1}" ] ; do	
	case ${1} in
	    "--in")
		[ ${IS_FILE} == ${NO} ] && \
		    usage "Can't use both --in and --inpath!"
		IS_FILE=${YES}
		IN_PATH=${2}
		shift 2
		;;

	    "--inpath")
		[ ${IS_FILE} == ${YES} ] && \
		    usage "Can not use both --in and --inpath!"
		IS_FILE=${NO}
		IN_PATH=${2}
		shift 2
		;;
	    
	    "--out")
		OUT_PATH=${2}
		shift 2
		;;
	    
	    "--width")
		MAX_WIDTH=${2}
		shift 2
		;;

	    "--height")
		MAX_HEIGHT=${2}
		shift 2
		;;
	    
	    "--help")
		usage
		;;
	    
	    "-H")
		usage
		;;
	    
	    "-V")
		version
		exit 0
		;;
	    
	    "--version")
		version
		exit 0
		;;
	    
	    "--eps")
		EXT=${EPS}
		shift
		;;
	    
	    "--png")
		EXT=${PNG}
		shift
		;;
	    
	    "--query-rotate")
		if [ ${CONVERTER} != ${IMAGICK} ] ; then
		    echo "! ImageMagick not found, ignoring --query-rotate."
		else
		    ROTATE=${QUERY}
		fi
		shift
		;;

	    "--rotate")
		if [ ${CONVERTER} != ${IMAGICK} ] ; then
		    echo "! ImageMagick not found, ignoring --always-rotate."
		else
		    ROTATE=${YES}
		fi
		shift
		;;

	    "--viewer")
		VIEWER=${2}
		shift 2
		;;

	    "--maxdepth")
		MAX_DEPTH=${2}
		shift 2
		;;
	    
	    *)
		usage "Invalid parameter '${1}'."
		;;
	esac
    done

    [ -z "${IN_PATH}" ] && MISSING="input path"
    [ -z "${OUT_PATH}" ] && MISSING="output path"
    
    [ -z "${MISSING}" ] || usage "${CMD}: Missing ${MISSING}!"
    
    [ -z "${MAX_WIDTH}" ] && MAX_WIDTH=${MAX_WIDTH_DEFAULT}
    [ -z "${MAX_HEIGHT}" ] && MAX_HEIGHT=${MAX_HEIGHT_DEFAULT}
}


function preview_image() {
    if ! which ${VIEWER} 2>&1 >/dev/null ; then
	echo " ! Viewer ${VIEWER} not found, consider using --viewer."
    else
	tmp_image=$( mktemp )
	convert ${input} -rotate 270 ${tmp_image}
	echo " + Starting ${VIEWER}..."
	${VIEWER} ${tmp_image}
    fi
}


function check_rotation() {
    if [ ${ROTATE} == ${YES} ] ; then
	do_rotate=${YES}
    elif [ ${ROTATE} == ${QUERY} ] ; then
	do_rotate="-"
	echo " ? Rotate ${fname}?"
	while ! echo ${do_rotate} | grep -qi "[ynpb]" ; do
	    read -s -p "  (y)es, (N)o, (p)review, (q)uit? " -n 1 do_rotate
	    [ -z "${do_rotate}" ] && do_rotate="n"
	    case ${do_rotate} in
		y|Y) 
		    echo "Yes" 
		    do_rotate=${YES}
		    ;;
		n|N) 
		    echo "No"
		    ;;
		p|P) 
		    echo "Preview"
		    preview_image ${1}
		    do_rotate="-"
		    ;;
		q)
		    echo "Quit"
		    exit 0
		    ;;
		*) 
		    echo "?"
		    do_rotate="-"
		    ;;
	    esac
	done
    else
	do_rotate="n"
    fi
}


function create_dirs() {
    if [ -e ${OUT_PATH} ] ; then    
	if [ ! -d ${OUT_PATH} ] ; then
	    echo "${CMD}: ${OUT_PATH} exists and is not a directory!"
	    exit 42
	elif [ ! -w ${OUT_PATH} ] ; then
	    echo "${CMD}: Cannot write to ${OUT_PATH}!"
	    exit 42
	fi
    else
	echo "* Creating '${OUT_PATH}'"
	if ! mkdir -p ${OUT_PATH} ; then
	    echo "${CMD}: Unable to create ${OUT_PATH}!"
	    exit 42
	fi
    fi
}


function determine_scales() {
    scale_norot_x=$( echo "scale=4 ; ${width} / ${MAX_WIDTH} * 10000" | bc )
    scale_norot_x=${scale_norot_x/.*/}
    scale_norot_y=$( echo "scale=4 ; ${height} / ${MAX_HEIGHT} * 10000" | bc )
    scale_norot_y=${scale_norot_y/.*/}
    scale_norot=${scale_norot_y}
    [ ${scale_norot_x} -gt ${scale_norot_y} ] && scale_norot=${scale_norot_x}

    scale_rot_x=$( echo "scale=4 ; ${height} / ${MAX_WIDTH} * 10000" | bc )
    scale_rot_x=${scale_rot_x/.*/}
    scale_rot_y=$( echo "scale=4 ; ${width} / ${MAX_HEIGHT} * 10000" | bc )
    scale_rot_y=${scale_rot_y/.*/}
    scale_rot=${scale_rot_y}
    [ ${scale_rot_x} -gt ${scale_rot_y} ] && scale_rot=${scale_rot_x}

    if [ ${width} -gt ${MAX_WIDTH} ] || [ ${height} -gt ${MAX_HEIGHT} ] ; then
	too_large=${YES}
    else
	too_large=${NO}
    fi

    rotation_helps=${NO}
    [ ${scale_rot} -lt ${scale_norot} ] && rotation_helps=${YES}
}


function calculate_size() {
    new_width=$( echo "scale=0 ; 10000 * ${width} / ${scale_norot}" | bc )
    new_height=$( echo "scale=0 ; 10000 * ${height} / ${scale_norot}" | bc )
    geometry="${new_width}x${new_height}"
}


function rotate_size() {
    tmpvalue=${height}
    height=${width}
    width=${tmpvalue}
}


function do_conversion() {
    fname=$( basename ${input} )
    width=$( file ${input} | sed -r 's/.*, ([0-9]+) x [0-9]+.*/\1/' )
    height=$( file ${input} | sed -r 's/.*, [0-9]+ x ([0-9]+).*/\1/' )
    [ ! -e "${OUT_PATH}/${fpath}" ] && mkdir -p "${OUT_PATH}/${fpath}"
    output="${OUT_PATH}/${fpath}/${fname%.*}.${EXT}"
    tempfile="/tmp/maemodoc-scaleimage_tmp.${input/*./}"

    determine_scales
    if [ ${too_large} == ${NO} ] ; then
	echo "   Skipping ${fname}"
	continue
    fi

    if [ ${CONVERTER} == ${INKSCAPE} ] ; then
	calculate_size
	params="--export-${EXT}=${output}"
	params="${params} --export-width=${new_width}"
	params="${params} --export-height=${new_height}"
	echo " + Scaling ${fname} to ${geometry}"
	params="${params} --file=${input}"

    elif [ ${CONVERTER} == ${IMAGICK} ] ; then
	if [ ${rotation_helps} == ${YES} ] ; then
	    check_rotation ${input}
	    if [ ${do_rotate} == ${YES} ] ; then		
		echo " + Rotating ${fname} to ${height}x${width}"
		convert ${input} -rotate 270 ${tempfile} 2>&1 1>>${LOGFILE}
		rotate_size
	    fi
	fi

	[ -e ${tempfile} ] || cp ${input} ${tempfile}

	determine_scales
	if [ ${too_large} == ${YES} ] ; then
	    calculate_size
	    echo " + Scaling ${fname} to ${geometry}"
	    convert ${tempfile} -adaptive-resize ${geometry} ${output}
	fi

	[ -e ${output} ] || mv ${tempfile} ${output}
	rm -f ${tempfile}

    else
	echo "${CMD}: Unknown converter '${CONVERTER}'!"
	exit 42
    fi
}





## "Main"

set +u

[ -z "${1}"  ] && usage

check_bins

parse_args ${*}

set -u

create_dirs

rm -f ${LOGFILE} 2>/dev/null

if [ ${IN_PATH} == ${OUT_PATH} ] ; then
    echo "${CMD}: Refusing to overwrite input path!"
    exit 42
fi

fpath="."

echo "* Input path is '${IN_PATH}'."
echo "* Output directory is '${OUT_PATH}.'"
echo "* Maximum image width is '${MAX_WIDTH}'."
echo "* Maximum image height is '${MAX_HEIGHT}'."
[ ${ROTATE} == ${QUERY} ] || echo "* Always rotate suitable images"
echo "* Using ${CONVERTER}"

if [ ${IS_FILE} == ${NO} ] ; then
    for input in $( find ${IN_PATH} -mount -maxdepth ${MAX_DEPTH} | \
	egrep -i "\.(png|jpg|jpeg)$" ) ; do
	if ! file -bi ${input} | egrep -q "^image\/" ; then
	    echo " ! ${input} is not an image!"
	    continue
	fi
	fpath=$( dirname ${input} )
	fpath=${fpath/$IN_PATH/}
	do_conversion
    done
else
    if [ ! -f ${IN_PATH} ] || \
	( ! file -bi ${IN_PATH} | egrep -q "^image\/" ) ; then
	echo "${CMD}: ${IN_PATH} is not an image!"
	exit 42
    fi
    fpath=""
    input=${IN_PATH}
    do_conversion
fi

echo "Done."
