#!/bin/bash
#=================================================
# BOINC starter/status displayer
# Jean Philippe EIMER - phil.eimer@9online.fr
#-------------------------------------------------
# Released under the GNU General Public License v2
#=================================================

#---------------------------------------------
#---------------------------------------------
# Parameters to be set before using the script

# The path where BOINC state files reside
BOINC_PATH=/usr/local/boinc

# The path where BOINC client executable resides (without the client name)
# If client 'setiathome' is in /usr/bin, you'll have BOINC_BIN_PATH=/usr/bin
# This path may be absolute or relative to BOINC_PATH
BOINC_BIN_PATH=.

# LOG file for BOINC, with its absolute path
BOINC_LOG_FILE=$BOINC_PATH/boinc.log

# Options to give to the client when it starts
# See the documentation of the BOINC client
BOINC_OPTIONS=""

# Nothing should be modified below this line
#---------------------------------------------
#---------------------------------------------

#***********
# VARIABLES
#***********
VERSION="1.6"
DATE="02/2005"
AUTHOR="Jean Philippe EIMER"
EMAIL="phil.eimer@9online.fr"

BOINC_EXEC=boinc

STATE_FILE=$BOINC_PATH/client_state.xml
PID_CMD=/sbin/pidof
DATE_CMD=date
PS_CMD=ps
GREP_CMD=grep

BOINC_DATE_FORMAT="%c"

# Comment if you don't want color
BOINC_WARNING="\033[0;31m"			# RED
BOINC_INFO="\033[0;36m"				# LIGHT BLUE
BOINC_TITLE_COLOR="\033[01;34m"		# BOLD BLUE
BOINC_SUBTITLE_COLOR="\033[01;01m"	# BOLD 
BOINC_NORMAL="\033[0m"				


