#!/bin/bash

function print_help_and_exit
{
cat >&2 << EOF

'voronota-voromqa' script is an implementation of VoroMQA method using Voronota.

Basic options:
    --input | -i                   string   *  input structure file in PDB format
    --input-filter-query           string      input atoms filtering query parameters
    --output-atom-scores           string      output text file with atom scores
    --output-atom-scores-pdb       string      output PDB file with atom scores as B-factors
    --output-residue-scores        string      output text file with residue scores
    --output-residue-scores-pdb    string      output PDB file with residue scores as B-factors
    --output-residue-scores-plot   string      output PNG image file with residue scores plot, requires R
    --help | -h                                flag to display help message and exit

Advanced options:
    --cache-dir                    string      path to cache directory
    --smoothing-window             number      residue scores smoothing window size, default is 5
    --atoms-query                  string      atoms query parameters to define selection
    --contacts-query               string      contacts query parameters to define selection
    --output-selected-scores       string      output text file with selected atom scores
    --reference-sequence           string      sequence file or string for residue renumbering
    --output-sequence-alignment    string      output text file with sequence alignment
    --multiple-models                          flag to handle multiple models in PDB file

Standard output (one line):
    {input file path} {global score} {number of residues} {number of atoms} [ {selection score} {number of selected atoms} ]

EOF
exit 1
}

readonly ZEROARG=$0
INFILE=""
REFERENCE_SEQUENCE=""
INPUT_FILTER_QUERY_PARAMETERS=""
OUTFILE_SEQUENCE_ALIGNMENT=""
OUTFILE_BALLS=""
OUTFILE_CONTACTS=""
OUTFILE_ATOM_SCORES=""
OUTFILE_ATOM_SCORES_PDB=""
OUTFILE_RESIDUE_SCORES=""
OUTFILE_RESIDUE_SCORES_PDB=""
OUTFILE_ATOM_DEPTHS=""
OUTFILE_CAMEO_RESIDUE_SCORES=""
OUTFILE_PLOT=""
OUTFILE_MAP=""
OUTFILE_SCREENSHOT=""
OUTFILE_SCORES_FOR_CASP=""
OUTFILE_SCORES_FOR_CASP_PDB=""
OUTFILE_SCORES_FOR_CASP_LOG=""
OUTFILE_CUTTING_SUGGESTIONS=""
OUTDIR_SUMMARY_FOR_POTENTIAL=""
SMOOTHING_WINDOW="5"
ATOMS_QUERY_PARAMETERS=""
CONTACTS_QUERY_PARAMETERS=""
OUTFILE_SELECTED_ATOM_SCORES=""
CACHE_DIRECTORY=""
MULTIPLE_MODELS_CHAINS_OPTION=""
UNTEACHING_DIRECTORY=""
REBUILD_SIDECHAINS_COMMAND=""
SCREENSHOT_WIDTH="500"
SCREENSHOT_HEIGHT="500"
SCREENSHOT_BACKGROUND="black"
PLOT_MODE="normal"
SURFACE_CRAVING_ATOMS_OUTPUT=""
SURFACE_CRAVING_ATOMS_OUTPUT_PDB=""
SURFACE_CRAVING_RESIDUES_OUTPUT=""
SURFACE_CRAVING_RESIDUES_OUTPUT_PDB=""
SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT=""
NEGLECT_SAS=false
REINTERPRET_SAS=false
MORE_LOGGING=false
PRINT_ENERGY_OF_CONTACTS_SELECTION=false
HELP_MODE=false

