#!/bin/ksh
myself=${0##*/}
DESC='Show change log or file diff between GEM versions'
USAGE="USAGE: ${myself##*/} [-h] [-v] \\ \n
       \t [--log | --filelist | --version | --diff [DIFF_TOOL] | --dirdiff [DIFF_TOOL] ] \\ \n 
       \t [--all] \\ \n
       \t [--dyn] \\ \n
       \t [--phy] \\ \n
       \t [--utils] \\ \n
       \t [--scripts]  \\ \n
       \t [--local]  \\ \n
       \t VERSION [VERSION2]"
GITDEPOTBASE=~armnenv/GitDepots
#BNDLBASE=/home/ordenv/ssm-domains/ssm-setup-1.0/dot-profile-setup_1.0_multi/notshared/data/ssm_domains
BNDLBASE=~armnenv/SsmBundles
#BNDLBASE=~armnsch/SsmBundles

#---- Functions ------------------------------------------------------
#====
usage_long() {
	 toto=$(echo -e $USAGE)
	 more <<EOF
$DESC

$toto

Options:
    -h, --help : print this help

    --diff     : [default] iteratively show the diff of all different files
                 cannot be mixed with other modes 
                 (--dirdiff, -- filelist, --log, --version)
    --dirdiff  : show the directory diff
                 cannot be mixed with other modes 
                 (--diff, -- filelist, --log, --version)
    --filelist : list the files that were changed and/or renamed
    --log      : list the log messages of all commits between the 2 versions
    --version  : print version numbers

    --all      : [default] show diff, log or filelist of all components
    --dyn      : show diff, log or filelist of gemdyn files
    --phy      : show diff, log or filelist of rpnphy files
    --utils    : show diff, log or filelist of modelutiles files
    --scripts  : show diff, log or filelist of gem-scripst files

    --local    : consider local modifications in the comparison
                 A 3way diff is done if kdiff3 is provided,
                 otherwise only the first provided model version is compared
                 (--log mode is not available with this option)

    VERSION    : version to compare against (e.g. GEM/4.2.0)
    VERSION2   : 2nd version in the comparison (present version if not provided)

    For --diff and --dirdiff modes, 
    1) a diff tool can be specified as argument (e.g. xxdiff, kdiff3, ...)
       if not provided it default to the value of the env var ECDIFF
       or to the basic text diff is used
       (e.g. export ECDIFF=xxdiff)
    2) diff arguments can be provided by setting them in 
       the ECDIFFARGS env var
       (e.g. export ECDIFFARGS="-wB")

    For --diff, --filelist modes, since they use "git", 
    "git diff" options can be set in the GITDIFFARGS env var, 
    default added options are "-M -C" (detect renamed and copied files)
    (e.g. export GITDIFFARGS="-b -w --stat")

EOF
}

#====
is_bundle() {
	 _gemversion=$1
    _isfile="$(ls -d $BNDLBASE/${_gemversion}.bndl 2>/dev/null)"
    if [[ x${_isfile} == x ]] ; then
	    _gemversion=GEM/$1
       _isfile="$(ls -d $BNDLBASE/${_gemversion}.bndl 2>/dev/null)"
    fi
    if [[ x${_isfile} == x ]] ; then
	    _gemversion=GEM/x/$1
       _isfile="$(ls -d $BNDLBASE/${_gemversion}.bndl 2>/dev/null)"
    fi
    if [[ x${_isfile} == x ]] ; then
	    _gemversion=''
    elif [[ ! -r ${_isfile} ]] ; then
	    _gemversion=''
    fi
    echo $_gemversion
}