#***********
# FUNCTIONS
#***********
set_messages()
{
	# Messages initialization
	
	# Locale management
	if [ -z "$LC_ALL" ]; then
		BOINC_LANG=$LANG
	else
		# Extract language part of LC_ALL (fr_FR -> fr)
		BOINC_LANG=$LC_ALL
	fi
	BOINC_LANG=${BOINC_LANG:0:2}

	MESS_LIST="MESS_TIME_Y	MESS_TIME_D	MESS_TIME_H	MESS_TIME_M	MESS_FLOAT"
	MESS_LIST="$MESS_LIST MESS_PROJECT_INFO MESS_PROJECT_NAME MESS_REGISTER MESS_HOST_CREATE MESS_USER_CREDIT MESS_AVG_CPU MESS_AVG_UPDATE MESS_PROJECT_APP"
	MESS_LIST="$MESS_LIST MESS_CURRENT_STOPPED MESS_CURRENT MESS_CURRENT_NONE MESS_CURRENT_PROJECT MESS_CURRENT_APP MESS_CURRENT_STATE MESS_CURRENT_CPU MESS_CURRENT_REMAIN MESS_CURRENT_PROGRESS MESS_CURRENT_DEADLINE"
	MESS_LIST="$MESS_LIST MESS_CURRENT_STATE_0 MESS_CURRENT_STATE_1 MESS_CURRENT_STATE_2 MESS_CURRENT_STATE_3 MESS_CURRENT_STATE_4 MESS_CURRENT_STATE_5 MESS_CURRENT_STATE_WAITING"
	MESS_LIST="$MESS_LIST MESS_CLIENT MESS_CLIENT_PID MESS_CLIENT_TITLE MESS_CLIENT_NONE MESS_RUN_STATUS MESS_RUN_STOP_L MESS_RUN_STOP_R MESS_RUN_STOP_ERR MESS_RUN_START MESS_RUN_START_ERR MESS_RUN_NOT"
	MESS_LIST="$MESS_LIST MESS_HELP_TITLE MESS_HELP_AUTHOR MESS_HELP_VERSION MESS_HELP_USAGE MESS_HELP_OPTIONS MESS_HELP_OPT_HELP MESS_HELP_OPT_VERSION MESS_HELP_OPT_NO MESS_HELP_OPT_APPS MESS_HELP_OPT_PROJECTS MESS_HELP_OPT_UNITS MESS_HELP_OPT_START MESS_HELP_OPT_STOP MESS_HELP_OPT_LOG"

	i=0
	for mess in $MESS_LIST;  do
		(( $mess=i++ ))
	done

	# Messages definition
	case $BOINC_LANG in
		fr )	# french
			MESSAGE[$MESS_TIME_Y]="an"
			MESSAGE[$MESS_TIME_D]="j"
			MESSAGE[$MESS_TIME_H]="h"
			MESSAGE[$MESS_TIME_M]="min"

			MESSAGE[$MESS_FLOAT]=","

			MESSAGE[$MESS_PROJECT_INFO]="Informations projets"
			MESSAGE[$MESS_PROJECT_NAME]="Projet :"
			MESSAGE[$MESS_REGISTER]="Utilisateur enregistr le :"
			MESSAGE[$MESS_HOST_CREATE]="Machine enregistre le    :"
			MESSAGE[$MESS_USER_CREDIT]="Crdits de l'utilisateur  :"
			MESSAGE[$MESS_AVG_CPU]="Temps machine moyen       :"
			MESSAGE[$MESS_AVG_UPDATE]="Mise  jour du temps le   :"
			MESSAGE[$MESS_PROJECT_APP]="Application - Version     :"

			MESSAGE[$MESS_CURRENT_STOPPED]="ARRETEE !"
			MESSAGE[$MESS_CURRENT]="Units en cours"
			MESSAGE[$MESS_CURRENT_NONE]="Aucune unit en cours de calcul"
			MESSAGE[$MESS_CURRENT_PROJECT]="Projet :"
			MESSAGE[$MESS_CURRENT_APP]="Application   :"
			MESSAGE[$MESS_CURRENT_STATE]="Etat        :"
			MESSAGE[$MESS_CURRENT_CPU]="Temps machine :"
			MESSAGE[$MESS_CURRENT_REMAIN]="Temps restant :"
			MESSAGE[$MESS_CURRENT_PROGRESS]="Progression :"
			MESSAGE[$MESS_CURRENT_DEADLINE]="Date limite :"
			MESSAGE[$MESS_CURRENT_STATE_0]="attente de tlchargement"
			MESSAGE[$MESS_CURRENT_STATE_1]="rception en cours"
			MESSAGE[$MESS_CURRENT_STATE_2]="calcul en cours"
			MESSAGE[$MESS_CURRENT_STATE_3]="calcul termin"
			MESSAGE[$MESS_CURRENT_STATE_4]="envoi du rsultat"
			MESSAGE[$MESS_CURRENT_STATE_5]="rsultat envoy"
			MESSAGE[$MESS_CURRENT_STATE_WAITING]="en attente de calcul"

			MESSAGE[$MESS_CLIENT]="Applications"
			MESSAGE[$MESS_CLIENT_TITLE]="Application\tPID\tDmar.\tTemps machine\tNice\tProjet"
			MESSAGE[$MESS_CLIENT_NONE]="Aucune application en cours d'excution"

			MESSAGE[$MESS_RUN_STATUS]="BOINC est actif"
			MESSAGE[$MESS_RUN_STOP_L]="BOINC" 
			MESSAGE[$MESS_RUN_STOP_R]="a t arrt." 
			MESSAGE[$MESS_RUN_STOP_ERR]="BOINC ne peut tre arrt que par l'utilisateur"
			MESSAGE[$MESS_RUN_START]="BOINC a dmarr"
			MESSAGE[$MESS_RUN_START_ERR]="BOINC n'a pas pu dmarrer !"
			MESSAGE[$MESS_RUN_NOT]="BOINC n'est pas en cours d'excution !"

			MESSAGE[$MESS_HELP_TITLE]="Script pour dmarrer BOINC et afficher l'tat des projets"
			MESSAGE[$MESS_HELP_AUTHOR]="Auteur"
			MESSAGE[$MESS_HELP_VERSION]="Version"
			MESSAGE[$MESS_HELP_USAGE]="Utilisation : boinc OPTION"
			MESSAGE[$MESS_HELP_OPTIONS]="OPTION disponibles :"
			MESSAGE[$MESS_HELP_OPT_HELP]="affiche ce texte d'aide"
			MESSAGE[$MESS_HELP_OPT_VERSION]="affiche la version du script"
			MESSAGE[$MESS_HELP_OPT_NO]="    <sans option>  : affiche tout (applications, projets, units)"
			MESSAGE[$MESS_HELP_OPT_APPS]="affiche les applications en cours"
			MESSAGE[$MESS_HELP_OPT_PROJECTS]="affiche le dtail des projets"
			MESSAGE[$MESS_HELP_OPT_UNITS]="affiche l'tat des units en cours"
			MESSAGE[$MESS_HELP_OPT_START]="dmarre le client BOINC"
			MESSAGE[$MESS_HELP_OPT_STOP]="envoie le signal TERM pour arrter le client"
			MESSAGE[$MESS_HELP_OPT_LOG]="affiche les N dernires lignes du fichier LOG"
		;;

		fi | su )	# finish, suomi
			MESSAGE[$MESS_TIME_Y]="v"
			MESSAGE[$MESS_TIME_D]="p"
			MESSAGE[$MESS_TIME_H]="t"
			MESSAGE[$MESS_TIME_M]="min"

			MESSAGE[$MESS_FLOAT]=","

			MESSAGE[$MESS_PROJECT_INFO]="Projektin Tiedot"
			MESSAGE[$MESS_PROJECT_NAME]="Projekti :"
			MESSAGE[$MESS_REGISTER]="Kyttj rekisteritynyt  :"
			MESSAGE[$MESS_HOST_CREATE]="Palvelin rekisteritynyt  :"
			MESSAGE[$MESS_USER_CREDIT]="Kyttjn pisteet         :"
			MESSAGE[$MESS_AVG_CPU]="Keskim. CPU aika          :"
			MESSAGE[$MESS_AVG_UPDATE]="CPU aika pivitetty       :"
			MESSAGE[$MESS_PROJECT_APP]="Sovellus - Versio         :"

			MESSAGE[$MESS_CURRENT_STOPPED]="PYSYTETTY !"
			MESSAGE[$MESS_CURRENT]="Kytss olevat tyt"
			MESSAGE[$MESS_CURRENT_TITLES]="Nimi\tProjekti\tTila\t\tCPU Aika\tArv. Jljell\tEdistyminen"
			MESSAGE[$MESS_CURRENT_NONE]="Ei odottavia tit"
			MESSAGE[$MESS_CURRENT_PROJECT]="Projekti :"
			MESSAGE[$MESS_CURRENT_APP]="Sovellus       :"
			MESSAGE[$MESS_CURRENT_STATE]="Tila     :"
			MESSAGE[$MESS_CURRENT_CPU]="CPU Aika       :"
			MESSAGE[$MESS_CURRENT_REMAIN]="Aikaa jljell :"
			MESSAGE[$MESS_CURRENT_PROGRESS]="Laskettu :"
			MESSAGE[$MESS_CURRENT_DEADLINE]="Aikaraja :"
			MESSAGE[$MESS_CURRENT_STATE_0]="odottaa uutta tyt"
			MESSAGE[$MESS_CURRENT_STATE_1]="lataamassa"
			MESSAGE[$MESS_CURRENT_STATE_2]="laskemassa"
			MESSAGE[$MESS_CURRENT_STATE_3]="valmis"
			MESSAGE[$MESS_CURRENT_STATE_4]="lhett tulokset"
			MESSAGE[$MESS_CURRENT_STATE_5]="tulokset lhetetty"
			MESSAGE[$MESS_CURRENT_STATE_WAITING]="odottaa laskentaa"

			MESSAGE[$MESS_CLIENT]="Sovellus"
			MESSAGE[$MESS_CLIENT_PID]="BOINC Prosessin ID :"
			MESSAGE[$MESS_CLIENT_TITLE]="Sovellus\tPID\tAlkoi\tCPU Aika\tNice\tProjekti"
			MESSAGE[$MESS_CLIENT_NONE]="Ei ajettavia sovelluksia"

			MESSAGE[$MESS_RUN_STATUS]="BOINC projektin tila"
			MESSAGE[$MESS_RUN_STOP_L]="BOINC (PID " 
			MESSAGE[$MESS_RUN_STOP_R]=") pysytetty." 
			MESSAGE[$MESS_RUN_STOP_ERR]="BOINC:n voi pysytt vain kyttj"
			MESSAGE[$MESS_RUN_START]="BOINC kynnistetty"
			MESSAGE[$MESS_RUN_START_ERR]="BOINC:a EI voitu kynnist !"
			MESSAGE[$MESS_RUN_NOT]="BOINC EI ole ajossa !"

			MESSAGE[$MESS_HELP_TITLE]="BOINC kynnistj ja projektin tilan esittj"
			MESSAGE[$MESS_HELP_AUTHOR]="Author"
			MESSAGE[$MESS_HELP_VERSION]="Versio"
			MESSAGE[$MESS_HELP_USAGE]="Kytt : boinc OPTIOT"
			MESSAGE[$MESS_HELP_OPTIONS]="Kytss olevat OPTIOT :"
			MESSAGE[$MESS_HELP_OPT_HELP]="tulostaa tmn tekstin"
			MESSAGE[$MESS_HELP_OPT_VERSION]="tulostaa version"
			MESSAGE[$MESS_HELP_OPT_NO]="    <ei optiota>   : nytt kaiken (sovellukset, projetit, tyt)"
			MESSAGE[$MESS_HELP_OPT_APPS]="nytt suoritettavan sovelluksen"
			MESSAGE[$MESS_HELP_OPT_PROJECTS]="nytt projektin tiedot"
			MESSAGE[$MESS_HELP_OPT_UNITS]="nytt tyyksikiden tilan"
			MESSAGE[$MESS_HELP_OPT_START]="kynnist BOINC:n"
			MESSAGE[$MESS_HELP_OPT_STOP]="lhett TERM signaalin"
			MESSAGE[$MESS_HELP_OPT_LOG]="nytt LOG tiedoston N viimeist rivi"
			;;

		* )	# default is english
			MESSAGE[$MESS_TIME_Y]="yr"
			MESSAGE[$MESS_TIME_D]="d"
			MESSAGE[$MESS_TIME_H]="h"
			MESSAGE[$MESS_TIME_M]="min"

			MESSAGE[$MESS_FLOAT]="."

			MESSAGE[$MESS_PROJECT_INFO]="Project Info"
			MESSAGE[$MESS_PROJECT_NAME]="Project :"
			MESSAGE[$MESS_REGISTER]="User registered on  :"
			MESSAGE[$MESS_HOST_CREATE]="Host registered on  :"
			MESSAGE[$MESS_USER_CREDIT]="User credits        :"
			MESSAGE[$MESS_AVG_CPU]="Average CPU time    :"
			MESSAGE[$MESS_AVG_UPDATE]="CPU time updated on :"
			MESSAGE[$MESS_PROJECT_APP]="Application-Version :"

			MESSAGE[$MESS_CURRENT_STOPPED]="STOPPED !"
			MESSAGE[$MESS_CURRENT]="Current Working Units"
			MESSAGE[$MESS_CURRENT_TITLES]="Name\tProject\tState\t\tCPU Time\tEst. Remain.\tProgress"
			MESSAGE[$MESS_CURRENT_NONE]="No working unit pending"
			MESSAGE[$MESS_CURRENT_PROJECT]="Project :"
			MESSAGE[$MESS_CURRENT_APP]="Application    :"
			MESSAGE[$MESS_CURRENT_STATE]="State    :"
			MESSAGE[$MESS_CURRENT_CPU]="CPU Time       :"
			MESSAGE[$MESS_CURRENT_REMAIN]="Time remaining :"
			MESSAGE[$MESS_CURRENT_PROGRESS]="Progress :"
			MESSAGE[$MESS_CURRENT_DEADLINE]="Deadline :"
			MESSAGE[$MESS_CURRENT_STATE_0]="waiting for download"
			MESSAGE[$MESS_CURRENT_STATE_1]="downloading"
			MESSAGE[$MESS_CURRENT_STATE_2]="being computed"
			MESSAGE[$MESS_CURRENT_STATE_3]="finished"
			MESSAGE[$MESS_CURRENT_STATE_4]="uploading result"
			MESSAGE[$MESS_CURRENT_STATE_5]="result uploaded"
			MESSAGE[$MESS_CURRENT_STATE_WAITING]="waiting for computation"

			MESSAGE[$MESS_CLIENT]="Applications"
			MESSAGE[$MESS_CLIENT_TITLE]="Application\tPID\tStart\tCPU Time\tNice\tProject"
			MESSAGE[$MESS_CLIENT_NONE]="No running application"

			MESSAGE[$MESS_RUN_STATUS]="BOINC is running"
			MESSAGE[$MESS_RUN_STOP_L]="BOINC" 
			MESSAGE[$MESS_RUN_STOP_R]="has been stopped." 
			MESSAGE[$MESS_RUN_STOP_ERR]="BOINC can only be stopped by user"
			MESSAGE[$MESS_RUN_START]="BOINC has just been started"
			MESSAGE[$MESS_RUN_START_ERR]="BOINC could not be started !"
			MESSAGE[$MESS_RUN_NOT]="BOINC is not running !"

			MESSAGE[$MESS_HELP_TITLE]="BOINC starter and projects state displayer"
			MESSAGE[$MESS_HELP_AUTHOR]="Author"
			MESSAGE[$MESS_HELP_VERSION]="Version"
			MESSAGE[$MESS_HELP_USAGE]="Usage : boinc OPTION"
			MESSAGE[$MESS_HELP_OPTIONS]="Available OPTION :"
			MESSAGE[$MESS_HELP_OPT_HELP]="prints this text"
			MESSAGE[$MESS_HELP_OPT_VERSION]="prints the version"
			MESSAGE[$MESS_HELP_OPT_NO]="    <no option>    : displays all (applications, projects, units)"
			MESSAGE[$MESS_HELP_OPT_APPS]="displays running applications"
			MESSAGE[$MESS_HELP_OPT_PROJECTS]="displays projects details"
			MESSAGE[$MESS_HELP_OPT_UNITS]="displays working units state"
			MESSAGE[$MESS_HELP_OPT_START]="starts the BOINC client"
			MESSAGE[$MESS_HELP_OPT_STOP]="sends the TERM signal to kill the client"
			MESSAGE[$MESS_HELP_OPT_LOG]="displays LOG file's N latest lines"
		;;
	esac
}