while [[ $# > 0 ]]
do
	OPTION="$1"
	OPTARG="$2"
	shift
	case $OPTION in
	-i|--input)
		INFILE="$OPTARG"
		shift
		;;
	--reference-sequence)
		REFERENCE_SEQUENCE="$OPTARG"
		shift
		;;
	--input-filter-query)
		INPUT_FILTER_QUERY_PARAMETERS="$OPTARG"
		shift
		;;
	--output-balls)
		OUTFILE_BALLS="$OPTARG"
		shift
		;;
	--output-contacts)
		OUTFILE_CONTACTS="$OPTARG"
		shift
		;;
	--output-sequence-alignment)
		OUTFILE_SEQUENCE_ALIGNMENT="$OPTARG"
		shift
		;;
	--output-atom-scores)
		OUTFILE_ATOM_SCORES="$OPTARG"
		shift
		;;
	--output-atom-scores-pdb)
		OUTFILE_ATOM_SCORES_PDB="$OPTARG"
		shift
		;;
	--output-residue-scores)
		OUTFILE_RESIDUE_SCORES="$OPTARG"
		shift
		;;
	--output-residue-scores-pdb)
		OUTFILE_RESIDUE_SCORES_PDB="$OPTARG"
		shift
		;;
	--output-atom-depth-values)
		OUTFILE_ATOM_DEPTHS="$OPTARG"
		shift
		;;
	--output-residue-scores-for-CAMEO)
		OUTFILE_CAMEO_RESIDUE_SCORES="$OPTARG"
		shift
		;;
	--output-residue-scores-plot)
		OUTFILE_PLOT="$OPTARG"
		shift
		;;
	--output-contacts-map-svg)
		OUTFILE_MAP="$OPTARG"
		shift
		;;
	--output-screenshot)
		OUTFILE_SCREENSHOT="$OPTARG"
		shift
		;;
	--output-scores-for-CASP)
		OUTFILE_SCORES_FOR_CASP="$OPTARG"
		shift
		;;
	--output-scores-for-CASP-pdb)
		OUTFILE_SCORES_FOR_CASP_PDB="$OPTARG"
		shift
		;;
	--output-scores-for-CASP-log)
		OUTFILE_SCORES_FOR_CASP_LOG="$OPTARG"
		shift
		;;
	--output-cutting-suggestions)
		OUTFILE_CUTTING_SUGGESTIONS="$OPTARG"
		shift
		;;
	--outdir-summary-for-potential)
		OUTDIR_SUMMARY_FOR_POTENTIAL="$OPTARG"
		shift
		;;
	--smoothing-window)
		SMOOTHING_WINDOW="$OPTARG"
		shift
		;;
	--atoms-query)
		ATOMS_QUERY_PARAMETERS="$OPTARG"
		shift
		;;
	--contacts-query)
		CONTACTS_QUERY_PARAMETERS="$OPTARG"
		shift
		;;
	--output-selected-scores)
		OUTFILE_SELECTED_ATOM_SCORES="$OPTARG"
		shift
		;;
	--cache-dir)
		CACHE_DIRECTORY="$OPTARG"
		shift
		;;
	--unteaching-dir)
		UNTEACHING_DIRECTORY="$OPTARG"
		shift
		;;
	--rebuild-sidechains)
		REBUILD_SIDECHAINS_COMMAND="$OPTARG"
		shift
		;;
	--screenshot-width)
		SCREENSHOT_WIDTH="$OPTARG"
		shift
		;;
	--screenshot-height)
		SCREENSHOT_HEIGHT="$OPTARG"
		shift
		;;
	--screenshot-background)
		SCREENSHOT_BACKGROUND="$OPTARG"
		shift
		;;
	--surface-craving-atoms-output)
		SURFACE_CRAVING_ATOMS_OUTPUT="$OPTARG"
		shift
		;;
	--surface-craving-atoms-output-pdb)
		SURFACE_CRAVING_ATOMS_OUTPUT_PDB="$OPTARG"
		shift
		;;
	--surface-craving-residues-output)
		SURFACE_CRAVING_RESIDUES_OUTPUT="$OPTARG"
		shift
		;;
	--surface-craving-residues-output-pdb)
		SURFACE_CRAVING_RESIDUES_OUTPUT_PDB="$OPTARG"
		shift
		;;
	--surface-craving-atoms-energies-output)
		SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT="$OPTARG"
		shift
		;;
	--multiple-models)
		MULTIPLE_MODELS_CHAINS_OPTION="--multimodel-chains"
		;;
	--small-plot)
		PLOT_MODE="small"
		;;
	--neglect-SAS)
		NEGLECT_SAS=true
		;;
	--reinterpret-SAS)
		REINTERPRET_SAS=true
		;;
	--more-logging)
		MORE_LOGGING=true
		;;
	--print-energy-of-contacts-selection)
		PRINT_ENERGY_OF_CONTACTS_SELECTION=true
		;;
	-h|--help)
		HELP_MODE=true
		;;
	*)
		echo >&2 "Error: invalid command line option '$OPTION'"
		exit 1
		;;
	esac
done

if [ -z "$INFILE" ] || $HELP_MODE
then
	print_help_and_exit
fi

if [ -n "$OUTFILE_CAMEO_RESIDUE_SCORES" ] && [ -n "$MULTIPLE_MODELS_CHAINS_OPTION" ]
then
	echo >&2 "Error: '--output-residue-scores-for-CAMEO' and '--multiple-models' cannot be used together"
	exit 1
fi

if [ -n "$REBUILD_SIDECHAINS_COMMAND" ] && [ -n "$MULTIPLE_MODELS_CHAINS_OPTION" ]
then
	echo >&2 "Error: '--rebuild-side-chains' and '--multiple-models' cannot be used together"
	exit 1
fi

if [ -n "$REBUILD_SIDECHAINS_COMMAND" ] && [ -n "$OUTFILE_CAMEO_RESIDUE_SCORES" ]
then
	echo >&2 "Error: '--rebuild-sidechains' and '--output-residue-scores-for-CAMEO' cannot be used together"
	exit 1
fi

if [ -z "$REFERENCE_SEQUENCE" ] && [ -n "$OUTFILE_SEQUENCE_ALIGNMENT" ]
then
	echo >&2 "Error: '--output-sequence-alignment' cannot be used without '--reference-sequence'"
	exit 1
fi

if [ -z "$REFERENCE_SEQUENCE" ] && [ -n "$OUTFILE_SCORES_FOR_CASP" ]
then
	echo >&2 "Error: '--output-scores-for-CASP' cannot be used without '--reference-sequence'"
	exit 1
fi

if [ -z "$OUTFILE_SCORES_FOR_CASP" ] && [ -n "$OUTFILE_SCORES_FOR_CASP_PDB" ]
then
	echo >&2 "Error: '--output-scores-for-CASP-pdb' cannot be used without '--output-scores-for-CASP'"
	exit 1
fi

if [ -z "$OUTFILE_SCORES_FOR_CASP" ] && [ -n "$OUTFILE_SCORES_FOR_CASP_LOG" ]
then
	echo >&2 "Error: '--output-scores-for-CASP-log' cannot be used without '--output-scores-for-CASP'"
	exit 1
fi

if [[ "$ZEROARG" == *"/"* ]]
then
	cd $(dirname $ZEROARG)
	export PATH=$(pwd):$PATH
	cd - &> /dev/null