#====
get_versions() {
	 _bndlno=x${1:-1}
	 _component=${2:-gemdyn}
    if [[ $_bndlno == x1 ]] ; then
       _bndllist="$mygembndl1list"
    else
       _bndllist="$mygembndl2list"
    fi
    _version="$(echo $_bndllist | tr ' ' '\n' | grep /${_component}_)"
    _atform="$(echo $_bndllist | tr ' ' '\n' | grep @ | grep /${_component})"
    if [[ x${_version} == x && x${_atform} != x ]] ; then
       _version="$(echo ${_atform%%@*})"
    fi
    [[ x${_version} == x ]] && _version="$(echo $_bndllist | tr ' ' '\n' | grep /${_component})"
	 _version="$(echo ${_version##*/})"
    _version=${_version#*_}
    _version=${_version%_*}
    if [[ x${_version} == x ]] ; then
       _gemdom="$(echo $_bndllist | tr ' ' '\n' | grep /gem_)"
       _version="$(ls -1d ${_gemdom}/etc/ssm.d/published/* | grep /${_component} | grep all)"
       [[ x${_version} == x ]] && _version="$(ls -1d ${_gemdom}/etc/ssm.d/published/* | grep /${_component} | grep multi)"
       _version=${_version##*/}
       _version="$(echo ${_version} | cut -d_ -f2)"
    fi
	 echo ${_version}
}

#====
get_buildlib_versions() {
	 _bndlno=${1:-1}
	 _component=$2
    _gemdynversion=$3
    _gemdynsrcpath=$(get_src_path ${_bndlno} gemdyn src ${_gemdynversion})
    _utilsversion=$4
    _utilssrcpath=$(get_src_path ${_bndlno} modelutils src ${_utilsversion})
    _version="$(cat ${_utilssrcpath}/include/recettes | grep ^${_component}  | grep '=' | cut -d= -f2 | tr '()' '{}')"
    if [[ x${_version} == x ]] ; then
       _version="$(cat ${_gemdynsrcpath}/include/build_components | grep ${_component} | grep '=' | cut -d= -f2 | tr '()' '{}')"
    fi
    _gemversion=$mygembndl1
    [[ x$_bndlno == x2 ]] && _gemversion=$mygembndl2
    [[ x$ATM_MODEL_BNDL == x$_gemversion ]] && _version=$(eval "echo ${_version}")
	 echo ${_version}
}


#====
get_compiler() {
	 _bndlno=x${1:-1}
    if [[ $_bndlno == x1 ]] ; then
       _bndllist="$mygembndl1list"
    else
       _bndllist="$mygembndl2list"
    fi
    _component=pgi
    _path="$(echo $_bndllist | tr ' ' '\n' | grep -i /${_component})"
    if [[ x${_path} == x ]] ; then
       _component=xlf
       _path="$(echo $_bndllist | tr ' ' '\n' | grep -i /${_component})"
    fi
	 _version="$(echo ${_path##*/})"
    _version="$(echo ${_version} | sed 's/\.sh$//')"
    echo ${_version}
}

#====
get_src_path(){
	 _bndlno=${1:-1}
	 _component=$2
    _srcorbin=${3:-src}
    _version=$4
    [[ x$_version == x ]] && _version="$(get_versions $_bndlno ${_component})"
    _dom=__NO-SUCH-DIR__
    for mysubdir in \
       GEM/d/x \
       ENV/d/x \
       GEM/d/x/${_component} \
       ENV/d/x/${_component} \
       GEM/d/${_component} \
       ENV/d/${_component} ; do
       if [[ -d ${BNDLBASE}/${mysubdir}/${_component}_${_version} ]] ; then
          _dom=${mysubdir}/${_component}_${_version}
          break
       elif [[ -d ${BNDLBASE}/${mysubdir}/${_component}/${_version} ]]; then 
          _dom=${mysubdir}/${_component}/${_version}
          break
       fi
    done
    echo $(ls -d ${BNDLBASE}/${_dom}/${_component}_${_version}_all/${_srcorbin} 2>/dev/null)
}

#====
echocol() {
	 _nbcol=$1
	 _str=${2:-' '}

	 _len="$(echo ${_str}| wc -c)"
	 #let _nbcol=$_nbcol-$_len
    _nbcol=$((_nbcol-_len))
	 myspace=""
	 while [[ _nbcol -gt 0 ]] ; do
		  myspace="$myspace "
		  let _nbcol=$_nbcol-1
	 done
	 echo "${_str}$myspace"
}


#====
domydiff() {
	 _component=$1
	 _ver1=$2
	 _ver2=$3
	 _srcorbin=$4
	 cd $GITDEPOTBASE/${_component}.git
	 echo -e "#=============================================================="
	 echo -e "#$(echocol 18 GEM_BUNDLE) $(echocol 18 $mygembndl1) $mygembndl2"
	 echo -e "#$(echocol 18 ${_component}) $(echocol 18 ${_ver1}) ${_ver2}"
	 echo -e "#--------------------------------------------------------------"
	 echo -e "#PATH to ${_component}_${_ver1} src: $(get_src_path 1 ${_component} ${_srcorbin} ${_ver1})"
	 echo -e "#PATH to ${_component}_${_ver2} src: $(get_src_path 2 ${_component} ${_srcorbin} ${_ver2})"

    _filelist="$(git diff --name-only --text -M -C ${GITDIFFARGS} ${_component}_${_ver1} ${_component}_${_ver2})"
    if [[ "x$_filelist" == "x" ]] ; then
       echo -e "#$(echocol 18 ----------) No Changed File"
	 echo -e "#=============================================================="
       return 0
    fi

	 if [[ x$mylog == x1 ]] ; then
		  echo -e "#---- Change Log ----------------------------------------------"
		  #git log --summary --reverse ${_component}_${_ver1}...${_component}_${_ver2}
		  git log --reverse --pretty=medium ${_component}_${_ver1}...${_component}_${_ver2} | grep -v '^commit'
	 fi
	 if [[ x$myfilelist == x1 ]] ; then
		  echo -e "#---- Changed Files -------------------------------------------"
		  #git diff --name-only --text -M -C ${GITDIFFARGS} ${_component}_${_ver1} ${_component}_${_ver2}
        echo -e $_filelist | tr ' ' '\n'
	 fi
	 if [[ x$mydiff != x ]] ; then
		  echo -e "#---- Diff of Files -------------------------------------------"
		  export ECDIFF=$mydiff
		  export ECDIFFARGS=${ECDIFFARGS:-""}
		  export GITDIFFARGS="${GITDIFFARGS:-''} --text -M -C"
		  export GITDIFFARFG="${GITDIFFARGS}"
		  #if [[ x$mydiff == xdiff ]] ; then
		  #		git diff ${GITDIFFARGS} ${_component}_${_ver1} ${_component}_${_ver2}
		  #else
				r.gitdiff --${mydiff} ${_component}_${_ver1} ${_component}_${_ver2}
		  #fi
	 fi

	 if [[ x$mydirdiff != x ]] ; then
		  echo -e "#---- Dir Diff ------------------------------------------------"
		  export ECDIFF=$dirmydiff
		  export ECDIFFARGS=${ECDIFFARGS:-""}
		  _src1=$(get_src_path 1 ${_component} ${_srcorbin} ${_ver1})
		  _src2=$(get_src_path 2 ${_component} ${_srcorbin} ${_ver2})
		  echo ${mydirdiff} ${ECDIFFARGS} ${_src1} ${_src2}
		  ${mydirdiff} ${ECDIFFARGS} ${_src1}  ${_src2}
	 fi
	 
	 echo -e "#=============================================================="
}

#====
localdiff() {
	 _extlist='*.ftn *.ftn90 *.cdk *.cdk90 *.c *.h *.hf *.fh *.inc'
	 _basedir=$TMPDIR/gemdiff$$
	 _dirlocal=${_basedir}/local
	 _dirmodel1=${_basedir}/$mygembndl1
	 _dirmodel2=${_basedir}/$mygembndl2
	 mkdir -p ${_dirlocal}
	 mkdir -p ${_dirmodel1}
	 mkdir -p ${_dirmodel2}
	 _localfiles="$(ls ${_extlist} 2>/dev/null)"
	 _here=$(pwd)
	 _dynpath1=$(get_src_path 1 gemdyn src $gemdyn1)
	 _phypath1=$(get_src_path 1 rpnphy src $rpnphy1)
	 _utilspath1=$(get_src_path 1 modelutils src $utils1)
	 if [[ x$mygembndl2 != x ]] ; then 
       _dynpath2=$(get_src_path 2 gemdyn src $gemdyn2)
	    _phypath2=$(get_src_path 2 rpnphy src $rpnphy2)
	    _utilspath2=$(get_src_path 2 modelutils src $utils2)
    fi
	 for _item in ${_localfiles} ; do
		  ln -s ${_here}/$_item ${_dirlocal}/$_item

		  if [[ x$mydyn == x1 ]] ; then
				cd $_dynpath1
				mylist="$(\ls $_item */$_item 2>/dev/null)"
				if [[ x$mylist != x ]] ; then
					 for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel1}/${_item2##*/} ; done
				fi
		  fi
		  if [[ x$myphy == x1 ]] ; then
				cd $_phypath1
				mylist="$(\ls $_item */$_item 2>/dev/null)"
				if [[ x$mylist != x ]] ; then
					 for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel1}/${_item2##*/} ; done
				fi
		  fi
		  if [[ x$myutils == x1 ]] ; then
				cd $_utilspath1
				mylist="$(\ls $_item */$_item 2>/dev/null)"
				if [[ x$mylist != x ]] ; then
					 for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel1}/${_item2##*/} ; done
				fi
		  fi

		  if [[ x$mygembndl2 != x$mygembndl1 && x$mygembndl2 != x ]] ; then
				if [[ x$mydyn == x1 ]] ; then
					 cd $_dynpath2
					 mylist="$(\ls $_item */$_item 2>/dev/null)"
					 if [[ x$mylist != x ]] ; then
						  for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel2}/${_item2##*/} ; done
					 fi
				fi
				if [[ x$myphy == x1 ]] ; then
					 cd $_phypath2
					 mylist="$(\ls $_item */$_item 2>/dev/null)"
					 if [[ x$mylist != x ]] ; then
						  for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel2}/${_item2##*/} ; done
					 fi
				fi
				if [[ x$myutils == x1 ]] ; then
					 cd $_utilspath2
					 mylist="$(\ls $_item */$_item 2>/dev/null)"
					 if [[ x$mylist != x ]] ; then
						  for _item2 in $mylist ; do ln -sf $(pwd)/$_item2 ${_dirmodel2}/${_item2##*/} ; done
					 fi
				fi
		  else
				mygembndl2=''
				_dirmodel2=''
		  fi
	 done

	 cd ${_basedir}
	 echo -e "#=============================================================="
	 echo -e "#$(echocol 18 GEM_BUNDLE) $(echocol 18 $mygembndl1) $(echocol 18 $mygembndl2) local"

    if [[ "x${_localfiles}" == x ]] ; then
       echo -e "#$(echocol 18 ----------) No local modifications"
	    echo -e "#=============================================================="
       return 0
    fi

	 if [[ x$myfilelist == x1 ]] ; then
		  #[[ x$mygembndl2 != x ]] && mydiff=diff3
		  echo -e "#---- Locally Changed Files -----------------------------------"
		  for item in ${_localfiles} ; do
				#ls local/$item $mygembndl1/$item
				if [[ ! -e $mygembndl1/$item ]] ; then
					 echo -e "new file: $item"
				elif [[ "x$(diff -q local/$item $mygembndl1 2>/dev/null)" != "x" ]] ; then
					 echo -e "modified: $item"
				else
					 echo -e "same file: $item"					 
				fi
				#diff -q local/$item $mygembndl1 $mygembndl2
		  done
	 fi

	 if [[ x$mydiff != x ]] ; then
		  #[[ x$mydiff != xkdiff3 && x$mydiff != xdiff3 ]] && mygembndl2=''
		  #echo -e "#---- Diff of Locally Changed Files ---------------------------"
		  #for item in ${_localfiles} ; do
		  #		if [[ ! -e $mygembndl1/$item && ! -e $mygembndl2/$item ]] ; then
		  #			 echo -e "new file: $item"
		  #		else
		  #			 echo $mydirdiff ${ECDIFFARGS} $mygembndl1/$item $mygembndl2 local
		  #			 $mydiff ${ECDIFFARGS} $mygembndl1/$item $mygembndl2 local
		  #		fi
		  #done
		  mydirdiff=$mydiff
	 fi

	 if [[ x$mydirdiff != x ]] ; then
		  [[ x$mydirdiff != xkdiff3 && x$mydirdiff != xdiff3 ]] && mygembndl2=''
		  echo -e "#---- Local Dir Diff ------------------------------------------"
		  echo $mydirdiff ${ECDIFFARGS} $mygembndl1 $mygembndl2 local
		  $mydirdiff ${ECDIFFARGS} $mygembndl1 $mygembndl2 local
	 fi

	 echo -e "#=============================================================="
}


#---- Inline Options -------------------------------------------------
mydiff="${ECDIFF:-diff}"
mydirdiff=""
myfilelist=0
mylog=0
myversion=0
myall=1
mydyn=0
myphy=0
myutils=0
myscripts=0
mylocal=0
mygembndl1=""
mygembndl2=""
previous=""
while [[ $# -gt 0 ]] ; do
    case $1 in
        (-h|--help) usage_long; exit 0;;
		  (--diff) [[ x$(echo $2 | cut -c1) != x- && \
           x$(echo $2 | cut -c1) != x && \
           x$(echo $2 | cut -c1-3) != xGEM ]] && \
           mydiff=$2 && shift ;;
		  (--dirdiff) mydiff=""; mydirdiff="${ECDIFF:-diff}" ; \
           [[ x$(echo $2 | cut -c1) != x- && \
           x$(echo $2 | cut -c1) != x && \
           x$(echo $2 | cut -c1-3) != xGEM ]] && \
           mydirdiff=$2 && shift ;;
		  (--filelist) mydiff=""; myfilelist=1 ;;
		  (--log) mydiff=""; mylog=1 ;;
		  (--version) mydiff=""; myversion=1 ;;
		  (--all) myall=1 ;;
		  (--dyn) myall=0; mydyn=1 ;;
		  (--phy) myall=0; myphy=1 ;;
		  (--utils) myall=0; myutils=1 ;;
		  (--scripts) myall=0; myscripts=1 ;;
		  (--local) mylocal=1 ;;
        -*) echo "ERROR: Unrecognized option $1"
            echo -e $USAGE
            echo "---- ABORT ----"
            exit 1;;
        *)  [[ x$mygembndl1 != x ]] && mygembndl2=$1 ; [[ x$mygembndl1 == x ]] && mygembndl1=$1 ;;
    esac
	 previous=$1
    shift
done

[[ x$mygembndl1 == x ]] && mygembndl1=${ATM_MODEL_BNDL}

mygembndl1b=$(is_bundle $mygembndl1)
if [[ x$mygembndl1b == x ]] ; then
	 echo "ERROR: GEM bundle $mygembndl1 Not Found"
	 echo -e $USAGE
	 echo "---- ABORT ----"
	 exit 1  	 
fi
mygembndl1=$mygembndl1b

[[ x$mygembndl2 == x ]] && mygembndl2=$mygembndl1 && mygembndl1=${ATM_MODEL_BNDL}
[[ x$mygembndl2 == x$mygembndl1 ]] && mygembndl2=''

if [[ x$mygembndl1 == x ]] ; then
	 echo "ERROR: You Need to Provide at least one VERSION (e.g. GEM/4.2.0)"
	 echo -e $USAGE
	 echo "---- ABORT ----"
	 exit 1  	 
fi

if [[ x$mygembndl2 == x ]] ; then
	if [[ "x${myfilelist}${mylog}${mydiff}${mydirdiff}" != "x00" && x$mylocal == x0 ]] ; then
		echo "ERROR: You need to specify 2 versions"
		echo -e $USAGE
		echo "---- ABORT ----"
		exit 1  	 
	fi
fi

if [[ x$mygembndl2 != x ]] ; then
   mygembndl2b=$(is_bundle $mygembndl2)
   if [[ x$mygembndl2b == x ]] ; then
	   echo "ERROR: GEM bundle $mygembndl2 Not Found"
	   echo -e $USAGE
	   echo "---- ABORT ----"
	   exit 1
   fi
   mygembndl2=$mygembndl2b
   [[ x$mygembndl2 == x$mygembndl1 ]] && mygembndl2=''
fi


if [[ x$myall = x1 ]] ; then
	 mydyn=1
	 myphy=1
	 myutils=1
	 myscripts=1
fi

#---------------------------------------------------------------------
defmylist() {
mygembndl1list="$(s.resolve_ssm_shortcuts $mygembndl1 2>/dev/null | grep -v '++' | grep -v Prepend)" #grep -v @${_gemversion} | 
[[ x$mygembndl2 != x ]] && mygembndl2list="$(s.resolve_ssm_shortcuts $mygembndl2 2>/dev/null | grep -v '++' | grep -v Prepend)" #grep -v @${_gemversion} | 
}
#time \
defmylist

setmyversions() {
gdata1=$(get_versions 1 gem-data)
gemdyn1=$(get_versions 1 gemdyn)
rpnphy1=$(get_versions 1 rpnphy)
utils1=$(get_versions 1 modelutils)
gemscripts1=$(get_versions 1 gem-scripts)
vgrid1=$(get_versions 1 vgrid)
rmn1=$(get_buildlib_versions 1 RMN_VERSION $gemdyn1 $utils1)
comm1=rpn_comm$(get_buildlib_versions 1 COMM_VERSION $gemdyn1 $utils1)
compil1=$(get_compiler 1)
if [[ x$mygembndl2 != x ]] ; then
   gdata2=$(get_versions 2 gem-data)
   gemdyn2=$(get_versions 2 gemdyn)
   rpnphy2=$(get_versions 2 rpnphy)
   utils2=$(get_versions 2 modelutils)
   gemscripts2=$(get_versions 2 gem-scripts)
   vgrid2=$(get_versions 2 vgrid)
   rmn2=$(get_buildlib_versions 2 RMN_VERSION $gemdyn2 $utils2)
   comm2=rpn_comm$(get_buildlib_versions 2 COMM_VERSION $gemdyn2 $utils2)
   compil2=$(get_compiler 2)
fi
}
#time \
setmyversions

if [[ x$myversion == x1 ]] ; then
	 echo -e "#=============================================================="
	 echo -e "#GEM_BUNDLE  $(echocol 18 $mygembndl1) $mygembndl2"
	 echo -e "#--------------------------------------------------------------"
	 echo -e "#gem-data    $(echocol 18 $gdata1) $gdata2"
	 echo -e "#gemdyn      $(echocol 18 $gemdyn1) $gemdyn2"
	 echo -e "#rpnphy      $(echocol 18 $rpnphy1) $rpnphy2"
	 echo -e "#modelutils  $(echocol 18 $utils1) $utils2"
	 echo -e "#scripts     $(echocol 18 $gemscripts1) $gemscripts2"
	 echo -e "#vgrid       $(echocol 18 $vgrid1) $vgrid2"
	 echo -e "#RMN         $(echocol 18 $rmn1) $rmn2"
	 echo -e "#rpn_comm    $(echocol 18 $comm1) $comm2"
	 echo -e "#Compiler    $(echocol 18 $compil1) $compil2"
	 echo -e "#=============================================================="
	 echo "#More details at: https://wiki.cmc.ec.gc.ca/wiki/GEM/Change_Log"
	 echo "#Changing Component Version: https://wiki.cmc.ec.gc.ca/wiki/GEM/Component_Swap"
fi

if [[ x$mylocal == x1 ]] ; then
	 localdiff
	 exit 0
fi

if [[ x$mylog == x1 || x$myfilelist == x1 || x$mydiff != x || x$mydirdiff != x ]] ; then
	 if [[ x$mydyn == x1 ]] ; then
		  domydiff gemdyn $gemdyn1 ${gemdyn2:-?} src
	 fi
	 if [[ x$myphy == x1 ]] ; then
		  domydiff rpnphy $rpnphy1 ${rpnphy2:-?} src
	 fi
	 if [[ x$myutils == x1 ]] ; then
		  domydiff modelutils $utils1 ${utils2:-?} src
	 fi
	 if [[ x$myscripts == x1 ]] ; then
		  domydiff gem-scripts $gemscripts1 ${gemscripts2:-?} bin
	 fi
fi

exit 0