seconds_since_1970_to_date()
{
	# Converts a number of seconds since 1/1/1970 0h into a readable date
	# $1 = number of seconds since 1/1/1970 0h (integer)
	
	# Time computation
	TIME_HOUR=$(($1 % 86400 / 3600))
	TIME_MINUTE=$(($1 % 3600 / 60))
	TIME_SECOND=$(($1 % 60))

	# Year computation
	TIME_YEAR=$(($1 / 31556952))
	nbjour1970=$((TIME_YEAR * 365 + (TIME_YEAR + 1) / 4))
	TIME_DAY=$(($1 / 86400 - nbjour1970 + 1))
	((TIME_YEAR += 1970))

	# Month and Day computation
	TIME_MONTH=1

	# Year with a leap ?
	if (( TIME_YEAR % 4 == 0 ));  then	# we consider we are close to year 2000 !
		feb=29
	else
		feb=28
	fi
	
	for monthdays in 31 feb 31 30 31 30 31 31 30 31 30 31;  do
		if (( TIME_DAY <= monthdays )); then
			break
		fi

		((TIME_DAY -= monthdays))
		((TIME_MONTH++))
	done

	echo `$DATE_CMD "+$BOINC_DATE_FORMAT" -d "${TIME_MONTH}/${TIME_DAY}/${TIME_YEAR} ${TIME_HOUR}:${TIME_MINUTE}:${TIME_SECOND} UTC"`
}