fi

command -v voronota &> /dev/null || { echo >&2 "Error: 'voronota' executable not in binaries path"; exit 1; }
command -v voronota-resources &> /dev/null || { echo >&2 "Error: 'voronota-resources' executable not in binaries path"; exit 1; }

if [ -n "$OUTFILE_PLOT" ]
then
	command -v R &> /dev/null || { echo >&2 "Error: 'R' command, needed for plotting, is not available"; exit 1; }
fi

if [ -n "$OUTFILE_SCREENSHOT" ]
then
	command -v pymol &> /dev/null || { echo >&2 "Error: 'pymol' command, needed for making screenshots, is not available"; exit 1; }
fi

if [ -n "$REBUILD_SIDECHAINS_COMMAND" ]
then
	command -v $REBUILD_SIDECHAINS_COMMAND &> /dev/null || { echo >&2 "Error: '$REBUILD_SIDECHAINS_COMMAND' command, requested for rebuilding side-chains, is not available"; exit 1; }
fi

readonly TMPLDIR=$(mktemp -d)
trap "rm -r $TMPLDIR" EXIT

if [ -n "$REFERENCE_SEQUENCE" ] && [ ! -s "$REFERENCE_SEQUENCE" ]
then
	if [ "$REFERENCE_SEQUENCE" == "$(echo $REFERENCE_SEQUENCE | tr -dc '[:alpha:]')" ]
	then
		echo "$REFERENCE_SEQUENCE" > "$TMPLDIR/reference_sequence_file"
		REFERENCE_SEQUENCE="$TMPLDIR/reference_sequence_file"
	else
		echo >&2 "Error: invalid reference sequence"
		exit 1
	fi
fi

INFILE_CONTENTS=$INFILE
if [[ "$INFILE" == *"://"* ]]
then
	INFILE_CONTENTS=$TMPLDIR/downloaded_input_file
	curl -s "$INFILE" > $INFILE_CONTENTS
fi

if [ ! -s "$INFILE_CONTENTS" ]
then
	echo >&2 "Error: input file does not exist or is empty"
	exit 1
fi

INFILE_CONTENTS_EXTRACTED=$INFILE_CONTENTS
if [[ "$INFILE" == *".gz" ]]
then
	INFILE_CONTENTS_EXTRACTED=$TMPLDIR/extracted_input_file
	zcat $INFILE_CONTENTS > $INFILE_CONTENTS_EXTRACTED
	if [ ! -s "$INFILE_CONTENTS_EXTRACTED" ]
	then
		echo >&2 "Error: could not extract gzipped file"
		exit 1
	fi
fi

cat $INFILE_CONTENTS_EXTRACTED \
| voronota get-balls-from-atoms-file \
  --annotated $MULTIPLE_MODELS_CHAINS_OPTION \
  --radii-file <(voronota-resources radii) \
  --include-heteroatoms \
| voronota query-balls \
  --match 'R<LEU,ALA,GLY,VAL,GLU,SER,LYS,ILE,ASP,THR,ARG,PRO,ASN,PHE,GLN,TYR,HIS,MET,TRP,CYS,MSE,SEC>' \
| voronota query-balls \
  --drop-adjuncts \
  --drop-altloc-indicators \
| \
{
	if [ -n "$INPUT_FILTER_QUERY_PARAMETERS" ]
	then
		voronota query-balls $INPUT_FILTER_QUERY_PARAMETERS
	else
		cat
	fi
} \
| \
{
	if [ -s "$REFERENCE_SEQUENCE" ]
	then
		voronota query-balls \
		  --set-ref-seq-num-adjunct "$REFERENCE_SEQUENCE" \
		  --ref-seq-alignment $TMPLDIR/sequence_alignment \
		| voronota query-balls \
		  --renumber-from-adjunct refseq \
		| voronota query-balls \
		  --drop-adjuncts
	else
		cat
	fi
} \
| \
{
	if [ -n "$REBUILD_SIDECHAINS_COMMAND" ]
	then
		voronota query-balls \
		  --match 'A<CA,C,N,O,OXT>' \
		| voronota write-balls-to-atoms-file \
		  --pdb-output $TMPLDIR/atoms_stripped.pdb \
		> /dev/null

		$REBUILD_SIDECHAINS_COMMAND -h \
		  -i $TMPLDIR/atoms_stripped.pdb \
		  -o $TMPLDIR/atoms_rebuilt.pdb \
		> /dev/null

		cat $TMPLDIR/atoms_rebuilt.pdb \
		| voronota get-balls-from-atoms-file \
		  --annotated \
		  --radii-file <(voronota-resources radii) \
		| voronota query-balls \
		  --drop-adjuncts
	else
		cat
	fi
} \
> $TMPLDIR/balls

if $MORE_LOGGING && [ -f "$TMPLDIR/sequence_alignment" ]
then
	cat >&2 "$TMPLDIR/sequence_alignment"
fi

if [ -n "$OUTFILE_SEQUENCE_ALIGNMENT" ] && [ -f "$TMPLDIR/sequence_alignment" ]
then
	cp "$TMPLDIR/sequence_alignment" "$OUTFILE_SEQUENCE_ALIGNMENT"
fi

if [ ! -s "$TMPLDIR/balls" ]
then
	echo >&2 "Error: no atoms in input file"
	exit 1
fi

if [ -n "$OUTFILE_BALLS" ]
then
	mkdir -p $(dirname $OUTFILE_BALLS)
	cp "$TMPLDIR/balls" "$OUTFILE_BALLS"
