#!/bin/sh

argHelp()
{
    echo "The project management script of OpenSCADA mostly designed to call from OpenSCADA itself, but it also can be used independently.
The script is mostly software platform specific and this one is related for Linux.

openscada-proj list
openscada-proj proc|create|remove|snapshot|crash|cores|update {ProjName}
 Commands:
  list   - list of the accessible projects;
  proc   - performing of the RO project copying to WR, creating desktop link, processing core dumps;
  create - creating new project or copying the RO project to WR, creating desktop link;
  remove - removing the project;
  snapshot|crash|cores - creating the hot crash snapshot to the running project,
           where the 'crash' variant to call from OpenSCADA,
                 the 'cores' variant to call from 'proc' for processing the core-files;
  update - updating from 0.8.0 LTS.
 Arguments:
  ProjName - project name;
 Environment variables:
  dPrj     - directory of projects OpenSCADA, can be RO;
  dPrjUser - directory of projects OpenSCADA of the user, WR;
  dSysCfg  - directory of system configuration;
  dData    - directory of system data.

openscada-proj backup|backupRestore {ProjName} [{BackupName}]
openscada-proj backupList {ProjName}
 Commands:
  backup	- backup the project <ProjName> under the name <BackupName>, or with the current date at missing;
  backupRestore - restore the project <ProjName> from the backup name <BackupName>, or from the last one at missing;
  backupList	- list of backups of the project <ProjName>.
 Arguments:
  ProjName   - project name;
  BackupName - name of the backup archive.
 Environment variables:
  OSCD_TAR_ComprPrg - TAR compression program, by default gzip;
  OSCD_TAR_Args     - TAR extra arguments, by default \"--exclude=lock --exclude=ARCHIVES\";
  OSCD_BackLim      - Backups limit, by default 10.
";
}

gdbCall()
{
    gdb $@ --batch --quiet \
	-ex "echo \n==== (gdb) info thread ====\n" -ex "info thread" \
	-ex "echo \n==== (gdb) thread apply all bt full ====\n" -ex "thread apply all bt full" \
	-ex "echo \n==== (gdb) info sharedlibrary ====\n" -ex "info sharedlibrary"
}

crashHandler()
{
    if test -z "$(which gdb 2> /dev/null)"; then echo "No GDB program present!"; return 0; fi

    prjNm=$1
    dPrjRez=$dPrj/$prjNm
    if test -n "$dPrjUser" -a -d $dPrjUser/$prjNm; then dPrjRez=$dPrjUser/$prjNm; fi
    cd $dPrjRez

    if test "$2" = cores; then
	for fit in `ls core* 2> /dev/null`; do
	    resultFile="${prjNm}_${fit}_$(date +%F_%H.%M).crash"
	    echo "Processing the core dump files for backtrace obtaining in the file $resultFile"
	    gdbCall @bindir_full@/openscada --core ${fit} > $resultFile
	    gzip $resultFile
	    rm -f ${fit}
	done
	return 0
    fi

    if test "$2" != snapshot -a "$2" != crash; then echo "Unknown command $2 to the crash handler!"
    elif test ! -f $dPrjRez/lock; then echo "The project is not running since missing the file $dPrjRez/lock!"
    else
	pid=`cat $dPrjRez/lock | sed -r 's/^0*([0-9]+).*/\1/'`
	if ! ps -A -o "pid cmd" | grep "^ *$pid.*openscada" > /dev/null; then
	    echo "No 'openscada' process at pid $pid!"
	else
	    cd $dPrjRez
	    if test "$2" = crash; then
		resultFile="${prjNm}_$(date +%F_%H.%M).crash"
		echo "Processing the crashing project for backtrace obtaining in the file $resultFile"
		rm $dPrjRez/lock
	    else
		resultFile="${prjNm}_$2_$(date +%F_%H.%M).crash"
		echo "Processing the crash snapshot for backtrace obtaining in the file $resultFile"
	    fi
	    gdbCall -p $pid > $resultFile
	    gzip $resultFile
	fi
    fi
}

if test $# -lt 1; then argHelp; exit 0; fi

dPrjUser=${dPrjUser:=~/.openscada}
dPrj=${dPrj:=@oscd_datadir_full@}
dSysCfg=${dSysCfg:=@sysconfdir_full@}
dData=${dData:=@datadir_full@}