seconds_to_string()
{
	# Convert a number of seconds into a STRING (year, days, hours, minutes)
	# $1 = number of seconds (float)
	
	TIME_INT=$1
	# Remove float part
	TIME_INT=${TIME_INT/.*}
	
	# Number of years
	if (( TIME_INT > 31556952 ));  then
		TIME_YEAR=$((TIME_INT / 31556952))
		TIME_STRING="${TIME_YEAR}${MESSAGE[$MESS_TIME_Y]} "
	else
		TIME_STRING=""
	fi

	# Number of days
	if (( TIME_INT > 86400 ));  then
		TIME_DAY=$((TIME_INT % 31556952 / 86400))
		TIME_STRING="${TIME_STRING}${TIME_DAY}${MESSAGE[$MESS_TIME_D]} "
	fi

	# Number of hours and minutes 
	TIME_HOUR=$((TIME_INT % 86400 / 3600))
	TIME_MINUTE=$((TIME_INT % 3600 / 60))

	if ((TIME_MINUTE < 10 )); then
		TIME_MINUTE=" "$TIME_MINUTE
	fi

	echo "${TIME_STRING}${TIME_HOUR}${MESSAGE[$MESS_TIME_H]} ${TIME_MINUTE}${MESSAGE[$MESS_TIME_M]}"
}