fi

BALLS_MD5=""
if [ -n "$CACHE_DIRECTORY" ]
then
	BALLS_MD5=$(cat $TMPLDIR/balls | md5sum | awk '{print $1}')
	if [ -n "$BALLS_MD5" ]
	then
		BALLS_MD5="${BALLS_MD5}.voronota.voromqa"
		if [ -d "$CACHE_DIRECTORY/$BALLS_MD5" ] && [ -s "$CACHE_DIRECTORY/$BALLS_MD5/all_contacts" ] && [ -s "$CACHE_DIRECTORY/$BALLS_MD5/atom_energies" ] && [ -s "$CACHE_DIRECTORY/$BALLS_MD5/depth_values" ]
		then
			cp -r $CACHE_DIRECTORY/$BALLS_MD5 $TMPLDIR/foundation
		fi
	fi
fi

if [ ! -d "$TMPLDIR/foundation" ]
then
	mkdir -p $TMPLDIR/foundation
	
	cat $TMPLDIR/balls \
	| voronota calculate-contacts \
	  --annotated \
	  --tag-centrality \
	| tee $TMPLDIR/foundation/raw_contacts \
	| voronota query-contacts \
	  --match-min-seq-sep 1 \
	| voronota query-contacts \
	  --match-first 'A<C>' \
	  --match-second 'A<N>' \
	  --match-max-seq-sep 1 \
	  --match-max-dist 1.6 \
	  --invert \
	| voronota query-contacts \
	  --match-min-seq-sep 1 \
	  --match-max-seq-sep 1 \
	  --set-tags 'sep1' \
	| voronota query-contacts \
	  --match-min-seq-sep 2 \
	  --no-solvent \
	  --set-tags 'sep2' \
	| tee $TMPLDIR/foundation/all_contacts \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| tee $TMPLDIR/contacts \
	| voronota score-contacts-energy \
	  --potential-file <(voronota-resources energy_potential) \
	  --atom-scores-file $TMPLDIR/foundation/atom_energies \
	> /dev/null
	
	cat $TMPLDIR/contacts \
	| voronota x-query-contacts-depth-values \
	> $TMPLDIR/foundation/depth_values
	
	if [ -n "$CACHE_DIRECTORY" ] && [ -n "$BALLS_MD5" ]
	then
		mkdir -p $CACHE_DIRECTORY
		cp -r $TMPLDIR/foundation $CACHE_DIRECTORY/$BALLS_MD5
	fi
fi

if [ -n "$OUTFILE_CONTACTS" ]
then
	mkdir -p $(dirname $OUTFILE_CONTACTS)
	cp "$TMPLDIR/foundation/all_contacts" "$OUTFILE_CONTACTS"
fi

if $NEGLECT_SAS
then
	cat $TMPLDIR/foundation/all_contacts \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| sed 's|c<solvent>\s\+.\s\+\S\+$|c<solvent> . 0.001|' \
	| voronota score-contacts-energy \
	  --potential-file <(voronota-resources energy_potential) \
	  --atom-scores-file $TMPLDIR/foundation/atom_energies \
	> /dev/null
fi

if $REINTERPRET_SAS
then
	cat $TMPLDIR/foundation/all_contacts \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| voronota score-contacts-energy \
	  --potential-file <(voronota-resources energy_potential | voronota x-simulate-potential-for-membrane-proteins) \
	  --atom-scores-file $TMPLDIR/foundation/atom_energies \
	> /dev/null
fi

if [ -n "$OUTFILE_CUTTING_SUGGESTIONS" ]
then
	mkdir -p $(dirname "$OUTFILE_CUTTING_SUGGESTIONS")
	cat $TMPLDIR/foundation/all_contacts \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| voronota x-score-contacts-global-energy-by-cuts \
	  --potential-file <(voronota-resources energy_potential) \
	  --limit-results 10 \
	| column -t \
	> "$OUTFILE_CUTTING_SUGGESTIONS"
fi

if [ -n "$OUTDIR_SUMMARY_FOR_POTENTIAL" ]
then
	mkdir -p "$OUTDIR_SUMMARY_FOR_POTENTIAL"

	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --chains-summary-output $TMPLDIR/chains_counts \
	> /dev/null

	cat $TMPLDIR/foundation/all_contacts \
	| voronota query-contacts \
	  --match-min-seq-sep 2 \
	  --match-max-seq-sep 6 \
	  --set-tags 'sep1' \
	| sed 's/sep1;sep2/sep1/' \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| voronota score-contacts-potential \
	  --multiply-areas $(cat $TMPLDIR/chains_counts | head -1 | awk '{print (24.0/$1*$2)}') \
	> "$OUTDIR_SUMMARY_FOR_POTENTIAL/$(basename $INFILE .gz)"

	exit 0
fi