case "$1" in
  list)
    if test -d $dPrjUser; then
	echo "=== User projects ==="
	for fit in `ls $dPrjUser`; do
	    if test -d $dPrjUser/$fit && test -f $dPrjUser/$fit/oscada.xml; then echo "$fit"; fi
	done
	echo "=== Common projects ==="
    fi
    for fit in `ls $dPrj`; do
	if test -d $dPrj/$fit && test -f $dSysCfg/oscada_$fit.xml -o -f $dPrj/$fit/oscada.xml; then echo "$fit"; fi
    done
    ;;
  proc|create)
    if test $# -lt 2; then echo "Not enough arguments!"; exit 1; fi
    prjNm=$2
    dPrjRez=$dPrj/$prjNm

    # Processing the system projects' directory
    if test ! -d $dPrjRez -a -w $dPrj -a -f $dSysCfg/oscada_$prjNm.xml; then mkdir -p $dPrjRez; fi

    # Processing the user projects' directory
    if test ! -d $dPrjRez -o ! -w $dPrjRez && test -n "$dPrjUser"; then
	if test ! -d $dPrjUser; then mkdir -p $dPrjUser; fi
	if test ! -d $dPrjUser/LibsDB/; then
	    mkdir -p $dPrjUser/LibsDB/
	    ln -s $dPrj/LibsDB/* $dPrjUser/LibsDB/ || cp $dPrj/LibsDB/* $dPrjUser/LibsDB/
	fi
	dPrjRez=$dPrjUser/$prjNm
	if test ! -d $dPrjRez; then
	    mkdir -p $dPrjRez
	    if test -d $dPrj/$prjNm; then
		cp -R $dPrj/$prjNm/* $dPrjRez
		if test ! -f $dPrjRez/oscada.xml; then cp $dSysCfg/oscada_$prjNm.xml $dPrjRez/oscada.xml; fi
	    fi
	fi
    fi

    # Initiating common files and checking
    if test -d $dPrjRez -a -w $dPrjRez; then
	if test ! -f $dPrjRez/oscada.xml -a ! -w $dSysCfg/oscada_$prjNm.xml; then cp $dSysCfg/oscada_start.xml $dPrjRez/oscada.xml; fi
	if test ! -d $dPrjRez/LibsDB -a ! -L $dPrjRez/LibsDB; then ln -s ../LibsDB $dPrjRez/LibsDB; fi
	if test ! -d $dPrjRez/LibsDB -a ! -L $dPrjRez/LibsDB; then cp -R $dPrjRez/../LibsDB $dPrjRez/LibsDB; fi
	if test ! -d $dPrjRez/ARCHIVES/; then mkdir -p $dPrjRez/ARCHIVES/MESS $dPrjRez/ARCHIVES/VAL; fi
	if test $1 = create -a -n "$(which xdg-user-dir)" && test -n "$(xdg-user-dir DESKTOP)"; then
	    DESKTOP_DIR="$(xdg-user-dir DESKTOP)"
	    if test -n "$DESKTOP_DIR"  -a ! -f "$DESKTOP_DIR/openscada_$prjNm.desktop"; then
		cp $dData/applications/openscada.desktop "$DESKTOP_DIR/openscada_$prjNm.desktop"
		sed -i "s/Exec=/Exec=env OSCADA_ProjName=$prjNm /" "$DESKTOP_DIR/openscada_$prjNm.desktop"
		sed -i "s/\(^\(Generic\|\)Name\(=\|\\[.*\\]=\).*\)/\1: $prjNm/" "$DESKTOP_DIR/openscada_$prjNm.desktop"
	    fi
	fi

	# Checking for lost lock at it PID and openscada process in whole, and starting from the user directory
	if test -f $dPrjRez/lock; then
	    pid=`cat $dPrjRez/lock | sed -r 's/^0*([0-9]+).*/\1/'`
	    if ! ps -A -o "pid cmd" | grep "^ *$pid.*openscada" > /dev/null; then rm $dPrjRez/lock; fi
	fi

	# Processing the core dump files "core[.*]" in the work directory
	crashHandler $prjNm cores
    fi
    ;;
  remove)
    if test $# -lt 2; then echo "Not enough arguments!"; exit 1; fi
    prjNm=$2
    prjDir=

    if test -n "$dPrjUser" -a -d $dPrjUser; then
	for fit in `ls $dPrjUser`; do
	    if test -d $dPrjUser/$fit && test -f $dPrjUser/$fit/oscada.xml && test $fit = $prjNm; then
		prjDir=$dPrjUser/$fit
		break
	    fi
	done
    else
	for fit in `ls $dPrj`; do
	    if test -d $dPrj/$fit && test -f $dSysCfg/oscada_$fit.xml -o -f $dPrj/$fit/oscada.xml && test $fit = $prjNm; then
		prjDir=$dPrj/$fit
		break
	    fi
	done
    fi

    if test "x$prjDir" != "x"; then
	# Removing the backups
	cd $prjDir/..
	for iF in `ls -t ${prjNm}_*.backup 2> /dev/null`; do rm $iF; done

	# Removing the project folder
	rm -r $prjDir

	# Remove the desktop link
	if test -n "$(which xdg-user-dir)" && test -n "$(xdg-user-dir DESKTOP)"; then
	    DESKTOP_DIR="$(xdg-user-dir DESKTOP)"
	    if test -n "$DESKTOP_DIR" -a -f "$DESKTOP_DIR/openscada_$prjNm.desktop"; then
		rm $DESKTOP_DIR/openscada_$prjNm.desktop
	    fi
	fi
    else exit 1;
    fi
    ;;
  snapshot|crash|cores)
    if test $# -lt 2; then echo "Not enough arguments!"
    else crashHandler $2 $1
    fi
    ;;
  backup)
    if test $# -lt 2; then echo "Not enough arguments!"; exit 1; fi
    prjNm=$2
    prjBackNm=${prjNm}_$(date +%F_%H.%M).backup
    if test $# -ge 3; then prjBackNm=${prjNm}_$3.backup; fi
    prjsDir=$dPrj
    if test -n "$dPrjUser" -a -d $dPrjUser/$prjNm; then prjsDir=$dPrjUser; fi
    cd $prjsDir
    if test -d $prjNm; then
	echo "Backuping the project \"$prjNm\" to $prjBackNm"
	OSCD_TAR_ComprPrg=${OSCD_TAR_ComprPrg:=gzip}
	OSCD_TAR_Args=${OSCD_TAR_Args:=--exclude=lock --exclude=ARCHIVES}
	tar -I$OSCD_TAR_ComprPrg $OSCD_TAR_Args -cvf $prjBackNm $prjNm > /dev/null
	ln -f -s $prjBackNm ${prjNm}_last.backup

	#Processing the backup limit
	iBack=0
	OSCD_BackLim=${OSCD_BackLim:=10}
	for iF in `ls -t ${prjNm}_*.backup 2> /dev/null`; do
	    if test -h $iF; then continue; fi
	    if test $iBack -ge $OSCD_BackLim; then
		echo "Removing $iF by the limit $OSCD_BackLim"
		rm $iF
	    fi
	    iBack=$(($iBack + 1))
	done
    else echo "No the project \"$prjNm\" found!"; fi
    ;;
  backupRestore)
    if test $# -lt 2; then echo "Not enough arguments!"; exit 1; fi
    backNm=last
    if test $# -ge 3; then backNm=$3; fi
    prjNm=$2
    prjsDir=$dPrj
    if test -n "$dPrjUser" -a -d $dPrjUser/$prjNm; then prjsDir=$dPrjUser; fi
    cd $prjsDir
    prjBackNm=${prjNm}_$backNm.backup
    if test -d $prjNm -a -f $prjBackNm; then
	if test -f $prjNm/lock; then echo "Stop the project $prjNm before restoring from the backup $prjBackNm"; exit 1; fi
	echo "Restoring the project \"$prjNm\" from the backup $prjBackNm"
	rm -R $prjNm
	tar xvf $prjBackNm > /dev/null
    else echo "No the backup \"$prjBackNm\" found!"; fi
    ;;
  backupList)
    if test $# -lt 1; then echo "Not enough arguments!"; exit 1; fi
    prjNm=$2
    prjsDir=$dPrj
    if test -n "$dPrjUser" -a -d $dPrjUser/$prjNm; then prjsDir=$dPrjUser; fi
    cd $prjsDir
    for iF in `ls -t ${prjNm}_*.backup 2> /dev/null`; do
	if test -h $iF; then continue; fi
	echo $iF | sed -n "/^${prjNm}_\(.*\)\.backup/s//\1/p"
    done
    ;;
  update)
    if test $# -lt 2; then echo "Not enough arguments!"; exit 1; fi
    prjNm=$2
    # OpenSCADA user folder presence
    if test -z "$dPrjUser" -o ! -d $dPrjUser; then exit 1; fi
    # Source directory checking whether it <prjNm> or "DATA"
    if test -d $dPrjUser/$prjNm; then
	if test ! -f $dPrjUser/$prjNm/oscada.xml; then srcDir=$prjNm; fi
    elif test -d $dPrjUser/DATA -o -d $dPrjUser/.openscada_old/DATA; then srcDir=DATA; fi
    if test -z "$srcDir"; then exit 1; fi

    # Saving the old release data to ".openscada_old"
    if test ! -d $dPrjUser/.openscada_old; then
	mkdir $dPrjUser/.openscada_old
	mv $dPrjUser/LibsDB $dPrjUser/ARCHIVES $dPrjUser/DATA $dPrjUser/*.xml $dPrjUser/*.db $dPrjUser/icons $dPrjUser/.openscada_old/
	cp -R $dPrj/LibsDB $dPrjUser/LibsDB
    fi
    # New project folder creating
    if test ! -d $dPrjUser/$prjNm; then
	mkdir $dPrjUser/$prjNm
	cp $dPrjUser/.openscada_old/DATA/* $dPrjUser/$prjNm
    fi
    # Other elements copying
    cp $dSysCfg/oscada_start.xml $dPrjUser/$prjNm/oscada.xml
    if test ! -f $dPrjUser/$prjNm/St.db -a -f $dPrjUser/$prjNm/MainSt.db; then
	mv $dPrjUser/$prjNm/MainSt.db $dPrjUser/$prjNm/St.db
    fi
    cp -R $dPrjUser/.openscada_old/ARCHIVES $dPrjUser/$prjNm
    ln -s ../LibsDB $dPrjUser/$prjNm/LibsDB
    ln -s ./ $dPrjUser/$prjNm/$prjNm
    ;;
  *) argHelp ;;
esac

exit 0