#!/bin/bash

#########################################
# Name: qplot
#
# Summary: quick plot sample data for csv files
#
# Description:  
# Generate plot of sample data from CSV files
#
# Creates and executes a gnuplot command file
# Input: list of CSV data files (.csv)
# record format: timestamp (epoch seconds), field...
#
# Author: k. headley
#
# Copyright MBARI 2009
#
#########################################

#########################################
# Script configuration defaults
# casual users should not need to change
# anything below this section
#########################################
PLOT_HOME="."
OUTPUT="$PLOT_HOME/plot-output"
PDF="$OUTPUT/pdf"
PS="$OUTPUT/ps"
OFILE_NAME="qplot_out"
PS_OUT="$PS/$OFILE_NAME.ps"
PDF_OUT="$PDF/$OFILE_NAME.pdf"

GS_X=`which gs`
GRAPH_X=`which graph`
GNUPLOT_X=`which gnuplot`

# check for missing dependencies
declare -a MISSING_X

let "i=0"
if [ ! "$GS_X" ]
then
	MISSING_X[i]="gs"
	let "i+=1"
fi
if  [ ! "$GRAPH_X" ]
then
	MISSING_X[i]="graph"
	let "i+=1"
fi
if  [ ! "$GNUPLOT_X" ]
then
	MISSING_X[i]="gnuplot"
	let "i+=1"
fi

# if required package missing
# output error and exit
if [ "${#MISSING_X[*]}" -gt 0 ]
then
  echo
  echo "program(s) not found [${MISSING_X[@]}]"
  echo
  exit 1
fi

GPFILE="$PLOT_HOME/gp.tmp"
MAKEPDF="$GS_X -q -dNOPAUSE -dNOPROMPT  -dBATCH -sDEVICE=pdfwrite"
GRAPH="$GRAPH_X -T ps " 
GNUPLOT="$GNUPLOT_X $GPFILE"
replot=0
PLOT_STRING_FILE="plotString.txt"
TITLE=""
RANGE_MIN="*"
RANGE_MAX="*"
XRANGE_MIN="*"
XRANGE_MAX="*"
YTITLE=""
XTITLE="Timestamp (epoch sec)"
COL=2
NCOL=2
TFMT="%s"
XTFMT="\"%m/%d/%y %H:%M:%S\""
DSEP=","

#################################
# Script variable initialization
#################################
VERBOSE="FALSE"
DEBUG=""

declare -a PLOT_STRINGS
declare -a PLOT_SPECS

# Plot string holds the value of the
# plot command 
PLOT_STRING=""

ARGX=""

#################################
# Function Definitions
#################################
#################################
# name: printUsage
# description: print use message
# args: none
#################################
printUsage(){
    echo
    echo "`basename $0`: Generate plots from one or more delimited text files"
    echo 
    echo "usage: `basename $0` [options] file... "
    echo ""
	echo "Options:"
    echo "-d          : debug (keep temporary files) [$RANGE_MAX]"
    echo "-o <ofile>  : output file                  [$OFILE_NAME]"
    echo "-r <min Y>  : y-range min                  [$RANGE_MIN]"
    echo "-R <max Y>  : y-range max                  [$RANGE_MAX]"
    echo "-i <min X>  : x-range min                  [$XRANGE_MIN]"
    echo "-I <max X>  : x-range max                  [$XRANGE_MAX]"
    echo "-T <title>  : plot title                   [$TITLE]"
	echo "-Y <title>  : Y axis title                 [$YTITLE]"
	echo "-X <title>  : X axis title                 [$XTITLE]"
	echo "-t <fmt>    : time input format            [$TFMT]"
	echo "-x <fmt>    : x axis (time) format         [$XTFMT]"
	echo "-s <sep>    : data separator               [$DSEP]"
	echo "-y <pspec>  : file,xcol,N,col-1,title-1,...col-N,title-N "
    echo "-V          : verbose output               [$VERBOSE]"
    echo "-h          : print this help message"
    echo ""
    echo "Tip: store command line options in a file"
    echo "     and pipe/redirect input:"
	echo ""
    echo "    `basename $0` < my_plot_cfg"
    echo "    or"
    echo "    cat my_plot_cfg | `basename $0`"
    echo
}

########################################
# name: vout
# description: print verbose message to stderr
# args:
#     msg: message
########################################
vout(){
    if [ "$VERBOSE" == "TRUE" ]
    then
        echo "$1" >&2
    fi
}