if [ -n "$UNTEACHING_DIRECTORY" ] && [ -s "$UNTEACHING_DIRECTORY/contact_areas" ] && [ -s "$UNTEACHING_DIRECTORY/contact_categories" ]
then
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --chains-summary-output $TMPLDIR/chains_counts \
	> /dev/null

	{
		cat $UNTEACHING_DIRECTORY/contact_areas
		
		cat $TMPLDIR/foundation/all_contacts \
		| voronota query-contacts \
		  --match-min-seq-sep 2 \
		  --match-max-seq-sep 6 \
		  --set-tags 'sep1' \
		| sed 's/sep1;sep2/sep1/' \
		| awk '{print $1 " " $2 " " $5 " " $3}' \
		| tr ';' '_' \
		| voronota score-contacts-potential \
		  --multiply-areas $(cat $TMPLDIR/chains_counts | head -1 | awk '{print (24.0/$1*$2)}') \
		| awk '{print $1 " " $2 " " $3 " -" $4}'
	} \
	| voronota score-contacts-potential \
	  --input-contributions $UNTEACHING_DIRECTORY/contact_categories \
	  --potential-file $TMPLDIR/untaught_potential \
	> /dev/null

	cat $TMPLDIR/foundation/all_contacts \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| voronota score-contacts-energy \
	  --potential-file $TMPLDIR/untaught_potential \
	  --atom-scores-file $TMPLDIR/foundation/atom_energies \
	> /dev/null
fi

cat $TMPLDIR/foundation/atom_energies \
| voronota score-contacts-quality \
  --default-mean -0.34 \
  --default-sd 0.19 \
  --means-and-sds-file <(voronota-resources energy_means_and_sds) \
  --external-weights-file $TMPLDIR/foundation/depth_values \
  --smoothing-window $SMOOTHING_WINDOW \
  --atom-scores-file $TMPLDIR/atom_quality_scores \
  --residue-scores-file $TMPLDIR/residue_quality_scores \
> $TMPLDIR/global_quality_score

if [ ! -s "$TMPLDIR/global_quality_score" ] || [ ! -s "$TMPLDIR/atom_quality_scores" ] || [ ! -s "$TMPLDIR/residue_quality_scores" ]
then
	echo >&2 "Error: failed to calculate scores"
	exit 1
fi

if [ -n "$ATOMS_QUERY_PARAMETERS" ] || [ -n "$CONTACTS_QUERY_PARAMETERS" ]
then
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --set-external-adjuncts $TMPLDIR/foundation/depth_values \
	  --set-external-adjuncts-name depth \
	| voronota query-balls $ATOMS_QUERY_PARAMETERS \
	| awk '{print $1}' \
	> $TMPLDIR/selection_by_atoms_query
	
	cat $TMPLDIR/foundation/all_contacts \
	| voronota query-contacts $CONTACTS_QUERY_PARAMETERS \
	| awk '{print $1 " " $2}' | tr ' ' '\n' | sort | uniq | grep -v solvent \
	> $TMPLDIR/selection_by_contacts_query
	
	join -e EMPTY <(sort -k 1b,1 $TMPLDIR/selection_by_atoms_query) <(sort -k 1b,1 $TMPLDIR/selection_by_contacts_query) \
	| grep -v EMPTY \
	> $TMPLDIR/selection_by_queries
	
	join -e EMPTY <(sort -k 1b,1 $TMPLDIR/foundation/depth_values) <(sort -k 1b,1 $TMPLDIR/selection_by_queries) \
	| grep -v EMPTY \
	| awk '{print $1 " " $2}' \
	> $TMPLDIR/scoring_domain
	
	join -e EMPTY <(sort -k 1b,1 $TMPLDIR/scoring_domain) <(sort -k 1b,1 $TMPLDIR/atom_quality_scores) \
	| grep -v EMPTY \
	> $TMPLDIR/scoring_table
	
	{
		if [ -s "$TMPLDIR/scoring_table" ]
		then
			cat $TMPLDIR/scoring_table | awk '{sum+=$2;wsum+=($2*$3)} END {print (wsum/sum)}'
			cat $TMPLDIR/scoring_table | wc -l
		else
			echo "0"
			echo "0"
		fi
	} > $TMPLDIR/global_quality_score_of_selection
fi

if [ -n "$OUTFILE_ATOM_SCORES" ]
then
	mkdir -p $(dirname "$OUTFILE_ATOM_SCORES")
	cp $TMPLDIR/atom_quality_scores "$OUTFILE_ATOM_SCORES"
fi

if [ -n "$OUTFILE_RESIDUE_SCORES" ]
then
	mkdir -p $(dirname "$OUTFILE_RESIDUE_SCORES")
	cp $TMPLDIR/residue_quality_scores "$OUTFILE_RESIDUE_SCORES"
fi

if [ -n "$OUTFILE_SELECTED_ATOM_SCORES" ] && [ -f "$TMPLDIR/scoring_table" ]
then
	mkdir -p $(dirname "$OUTFILE_SELECTED_ATOM_SCORES")
	cat $TMPLDIR/scoring_table \
	| awk '{print $1 " " $3}' \
	| sort -V \
	> "$OUTFILE_SELECTED_ATOM_SCORES"
fi

if [ -n "$OUTFILE_ATOM_SCORES_PDB" ]
then
	mkdir -p $(dirname "$OUTFILE_ATOM_SCORES_PDB")
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --drop-altloc-indicators \
	  --set-adjuncts 'oc=1' \
	  --set-external-adjuncts $TMPLDIR/atom_quality_scores \
	  --set-external-adjuncts-name score \
	| \
	{
		if [ -s "$TMPLDIR/selection_by_queries" ]
		then
			voronota query-balls \
			  --match-external-annotations $TMPLDIR/selection_by_queries \
			  --set-adjuncts 'oc=2'
		else
			cat
		fi
	} \
	| voronota write-balls-to-atoms-file \
	  --pdb-output "$OUTFILE_ATOM_SCORES_PDB" \
	  --pdb-output-b-factor score \
	> /dev/null