format_version()
{
	# Add a dot to version string
	# $1 = version (string)
	
	VERS_MAJOR=$(($1/100))
	VERS_MINOR=$(($1%100))

	if (( VERS_MINOR < 10 )); then
		VERS_MINOR="0$VERS_MINOR"
	fi

	echo "$VERS_MAJOR.$VERS_MINOR"
}


extract_data()
{
	# Extract DATA from structured XML file
	# $1 = data chapter (string), $2 = chapter number (integer)
	# $3 = data name (string), $4 = data line number (integer)
	# $5 = filename (string)

	# extract line
	EXTRACTED_DATA=`$GREP_CMD -x -A $4 -m $2 "<$1>" $5 | tail -n 1 -`

	# remove tag
	EXTRACTED_DATA=${EXTRACTED_DATA/<$3>}
	EXTRACTED_DATA=${EXTRACTED_DATA/<\/$3>}
	echo $EXTRACTED_DATA
}


format_task_string()
{
	# remove some chars from a task string and add a TASK heading
	# $1 = string
	
	STRING=${1//.}
	STRING=${STRING//-}
	echo "TASK${STRING}"
}


init_arrays()
{
	# project array
	PROJECT_NB=`$GREP_CMD -c "<project>" $STATE_FILE`

	for (( pn = 1; pn <= PROJECT_NB ; pn++ )); do
		PROJECT_APP=`extract_data app_version $pn app_name 1 $STATE_FILE`
		(($PROJECT_APP=$pn))
	done

	# task array
	TASK_NB=`$GREP_CMD -c "<active_task>" $STATE_FILE`

	for (( tn = 1; tn <= TASK_NB; tn++ )); do
		TASK_RESULT_NAME=`extract_data active_task $tn result_name 2 $STATE_FILE`
		TASK_RESULT_NAME=`format_task_string $TASK_RESULT_NAME`
		(($TASK_RESULT_NAME=$tn))
	done
}


display_projects()
{
	# Displays information about projects managed by BOINC
	echo -e "\n $BOINC_TITLE_COLOR${MESSAGE[$MESS_PROJECT_INFO]}$BOINC_NORMAL"

	for (( pn = 1; pn <= PROJECT_NB ; pn++ )); do
		PROJECT_NAME=`extract_data project $pn project_name 2 $STATE_FILE`
		echo -e "   $BOINC_SUBTITLE_COLOR${MESSAGE[$MESS_PROJECT_NAME]} ${PROJECT_NAME}$BOINC_NORMAL"
		
		USER_REGISTRATION=`extract_data project $pn user_create_time 9 $STATE_FILE`
		FORMATED_DATE=`seconds_since_1970_to_date $USER_REGISTRATION` 
		echo "     ${MESSAGE[$MESS_REGISTER]} ${FORMATED_DATE}"

		HOST_REGISTRATION=`extract_data project $pn host_create_time 14 $STATE_FILE`
		FORMATED_DATE=`seconds_since_1970_to_date $HOST_REGISTRATION` 
		echo "     ${MESSAGE[$MESS_HOST_CREATE]} ${FORMATED_DATE}"

		USER_TOTAL_CREDIT=`extract_data project $pn user_total_credit 7 $STATE_FILE`
		USER_TOTAL_CREDIT=${USER_TOTAL_CREDIT/./${MESSAGE[$MESS_FLOAT]}}
		USER_TOTAL_CREDIT=${USER_TOTAL_CREDIT/%????}
		echo -e "     ${MESSAGE[$MESS_USER_CREDIT]} ${BOINC_SUBTITLE_COLOR}${USER_TOTAL_CREDIT}${BOINC_NORMAL}"
		
		AVG_CPU=`extract_data project $pn exp_avg_cpu 15 $STATE_FILE`
		AVG_CPU=`seconds_to_string $AVG_CPU`
		echo "     ${MESSAGE[$MESS_AVG_CPU]} ${AVG_CPU}"
		
		AVG_UPDATE=`extract_data project $pn exp_avg_mod_time 16 $STATE_FILE`
		AVG_UPDATE=${AVG_UPDATE/.*}
		FORMATED_DATE=`seconds_since_1970_to_date $AVG_UPDATE` 
		echo "     ${MESSAGE[$MESS_AVG_UPDATE]} ${FORMATED_DATE}"

		PROJECT_APP=`extract_data app_version $pn app_name 1 $STATE_FILE`
		PROJECT_APP_VERS=`extract_data app_version $pn version_num 2 $STATE_FILE`
		PROJECT_APP_VERS=`format_version PROJECT_APP_VERS`
		echo "     ${MESSAGE[$MESS_PROJECT_APP]} ${PROJECT_APP} - $PROJECT_APP_VERS"
	done
}


display_units()
{
	# Displays information about Working Units
	echo -e "\n $BOINC_TITLE_COLOR${MESSAGE[$MESS_CURRENT]}$BOINC_NORMAL"

	# Number of WU
	WORKUNIT_NB=`$GREP_CMD -c "<workunit>" $STATE_FILE`

	if (( WORKUNIT_NB != 0 )); then
		for (( wn = 1; wn <= WORKUNIT_NB ; wn++ )); do
			WORKUNIT_RESULT_NAME=`extract_data result $wn name 1 $STATE_FILE`
			WORKUNIT_RESULT_NAME=`format_task_string $WORKUNIT_RESULT_NAME`
			WORKUNIT_STATE=`extract_data result $wn state 4 $STATE_FILE`
			WORKUNIT_REMAIN=""

			case $WORKUNIT_STATE in
				0 | 1 | 2 )
					if [ "${!WORKUNIT_RESULT_NAME}" == "" ]; then
						WORKUNIT_STATE=$MESS_CURRENT_STATE_WAITING
						WORKUNIT_CPU="-"
						PROG_PERCENT="0%"
					else
						WORKUNIT_STATE=$((MESS_CURRENT_STATE_0 + WORKUNIT_STATE))
						WORKUNIT_CURRENT=`extract_data active_task ${!WORKUNIT_RESULT_NAME} current_cpu_time 8 $STATE_FILE`
						WORKUNIT_CURRENT=${WORKUNIT_CURRENT/.*}
						WORKUNIT_CPU=`seconds_to_string $WORKUNIT_CURRENT`
						PROGRESS=`extract_data active_task ${!WORKUNIT_RESULT_NAME} fraction_done 7 $STATE_FILE`
						PROG_PERCENT="${PROGRESS:2:2}${MESSAGE[$MESS_FLOAT]}${PROGRESS:4:2}%"
						PROGRESS=$((10#${PROGRESS:2:2}${PROGRESS:4:2}))
						if (( PROGRESS > 3500 )); then
							WORKUNIT_REMAIN=$((WORKUNIT_CURRENT * (10000 - PROGRESS) / PROGRESS ))
							WORKUNIT_REMAIN=`seconds_to_string $WORKUNIT_REMAIN`
						fi
					fi
					WORKUNIT_DEAD_LINE=`extract_data result $wn report_deadline 6 $STATE_FILE`
					WORKUNIT_DEAD_LINE=`seconds_since_1970_to_date $WORKUNIT_DEAD_LINE` 
				;;
				
				3| 4 | 5 )
					WORKUNIT_STATE=$((MESS_CURRENT_STATE_0 + WORKUNIT_STATE))
					WORKUNIT_CPU=`extract_data result $wn final_cpu_time 2 $STATE_FILE`
					WORKUNIT_CPU=`seconds_to_string $WORKUNIT_CPU`
					PROG_PERCENT="100%"
					WORKUNIT_DEAD_LINE="" 
				;;
			esac

			WORKUNIT_NAME=`extract_data workunit $wn name 1 $STATE_FILE`

			if (( ${#WORKUNIT_NAME} < 21 )); then
				WORKUNIT_NAME="$WORKUNIT_NAME\t"
			fi
			if (( ${#WORKUNIT_NAME} < 29 )); then
				WORKUNIT_NAME="$WORKUNIT_NAME\t"
			fi
			if (( ${#WORKUNIT_NAME} < 37 )); then
				WORKUNIT_NAME="$WORKUNIT_NAME\t"
			fi
			if (( ${#WORKUNIT_NAME} < 45 )); then
				WORKUNIT_NAME="$WORKUNIT_NAME\t"
			else
				WORKUNIT_NAME="$WORKUNIT_NAME\n     \t\t\t\t\t\t"
			fi
			
			echo -en "   $BOINC_SUBTITLE_COLOR$WORKUNIT_NAME$BOINC_NORMAL"
			
			WORKUNIT_APP=`extract_data workunit $wn app_name 2 $STATE_FILE`
			WORKUNIT_PROJECT=`extract_data project ${!WORKUNIT_APP} project_name 2 $STATE_FILE`
			echo -e  "${MESSAGE[$MESS_CURRENT_PROJECT]} $BOINC_SUBTITLE_COLOR$WORKUNIT_PROJECT$BOINC_NORMAL"
			
			WORKUNIT_STATE="${MESSAGE[$MESS_CURRENT_STATE]} ${MESSAGE[$WORKUNIT_STATE]}"
			if (( ${#WORKUNIT_STATE} < 27 )); then
				WORKUNIT_STATE="$WORKUNIT_STATE\t"
			fi
			echo -en "     $WORKUNIT_STATE"
			echo -e  "\t\t${MESSAGE[$MESS_CURRENT_CPU]} $WORKUNIT_CPU"
			PROG_PERCENT="${MESSAGE[$MESS_CURRENT_PROGRESS]} $PROG_PERCENT"
			echo -en "     $PROG_PERCENT"

			if [ "$WORKUNIT_REMAIN" != "" ]; then
				if (( ${#PROG_PERCENT} < 19 )); then
					echo -en "\t"
				fi
				echo -en "\t\t\t${MESSAGE[$MESS_CURRENT_REMAIN]} $WORKUNIT_REMAIN"
			fi
			if [ "$WORKUNIT_DEAD_LINE" != "" ]; then
				echo -en "\n     ${MESSAGE[$MESS_CURRENT_DEADLINE]} $WORKUNIT_DEAD_LINE"
			fi
			echo
		done
	else
		echo -e "   ${MESSAGE[$MESS_CURRENT_NONE]}"
	fi
}

display_apps()
{
	# Displays information about applications launched by BOINC
	
	# BOINC has just been launched
	if [ "$1" == "1" ]; then
		MESS_RUN=$BOINC_INFO${MESSAGE[$MESS_RUN_START]}" (PID "$BOINC_PID")"$BOINC_NORMAL
		MESS_STOPPED=$BOINC_WARNING${MESSAGE[$MESS_RUN_START_ERR]}$BOINC_NORMAL
	else
		MESS_RUN=${MESSAGE[$MESS_RUN_STATUS]}" (PID "$BOINC_PID")"
		MESS_STOPPED=$BOINC_WARNING${MESSAGE[$MESS_RUN_NOT]}$BOINC_NORMAL
	fi

	if [ "$BOINC_PID" == "" ]; then
		echo -e "\n$MESS_STOPPED"
	else	
		echo -e "\n$MESS_RUN"
		echo -e "\n $BOINC_TITLE_COLOR${MESSAGE[$MESS_CLIENT]}$BOINC_NORMAL"

		# Number of applications
#		APP_PID_NB=`$PS_CMD h -o pid --ppid $BOINC_PID | wc -l`
		APP_PID_NB=`pgrep -P $BOINC_PID | wc -l`
		APP_PID_NB=${APP_PID_NB// }

		if (( APP_PID_NB > 0 )); then
			echo -e "   $BOINC_SUBTITLE_COLOR${MESSAGE[$MESS_CLIENT_TITLE]}$BOINC_NORMAL"
			
			for (( app_pid = 1; app_pid <= APP_PID_NB ; app_pid++ )); do
#				APP_PID=`$PS_CMD h -o pid --ppid $BOINC_PID | head -n $app_pid | tail -n 1`
				APP_PID=`pgrep -P $BOINC_PID | head -n $app_pid | tail -n 1`
				APP_PID=${APP_PID// }

				APP_LONGNAME=`$PS_CMD h -o cmd -p $APP_PID`
				APP_LONGNAME=${APP_LONGNAME/ *}
				APP_NAME=${APP_LONGNAME/_*}

				# if process is forked, we use the fork
				APP_FORK_PID=`pgrep -P $APP_PID`

				while [ "$APP_FORK_PID" != "" ]; do
					APP_PID=$APP_FORK_PID
					APP_FORK_PID=`pgrep -P $APP_PID`
				done

				echo -en "   $APP_NAME"
				if (( ${#APP_NAME} < 13 )); then
					echo -en "\t"
				fi

				echo -en "$APP_PID"

				APP_START=`$PS_CMD h -o stime -p $APP_PID`
				echo -en "\t$APP_START"

				APP_TIME=`$PS_CMD h -o time -p $APP_PID`
				echo -en "\t$APP_TIME"

				APP_NICE=`$PS_CMD h -o nice -p $APP_PID`
				APP_NICE=${APP_NICE// }
				echo -en "\t$APP_NICE"

				PROJ_NAME=`extract_data project ${!APP_NAME} project_name 2 $STATE_FILE`
				echo -e "\t$PROJ_NAME"
			done
		else
			echo -e "   ${MESSAGE[$MESS_CLIENT_NONE]}"
		fi
	fi
}


#********
# SCRIPT
#********

set_messages

BOINC_PID=`$PID_CMD $BOINC_EXEC`

init_arrays

case $1 in
	--start | -s )
		if [ "$BOINC_PID" == "" ]; then
			cd $BOINC_PATH
			$BOINC_BIN_PATH/$BOINC_EXEC $BOINC_OPTIONS >> $BOINC_LOG_FILE 2>&1 &

			sleep 1

			BOINC_PID=`$PID_CMD $BOINC_EXEC`

			JUST_STARTED=1
		fi
		display_apps $JUST_STARTED
		;;

	--stop | -S )
		if [ "$BOINC_PID" != "" ]; then
			BOINC_USER=`$PS_CMD h -o user -p $BOINC_PID`
			
			if [ "$BOINC_USER" == "$USER" ]; then 
				kill $BOINC_PID
				echo -e "\n"${BOINC_WARNING}${MESSAGE[$MESS_RUN_STOP_L]}" (PID "${BOINC_PID}") "${MESSAGE[$MESS_RUN_STOP_R]}${BOINC_NORMAL}
			else
				echo -e "\n"${BOINC_WARNING}${MESSAGE[$MESS_RUN_STOP_ERR]} ${BOINC_USER} !${BOINC_NORMAL}
			fi
		else
			display_apps 
		fi
		;;
		
	--log | -l )
		if [ "$2" != "" ]; then
			TAILN="-n $2"
		fi

		tail $BOINC_LOG_FILE $TAILN 
		;;

	--version | -v | -V )
		echo "${MESSAGE[$MESS_HELP_VERSION]} ${VERSION} - ${DATE}"
		;;

	--help | -h | -\? )
		echo -e "\n${MESSAGE[$MESS_HELP_TITLE]}"
		echo
		echo "${MESSAGE[$MESS_HELP_AUTHOR]} : ${AUTHOR} - ${EMAIL}"
		echo "${MESSAGE[$MESS_HELP_VERSION]} ${VERSION} - ${DATE}"
		echo
		echo "${MESSAGE[$MESS_HELP_USAGE]}"
		echo
		echo "${MESSAGE[$MESS_HELP_OPTIONS]}"
		echo "${MESSAGE[$MESS_HELP_OPT_NO]}"
		echo "    -a, --apps     : ${MESSAGE[$MESS_HELP_OPT_APPS]}"
		echo "    -p, --projects : ${MESSAGE[$MESS_HELP_OPT_PROJECTS]}"
		echo "    -u, --units    : ${MESSAGE[$MESS_HELP_OPT_UNITS]}"
		echo "    -s, --start    : ${MESSAGE[$MESS_HELP_OPT_START]}"
		echo "    -S  --stop     : ${MESSAGE[$MESS_HELP_OPT_STOP]}"
		echo "    -l, --log [N]  : ${MESSAGE[$MESS_HELP_OPT_LOG]}"
		echo "-v, -V, --version  : ${MESSAGE[$MESS_HELP_OPT_VERSION]}"
		echo "-?, -h, --help     : ${MESSAGE[$MESS_HELP_OPT_HELP]}"
		;;

	--apps | -a )
		display_apps
		;;
		
	--projects | -p )
		display_projects
		;;
		
	--units | -u )
		display_units
		;;
		
	* )
		display_apps
		display_projects
		display_units
		;;
esac

echo