########################################
# name: exitError
# description: print use message to stderr
# args:
#     msg:        error message
#     returnCode: exit status to return
########################################
exitError(){
    echo >&2
    echo "$1" >&2
    exit $2
}

#################################
# name: add_plot_string
# description: generate lines for 
# the plot string file
# args: none
#################################
add_plot_string(){
	# exects comma-delimited specifier:
	# 0: file
	# 1: xcol
	# 2: x-title
	# 3: number of y fields
	# 4: y-col
	# 5: title...
	# n-1: y-col
	# n: title

	declare -a parms
	IFS=',' read -a parms <<< "$1"
	let "i=0"
	let "parm_count=${#parms[@]}-1"
	let "field_count=${parms[2]}"
	let "j=${#PLOT_STRINGS[@]}"

	while [ "${i}" -lt $field_count ]
	do
	let "idx=2*${i}+3"
	if [ "${j}" -lt 1 ]
	then
	PLOT_STRINGS[$j]="plot \"${parms[0]}\" using ${parms[1]}:${parms[$idx]} t ${parms[$idx+1]} with points"
	else
	PLOT_STRINGS[$j]="\"${parms[0]}\" using ${parms[1]}:${parms[$idx]} t ${parms[$idx+1]} with points"
	fi
	vout "PLOT_STRINGS[$j]=${PLOT_STRINGS[$j]}"
	let "i+=1"
	let "j+=1"	
	done
}

#################################
# name: process_plot_specs
# description: process plot specifiers
# args: none
#################################
process_plot_specs(){
	if [ "${#PLOT_SPECS[@]}" -gt 0 ]
	then
	 let "k=0"
	 while [ "${k}" -lt "${#PLOT_SPECS[@]}" ]
	 do
		vout "adding plot string $k/${#PLOT_SPECS[@]}"
		add_plot_string ${PLOT_SPECS[$k]}
		let "k+=1" 
	 done
	fi
}

#################################
# name: gen_plot_string
# description: generate plot string
# args: none
#################################
gen_plot_string(){
	# truncate plot string file
	> $PLOT_STRING_FILE
	let "i=0"
	while [ "${i}" -lt "${#PLOT_STRINGS[@]}" ]
	do
	  echo -n ${PLOT_STRINGS[$i]} >> ${PLOT_STRING_FILE}
	  let "i+=1"
	  # if still lines to do,
	  # add line ends
	  if [ "${i}" -lt "${#PLOT_STRINGS[@]}" ]
	  then
	    echo ", \\" >> ${PLOT_STRING_FILE}
	  fi	  
	done
	
	PLOT_STRING=`cat $PLOT_STRING_FILE`
	
	vout "plot string: [$PLOT_STRING]"
	if [ ! "${DEBUG}" ]
	then
		rm $PLOT_STRING_FILE
	fi
}

#################################
# name: makeGP
# description: Write gnuplot command file
# args: none
#################################
makeGP(){
vout "makeGP args $* [$#]"
vout $PLOT_STRING

# Do Not Indent (here-doc)
cat > $GPFILE << EOF
# GNU Plot definition file
# [automatically generated]

# general options
set terminal postscript color "Arial" 10
set title $TITLE
set output "$PS_OUT"
set multiplot
set pointsize 0.4  
set key samplen 2 spacing 1 width 1 height 1
set key noautotitle 
set key box

# input options
set datafile separator "${DSEP}"

# x-axis
set xlabel ${XTITLE}
set timefmt ${TFMT}
set xtics rotate

# y-axis
set yrange [$RANGE_MIN:$RANGE_MAX]
set xdata time
set xrange [$XRANGE_MIN:$XRANGE_MAX]
set ylabel ${YTITLE}
set format x ${XTFMT}

# for debug
#show xrange
#show yrange

# plot command string
$PLOT_STRING
EOF
}