fi

if [ -n "$OUTFILE_RESIDUE_SCORES_PDB" ]
then
	mkdir -p $(dirname "$OUTFILE_RESIDUE_SCORES_PDB")
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --drop-altloc-indicators \
	  --set-adjuncts 'oc=1' \
	  --set-external-adjuncts $TMPLDIR/residue_quality_scores \
	  --set-external-adjuncts-name score \
	| voronota write-balls-to-atoms-file \
	  --pdb-output "$OUTFILE_RESIDUE_SCORES_PDB" \
	  --pdb-output-b-factor score \
	> /dev/null
fi

if [ -n "$OUTFILE_ATOM_DEPTHS" ]
then
	mkdir -p $(dirname $OUTFILE_ATOM_DEPTHS)
	cp $TMPLDIR/foundation/depth_values "$OUTFILE_ATOM_DEPTHS"
fi

if [ -n "$OUTFILE_CAMEO_RESIDUE_SCORES" ]
then
	mkdir -p $(dirname $OUTFILE_CAMEO_RESIDUE_SCORES)
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --set-external-adjuncts <(awk '{print $1 " " (10*(1-$2))}' $TMPLDIR/residue_quality_scores) \
	  --set-external-adjuncts-name rqscore \
	| voronota write-balls-to-atoms-file \
	  --pdb-output $OUTFILE_CAMEO_RESIDUE_SCORES \
	  --pdb-output-b-factor rqscore \
	  --pdb-output-template $INFILE_CONTENTS_EXTRACTED \
	> /dev/null
fi

if [ -n "$OUTFILE_PLOT" ]
then

mkdir -p $(dirname $OUTFILE_PLOT)

cat $TMPLDIR/foundation/atom_energies \
| voronota score-contacts-quality \
  --default-mean -0.34 \
  --default-sd 0.19 \
  --means-and-sds-file <(voronota-resources energy_means_and_sds) \
  --external-weights-file $TMPLDIR/foundation/depth_values \
  --smoothing-window "$(echo "0,$SMOOTHING_WINDOW" | sed 's|^0,\(.\+,.\+\).*|\1|')" \
  --residue-scores-file $TMPLDIR/residue_quality_scores_for_plot \
> /dev/null

cat $TMPLDIR/residue_quality_scores_for_plot \
| voronota expand-descriptors \
> $TMPLDIR/table_for_plot

BACK_FILE="none"
if [ -s "$TMPLDIR/selection_by_queries" ]
then
	cat $TMPLDIR/selection_by_queries \
	| voronota expand-descriptors \
	| awk '{print $1 " " $2}' | sort | uniq \
	> $TMPLDIR/back_table_for_plot
	if [ -s "$TMPLDIR/back_table_for_plot" ]
	then
		BACK_FILE="$TMPLDIR/back_table_for_plot"
	fi
fi

R --slave --vanilla --args "$TMPLDIR/table_for_plot" "$BACK_FILE" "$OUTFILE_PLOT" "$PLOT_MODE" << 'EOF' &> /dev/null
	args=commandArgs(TRUE);
	infile=args[1];
	back_infile=args[2];
	outfile=args[3];
	plot_mode=args[4];
	
	t=read.table(infile, header=FALSE, stringsAsFactors=FALSE);
	chains=sort(union(t$V1, t$V1));
	
	back_t=c();
	if(back_infile!="none")
	{
		back_t=read.table(back_infile, header=FALSE, stringsAsFactors=FALSE);
	}
	
	if(plot_mode=="small")
	{
		png(filename=outfile, width=8*length(chains), height=2.5, units="in", res=80);
		par(mfcol=c(1, length(chains)));
		par(mar=c(2.7,3,1,1));
	} else
	{
		png(filename=outfile, width=10, height=5*length(chains), units="in", res=200);
		par(mfrow=c(length(chains), 1));
	}

	for(chain in chains)
	{
		title=ifelse(chain==".", "VoroMQA local scores for the unnamed chain", paste("VoroMQA local scores for chain ", chain, sep=""));
		
		st=t[which(t$V1==chain),];
		resnums=st$V2;
		v1=st$V8;
		v2=st$V9;
		N=length(v1);
		mask=rep(0, N);
		duplicate=identical(v1, v2);
		
		thick_color=rgb(0.0, 0.0, 0.0);
		thick_color_back=rgb(1.0, 0.0, 0.0);
		thin_color=ifelse(duplicate, thick_color, rgb(0.7, 0.7, 0.7));
		thin_color_back=ifelse(duplicate, thick_color_back, rgb(1.0, 0.7, 0.7));
		
		if(plot_mode=="small")
		{
			plot(c(min(resnums),max(resnums)), c(0, 1), type="n", main="", xlab="", ylab="");
		} else
		{
			plot(c(min(resnums),max(resnums)), c(0, 1), type="n", main=title, xlab="Residue number", ylab="Score");
		}
		
		points(c(min(resnums)-50,max(resnums)+50), c(0.5, 0.5), type="l");
		
		back_resnums=c();
		if(length(back_t)>0)
		{
			back_resnums=back_t$V2[which(back_t$V1==chain)];
		}
		
		resnums_col=rep(thin_color, N);
		resnums_col[which(is.element(resnums, back_resnums))]=thin_color_back;
		i=1;
		while(i<N)
		{
			if((resnums[i+1]-resnums[i])<2)
			{
				points(c(resnums[i], resnums[i+1]), c(v1[i], v1[i+1]), type="l", col=c(resnums_col[i], resnums_col[i+1]), lwd=1);
				mask[i]=1; mask[i+1]=1;
			}
			i=i+1;
		}
		sel=which(mask==0);
		if(length(sel)>0)
		{
			points(resnums[sel], v1[sel], col=resnums_col[sel], pch=16, cex=0.5);
		}
		
		if(duplicate==FALSE)
		{
			resnums_col=rep(thick_color, N);
			resnums_col[which(is.element(resnums, back_resnums))]=thick_color_back;
			i=1;
			while(i<N)
			{
				if((resnums[i+1]-resnums[i])<2)
				{
					points(c(resnums[i], resnums[i+1]), c(v2[i], v2[i+1]), type="l", col=c(resnums_col[i], resnums_col[i+1]), lwd=3);
				}
				i=i+1;
			}
			sel=which(mask==0);
			if(length(sel)>0)
			{
				points(resnums[sel], v2[sel], col=resnums_col[sel], pch=16, cex=0.7);
			}
		}
	}
	
	dev.off();
EOF
fi

if [ -n "$OUTFILE_MAP" ]
then
	mkdir -p $(dirname $OUTFILE_MAP)
	cat $TMPLDIR/foundation/all_contacts \
	| voronota query-contacts \
	  --drop-adjuncts \
	  --set-external-means $TMPLDIR/atom_quality_scores \
	| voronota query-contacts \
	  --no-solvent \
	  --match-adjuncts em=0:1 \
	| sed 's|em=||' \
	| awk '{print $1 " " $2 " " $3 " " $4 " " $5 " em=" ($3*$6)}' \
	| voronota query-contacts \
	  --inter-residue \
	| sed 's|em=||' \
	| awk '{print $1 " " $2 " " $3 " " $4 " " $5 " em=" ($6/$3)}' \
	| voronota x-plot-contacts \
	  --adjunct-gradient em \
	  --adjunct-gradient-blue 1 \
	  --adjunct-gradient-red 0 \
	  --svg-output $TMPLDIR/map.svg \
	> /dev/null
	mv $TMPLDIR/map.svg $OUTFILE_MAP
fi

if [ -n "$OUTFILE_SCORES_FOR_CASP" ] && [ -s "$TMPLDIR/sequence_alignment" ]
then
	mkdir -p $(dirname "$OUTFILE_SCORES_FOR_CASP")
	voronota x-write-qa-scores-in-casp-format \
	  --name "$(basename $INFILE)" \
	  --global-score "$(cat $TMPLDIR/global_quality_score)" \
	  --sequence-length "$(cat $TMPLDIR/sequence_alignment | head -1 | tr -d '-' | tr -d ' ' | tr -d '\n' | tr -d '\t' | wc -c)" \
	  --local-scores "$TMPLDIR/residue_quality_scores" \
	  --wrap_size 20 \
	  --completeness-threshold 0.85 \
	  --converted-local-scores "$TMPLDIR/residue_quality_scores_for_casp" \
	> "$OUTFILE_SCORES_FOR_CASP"
	
	if [ -n "$OUTFILE_SCORES_FOR_CASP_LOG" ]
	then
		mkdir -p $(dirname "$OUTFILE_SCORES_FOR_CASP_LOG")
		paste \
		  "$TMPLDIR/residue_quality_scores" \
		  "$TMPLDIR/residue_quality_scores_for_casp" \
		| column -t \
		> "$OUTFILE_SCORES_FOR_CASP_LOG"
	fi
	
	if [ -n "$OUTFILE_SCORES_FOR_CASP_PDB" ]
	then
		mkdir -p $(dirname "$OUTFILE_SCORES_FOR_CASP_PDB")
		cat $TMPLDIR/balls \
		| voronota query-balls \
		  --drop-altloc-indicators \
		  --set-adjuncts 'oc=1' \
		  --set-external-adjuncts "$TMPLDIR/residue_quality_scores_for_casp" \
		  --set-external-adjuncts-name score \
		| voronota write-balls-to-atoms-file \
		  --pdb-output "$OUTFILE_SCORES_FOR_CASP_PDB" \
		  --pdb-output-b-factor score \
		> /dev/null
	fi
fi

if [ -n "$OUTFILE_SCREENSHOT" ]
then
	cat $TMPLDIR/balls \
	| voronota query-balls \
	  --drop-altloc-indicators \
	  --set-adjuncts 'oc=1' \
	  --set-external-adjuncts "$TMPLDIR/residue_quality_scores" \
	  --set-external-adjuncts-name score \
	| voronota write-balls-to-atoms-file \
	  --pdb-output "$TMPLDIR/structure_for_screenshot.pdb" \
	  --pdb-output-b-factor score \
	> /dev/null
	
	mkdir -p $(dirname "$OUTFILE_SCREENSHOT")

pymol -W "$SCREENSHOT_WIDTH" -H "$SCREENSHOT_HEIGHT" -p -c "$TMPLDIR/structure_for_screenshot.pdb" &> /dev/null << EOF
	set all_states, on
	hide all
	bg_color $SCREENSHOT_BACKGROUND
	show cartoon
	spectrum b, red_white_blue, minimum=0, maximum=1
	orient
	center
	zoom complete=1
	save $OUTFILE_SCREENSHOT
	quit
EOF

fi