processCmdLine(){
	OPTIND=1
    vout "`basename $0` all args[$*]"
	while getopts dhT:o:i:I:r:R:t:Vy:x:X:Y: Option
	do
		vout "`basename $0` Processing option - $Option[$OPTARG]"
		case $Option in
			d ) DEBUG="TRUE"
			;;
			o ) OFILE_NAME="$OPTARG"
				PS_OUT="$PS/$OFILE_NAME.ps"
				PDF_OUT="$PDF/$OFILE_NAME.pdf"
			;;
			r ) RANGE_MIN=$OPTARG
			;;
			R ) RANGE_MAX=$OPTARG
			;;
			i ) XRANGE_MIN=$OPTARG
			;;
			I ) XRANGE_MAX=$OPTARG
			;;
			T ) TITLE=$OPTARG
			;;
			Y ) YTITLE=$OPTARG
			;;
			X ) XTITLE=$OPTARG
			;;
			t ) TFMT=$OPTARG
			;;
			x ) XTFMT=$OPTARG
			;;
			y ) PLOT_SPECS[${#PLOT_SPECS[@]}]=$OPTARG
			;;
			V ) VERBOSE="TRUE"
			;;
			h) printUsage
			  exit 0
			;;
			*) exitError "unrecognized option [$OPTOPT]"
			;;
		esac
	done

}

##########################
# Script main entry point
##########################

# Argument processing
# Accepts arguments from command line 
# or pipe/file redirect
# Comand line settings override config
# file settings
if [ -t 0 ]
then
	if [ "$#" -eq 0 ];then
		printUsage
		exit -1
	else
		processCmdLine $*
		let "i=$OPTIND-1"
		while [ "${i}" -gt 0  ]
		do
			shift
			let "i-=1"
		done
	fi
else	
	# save command line args
	declare -a cline_args
	let "i=1"
	while [ "$i" -le "$#" ]
	do
		cline_args[$i]="${@:$i:1}"
		let "i+=1"
	done

	# process config file 
  	declare -a arg_array
	let "z=0"
	while read line ; do
		IFS=" " read opt val <<< $line
		if [ "${opt}" ] && [[ $opt != \#* ]]
		then
		    vout "opt $opt $z"
			arg_array[$z]=${opt}
			let "z+=1"
			if [ "${val}" ]
			then
				vout "val $val $z"
				arg_array[$z]=${val}
				let "z+=1"
			fi
		else 
			vout "skipping line $line"
		fi
	done
	
	# set default delimiter to 
	# newline for parsing/setting
	# positional parameters
	# [must restore after processing]
	IFSO=$IFS
	IFS=`echo` 
	set - ${arg_array[*]}
	
	# apply config file settings
	processCmdLine ${arg_array[*]}

	# apply command line settings
	# (override config file options)
	set - ${cline_args[*]}
	processCmdLine ${cline_args[*]}

	# restore default delimiter
	IFS=$IFSO
	
	#let "i=$OPTIND-1"
	#while [ "${i}" -gt 0  ]
	#do
	#shift
	#let "i-=1"
	#done
		
fi

vout ""
vout "OPTIND     = [$OPTIND]"
vout "RANGE_MIN  = [$RANGE_MIN]"
vout "RANGE_MAX  = [$RANGE_MAX]"
vout "XRANGE_MIN = [$XRANGE_MIN]"
vout "XRANGE_MAX = [$XRANGE_MAX]"
vout "XTFMT      = [$XTFMT]"
vout "TITLE      = [$TITLE]"
vout "XTITLE     = [$XTITLE]"
vout "YTITLE     = [$YTITLE]"
vout "TFMT       = [$TFMT]"
vout "OFILE_NAME = [$OFILE_NAME]"
vout "DEBUG      = [$DEBUG]"
vout "VERBOSE    = [$VERBOSE]"
vout "PS_OUT     = [$PS_OUT]"
vout "PDF_OUT    = [$PDF_OUT]"
vout "ARGS       = [$*]"
vout "PLOT_SPECS = [${#PLOT_SPECS[@]}]"
vout ""


# Go to working directory
cd $PLOT_HOME

# create directories if they don't exist
if [ ! -d "$PS" ]
then
    mkdir -p "$PS"
fi
if [ ! -d "$PDF" ]
then
    mkdir -p "$PDF"
fi

# process plot specifiers
process_plot_specs
gen_plot_string

#################
# exit here
#################
#exit 0

# Generate gnuplot plot definition file
# use configured file paths for output
makeGP $*

# Plot data with gnuplot
vout "Creating Postscript..."
vout "GNUPLOT"
$GNUPLOT

# Convert PS to PDF with GhostScript
vout "Creating PDF..."
vout "$MAKEPDF -sOutputFile=$PDF_OUT $PS_OUT"
$MAKEPDF -sOutputFile=$PDF_OUT $PS_OUT

# remove temp gnuplot file
if [ ! "$DEBUG" ]
then
	rm $GPFILE
fi