if $PRINT_ENERGY_OF_CONTACTS_SELECTION
then
	cat $TMPLDIR/foundation/all_contacts \
	| voronota query-contacts $CONTACTS_QUERY_PARAMETERS \
	| awk '{print $1 " " $2 " " $5 " " $3}' \
	| tr ';' '_' \
	| voronota score-contacts-energy \
	  --potential-file <(voronota-resources energy_potential) \
	| awk '{print $5 " " $2 " " $3 " " $4 " " ($4/($2+$3))}' \
	> $TMPLDIR/energy_descriptor_of_contacts_selection
fi

{
echo $INFILE
cat $TMPLDIR/global_quality_score
cat $TMPLDIR/balls | grep 'A<CA>' | wc -l
cat $TMPLDIR/balls | wc -l
if [ -s "$TMPLDIR/global_quality_score_of_selection" ]
then
	cat $TMPLDIR/global_quality_score_of_selection
fi
if [ -s "$TMPLDIR/energy_descriptor_of_contacts_selection" ]
then
	cat $TMPLDIR/energy_descriptor_of_contacts_selection
fi
} \
| tr '\n' ' ' \
| sed 's/\s$/\n/'

if [ -n "$SURFACE_CRAVING_ATOMS_OUTPUT" ] || [ -n "$SURFACE_CRAVING_ATOMS_OUTPUT_PDB" ] || [ -n "$SURFACE_CRAVING_RESIDUES_OUTPUT" ] || [ -n "$SURFACE_CRAVING_RESIDUES_OUTPUT_PDB" ] || [ -n "$SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT" ]
then
	{
		echo "c<solvent>"
		cat $TMPLDIR/foundation/depth_values \
		| egrep ' 1$' \
		| awk '{print $1}'
	} > $TMPLDIR/exposure_ids

	cat $TMPLDIR/foundation/raw_contacts \
	| voronota query-contacts \
	  --match-external-first $TMPLDIR/exposure_ids \
	  --match-external-second $TMPLDIR/exposure_ids \
	| awk '{if($2=="c<solvent>") {print $1 " " $2 " " $5 " " $3} else {print $1 " " $2 " " $5 " 0"}}' \
	| tr ';' '_' \
	| voronota score-contacts-energy \
	  --potential-file <(voronota-resources energy_potential) \
	  --depth 3 \
	  --atom-scores-file $TMPLDIR/surface_atom_energies \
	> /dev/null
	
	cat $TMPLDIR/surface_atom_energies \
	| voronota score-contacts-quality \
	  --default-mean 0.13 \
	  --default-sd 0.13 \
	  --smoothing-window 0 \
	  --atom-scores-file $TMPLDIR/surface_atom_quality_scores \
	  --residue-scores-file $TMPLDIR/surface_residue_quality_scores \
	> /dev/null
	
	cat $TMPLDIR/surface_atom_quality_scores \
	| awk '{print $1 " " (1-$2)}' \
	> $TMPLDIR/surface_atom_craving_scores
	
	cat $TMPLDIR/surface_residue_quality_scores \
	| awk '{print $1 " " (1-$2)}' \
	> $TMPLDIR/surface_residue_craving_scores
	
	if [ -n "$SURFACE_CRAVING_ATOMS_OUTPUT" ]
	then
		mkdir -p $(dirname "$SURFACE_CRAVING_ATOMS_OUTPUT")
		cp $TMPLDIR/surface_atom_craving_scores "$SURFACE_CRAVING_ATOMS_OUTPUT"
	fi
	
	if [ -n "$SURFACE_CRAVING_RESIDUES_OUTPUT" ]
	then
		mkdir -p $(dirname "$SURFACE_CRAVING_RESIDUES_OUTPUT")
		cp $TMPLDIR/surface_residue_craving_scores "$SURFACE_CRAVING_RESIDUES_OUTPUT"
	fi
	
	if [ -n "$SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT" ]
	then
		mkdir -p $(dirname "$SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT")
		cp $TMPLDIR/surface_atom_energies "$SURFACE_CRAVING_ATOMS_ENERGIES_OUTPUT"
	fi
	
	if [ -n "$SURFACE_CRAVING_ATOMS_OUTPUT_PDB" ]
	then
		mkdir -p $(dirname "$SURFACE_CRAVING_ATOMS_OUTPUT_PDB")
		
		cat $TMPLDIR/balls \
		| voronota query-balls \
		  --drop-altloc-indicators \
		  --set-adjuncts 'oc=1' \
		  --set-external-adjuncts $TMPLDIR/surface_atom_craving_scores \
		  --set-external-adjuncts-name score \
		| voronota write-balls-to-atoms-file \
		  --pdb-output "$SURFACE_CRAVING_ATOMS_OUTPUT_PDB" \
		  --pdb-output-b-factor score \
		> /dev/null
	fi
	
	if [ -n "$SURFACE_CRAVING_RESIDUES_OUTPUT_PDB" ]
	then
		mkdir -p $(dirname "$SURFACE_CRAVING_RESIDUES_OUTPUT_PDB")
		
		cat $TMPLDIR/balls \
		| voronota query-balls \
		  --drop-altloc-indicators \
		  --set-adjuncts 'oc=1' \
		  --set-external-adjuncts $TMPLDIR/surface_residue_craving_scores \
		  --set-external-adjuncts-name score \
		| voronota write-balls-to-atoms-file \
		  --pdb-output "$SURFACE_CRAVING_RESIDUES_OUTPUT_PDB" \
		  --pdb-output-b-factor score \
		> /dev/null
	fi
fi
