#!/bin/bash

function print_help_and_exit
{
cat >&2 << 'EOF'

'voronota-js-global-cadscore' script computes global CAD-score between molecular structures.

Options:
    --target | -t             string  *  target file path
    --model | -m              string  *  model file path or '_list' to read file paths from stdin
    --restrict-input          string     query to restrict input atoms, default is '[]'
    --subselect-contacts      string     query to subselect contacts, default is '[]'
    --output-table-file       string     output table file path, default is '_stdout' to print to stdout
    --processors              number     maximum number of processors to run in parallel, default is 1
    --sbatch-parameters       string     sbatch parameters to run in parallel, default is ''
    --stdin-file              string     input file path to replace stdin
    --run-faspr               string     path to FASPR binary to rebuild side-chains
    --permuting-allowance     number     maximum number of chains for exhaustive remapping, default is 4
    --as-assembly                        flag to treat input files as biological assemblies
    --include-heteroatoms                flag to not discard heteroatoms
    --remap-chains                       flag to calculate and use optimal chains remapping
    --remap-chains-logging               flag to print log of chains remapping to stderr
    --ignore-residue-names               flag to ignore residue names in residue identifiers
    --test-common-ids                    flag to fail quickly if there are no common residues
    --crude                              flag to enable very crude faster mode
    --lt                                 flag to enable faster mode based on Voronota-LT
    --help | -h                          flag to display help message and exit

Standard output:
    space-separated table of scores
    
Examples:

    voronota-js-global-cadscore --target target.pdb --model model.pdb --lt
    
    ls *.pdb | voronota-js-global-cadscore --target target.pdb --model _list --lt --processors 8 | column -t

EOF
exit 1
}

function cat_stdin
{
	STDIN_SOURCE="$1"
	if [ "$STDIN_SOURCE" == "_stream" ]
	then
		cat
	else
		cat "$STDIN_SOURCE"
	fi
}

readonly ZEROARG=$0
ALLARGS=("$@")

if [ -z "$1" ]
then
	print_help_and_exit
fi

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

export LC_ALL=C

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

TARGET_INFILE=""
MODEL_INFILE=""
RESTRICT_INPUT="[]"
SUBSELECT_CONTACTS="[]"
OUTPUT_TABLE_FILE="_stdout"
MAX_PROCESSORS="1"
SBATCH_PARAMETERS=""
STDIN_FILE="_stream"
RUN_FASPR=""
PERMUTATION_ALLOWANCE="4"
SHUFFLE_CHAINS=""
INVERT_CASE_OF_CHAINS="false"
TARGET_INPUT_IS_SCRIPT="false"
MODEL_INPUT_IS_SCRIPT="false"
AS_ASSEMBLY="false"
INCLUDE_HETEROATOMS="false"
REMAP_CHAINS="false"
REMAP_CHAINS_LOGGING="false"
IGNORE_RESIDUE_NAMES="false"
TEST_COMMON_IDS="false"
CRUDE_MODE="false"
VORONOTALT_MODE="false"
HELP_MODE="false"

while [[ $# > 0 ]]
do
	OPTION="$1"
	OPTARG="$2"
	shift
	case $OPTION in
	-t|--target)
		TARGET_INFILE="$OPTARG"
		shift
		;;
	-m|--model)
		MODEL_INFILE="$OPTARG"
		shift
		;;
	--restrict-input)
		RESTRICT_INPUT="$OPTARG"
		shift
		;;
	--subselect-contacts)
		SUBSELECT_CONTACTS="$OPTARG"
		shift
		;;
	--output-table-file)
		OUTPUT_TABLE_FILE="$OPTARG"
		shift
		;;
	--processors)
		MAX_PROCESSORS="$OPTARG"
		shift
		;;
	--sbatch-parameters)
		SBATCH_PARAMETERS="$OPTARG"
		shift
		;;
	--stdin-file)
		STDIN_FILE="$OPTARG"
		shift
		;;
	--run-faspr)
		RUN_FASPR="$OPTARG"
		shift
		;;
	--permuting-allowance)
		PERMUTATION_ALLOWANCE="$OPTARG"
		shift
		;;
	--shuffle-chains)
		SHUFFLE_CHAINS="$OPTARG"
		shift
		;;
	--invert-case-of-chains)
		INVERT_CASE_OF_CHAINS="true"
		;;
	--target-input-is-script)
		TARGET_INPUT_IS_SCRIPT="true"
		;;
	--model-input-is-script)
		MODEL_INPUT_IS_SCRIPT="true"
		;;
	--as-assembly)
		AS_ASSEMBLY="true"
		;;
	--include-heteroatoms)
		INCLUDE_HETEROATOMS="true"
		;;
	--remap-chains)
		REMAP_CHAINS="true"
		;;
	--remap-chains-logging)
		REMAP_CHAINS_LOGGING="true"
		;;
	--ignore-residue-names)
		IGNORE_RESIDUE_NAMES="true"
		;;	
	--test-common-ids)
		TEST_COMMON_IDS="true"
		;;
	--crude)
		CRUDE_MODE="true"
		;;
	--lt)
		VORONOTALT_MODE="true"
		;;
	-h|--help)
		HELP_MODE="true"
		;;
	*)
		echo >&2 "Error: invalid command line option '$OPTION'"
		exit 1
		;;
	esac
done

if [ "$HELP_MODE" == "true" ]
then
	print_help_and_exit
fi

if [ -n "$GLOBAL_VORONOTA_JS_INCLUDE_HETEROATOMS" ]
then
	INCLUDE_HETEROATOMS="$GLOBAL_VORONOTA_JS_INCLUDE_HETEROATOMS"
fi

if [ -z "$TARGET_INFILE" ]
then
	echo >&2 "Error: target input file not provided"
	exit 1
fi

if [ "$TARGET_INFILE" == "_all_vs_all" ] && [ "$MODEL_INFILE" != "_list" ]
then
	echo >&2 "Error: target parameter '_all_vs_all' supported only if model parameter is '_list'"
	exit 1
fi

if [ "$INCLUDE_HETEROATOMS" == "true" ] && [ "$CRUDE_MODE" == "true" ]
then
	echo >&2 "Error: crude mode is not supported for heteroatoms"
	exit 1
fi

if [ -n "$RUN_FASPR" ] && [ ! -s "$RUN_FASPR" ]
then
	echo >&2 "Error: FASPR binary file '$RUN_FASPR' does not exist"
	exit 1
fi

if [ "$TARGET_INFILE" == "_all_vs_all" ]
then
	if [ "$MODEL_INFILE" != "_list" ]
	then
		echo >&2 "Error: target parameter '_all_vs_all' supported only if model parameter is '_list'"
		exit 1
	fi
	
	if [ -n "$SBATCH_PARAMETERS" ]
	then
		echo >&2 "Error: target parameter '_all_vs_all' is currently not supported for running using sbatch"
		exit 1
	fi
	
	readonly TMPLDIR=$(mktemp -d)
	trap "rm -r $TMPLDIR" EXIT
	
	cat_stdin "$STDIN_FILE" | egrep . | sort | uniq > "$TMPLDIR/input_list"
	
	if [ ! -s "$TMPLDIR/input_list" ]
	then
		echo >&2 "Error: no stdin data"
		exit 1
	fi
	
	mkdir -p "$TMPLDIR/per_target_tables"
	
	cat "$TMPLDIR/input_list" \
	| awk -v stdin_file="$TMPLDIR/input_list" -v outdir="$TMPLDIR/per_target_tables" '{print "--target " $1 " --model _list --stdin-file " stdin_file " --output-table-file " outdir "/" NR ".txt"}' \
	| xargs -L 1 -P "$MAX_PROCESSORS" "$ZEROARG" "${ALLARGS[@]}" --processors 1
	
	{
		find "$TMPLDIR/per_target_tables" -type f -not -empty | sort | head -1 | xargs -L 1 head -1
		find "$TMPLDIR/per_target_tables" -type f -not -empty | sort | xargs -L 1 tail -n +2 | sort
	} > "$TMPLDIR/all_targets_output_table"
	
	if [ -n "$OUTPUT_TABLE_FILE" ] && [ "$OUTPUT_TABLE_FILE" != "_stdout" ]
	then
		mkdir -p "$(dirname "$OUTPUT_TABLE_FILE")"
		cat "$TMPLDIR/all_targets_output_table" > "$OUTPUT_TABLE_FILE"
	else
		cat "$TMPLDIR/all_targets_output_table"
	fi
	
	exit 0
fi

if [ ! -s "$TARGET_INFILE" ]
then
	echo >&2 "Error: target input file '$TARGET_INFILE' does not exist"
	exit 1
fi

if [ -z "$MODEL_INFILE" ]
then
	echo >&2 "Error: model input file not provided"
	exit 1
fi

if [ "$MODEL_INFILE" != "_list" ] && [ "$MODEL_INFILE" != "_stream" ] && [ ! -s "$MODEL_INFILE" ]
then
	echo >&2 "Error: model input file '$MODEL_INFILE' does not exist"
	exit 1
fi

if [ "$MODEL_INFILE" == "_stream" ]
then
	readonly TMPLDIR=$(mktemp -d)
	trap "rm -r $TMPLDIR" EXIT
	
	cat_stdin "$STDIN_FILE" > "$TMPLDIR/input_stream"
	
	if [ ! -s "$TMPLDIR/input_stream" ]
	then
		echo >&2 "Error: no stdin data"
		exit 1
	fi
	
	"$ZEROARG" "${ALLARGS[@]}" --model "$TMPLDIR/input_stream"
	
	exit 0
fi

if [ -z "$MAX_PROCESSORS" ] || [ "$MAX_PROCESSORS" -ne "$MAX_PROCESSORS" ] || [ "$MAX_PROCESSORS" -lt "1" ]
then
	echo >&2 "Error: invalid number of processors '$MAX_PROCESSORS', must be a positive number"
	exit 1
fi

if [ -n "$SBATCH_PARAMETERS" ]
then
	command -v sbatch &> /dev/null || { echo >&2 "Error: 'sbatch' executable not in binaries path"; exit 1; }
	command -v squeue &> /dev/null || { echo >&2 "Error: 'squeue' executable not in binaries path"; exit 1; }
	
	if [ "$MODEL_INFILE" != "_list" ]
	then
		echo >&2 "Error: sbatch usage requested, but input is not '_list'"
		exit 1
	fi
	
	if [ "$MAX_PROCESSORS" -lt "2" ]
	then
		echo >&2 "Error: sbatch usage requested, but requested number of processors is less than 2"
		exit 1
	fi
fi

if [ "$MODEL_INFILE" == "_list" ] && [ "$MAX_PROCESSORS" -gt "1" ]
then
	readonly TMPLDIR=$(mktemp -d)
	trap "rm -r $TMPLDIR" EXIT
	
	cat_stdin "$STDIN_FILE" | egrep . | sort | uniq > "$TMPLDIR/input_list"
	
	if [ ! -s "$TMPLDIR/input_list" ]
	then
		echo >&2 "Error: no stdin data"
		exit 1
	fi
	
	NUM_OF_INPUTS="$(cat $TMPLDIR/input_list | wc -l)"
	SIZE_OF_PORTION="$(echo "a=$NUM_OF_INPUTS; b=$MAX_PROCESSORS; if(a%b) a/b+1 else a/b" | bc)"
	
	if [ "$SIZE_OF_PORTION" -gt "19997" ]
	then
		SIZE_OF_PORTION="19997"
	fi
	
	mkdir -p "$TMPLDIR/portions"
	
	split -l "$SIZE_OF_PORTION" "$TMPLDIR/input_list" "$TMPLDIR/portions/portion_"
	
	mkdir -p "$TMPLDIR/children_tables"
	
	if [ -n "$SBATCH_PARAMETERS" ]
	then
		mkdir -p "$TMPLDIR/slurm_logs"
		
		find $TMPLDIR/portions/ -type f -not -empty \
		| awk -v outdir="$TMPLDIR/children_tables" '{print "--stdin-file " $1 " --output-table-file " outdir "/" NR ".txt"}' \
		| xargs -L 1 sbatch -o "$TMPLDIR/slurm_logs/slurmjob-%j.out" -e "$TMPLDIR/slurm_logs/slurmjob-%j.err" $SBATCH_PARAMETERS "$ZEROARG" "${ALLARGS[@]}" --sbatch-parameters '' --processors 1 --model _list \
		| egrep '^Submitted batch job ' \
		| awk '{print $4}' \
		> "$TMPLDIR/slurm_job_ids"
		
		sleep 1
		REMAINING_SLURM_JOBS="$(squeue | grep -f "$TMPLDIR/slurm_job_ids" | wc -l)"
		while [ "$REMAINING_SLURM_JOBS" -gt "0" ]
		do
			sleep 5
			REMAINING_SLURM_JOBS="$(squeue | grep -f "$TMPLDIR/slurm_job_ids" | wc -l)"
		done
		
		find "$TMPLDIR/slurm_logs/" -type f -not -empty | xargs -L 1 cat >&2
	else
		find $TMPLDIR/portions/ -type f -not -empty \
		| awk -v outdir="$TMPLDIR/children_tables" '{print "--stdin-file " $1 " --output-table-file " outdir "/" NR ".txt"}' \
		| xargs -L 1 -P "$MAX_PROCESSORS" "$ZEROARG" "${ALLARGS[@]}" --processors 1 --model _list
	fi
	
	find "$TMPLDIR/children_tables" -type f -not -empty \
	| sort \
	| xargs -L 1 cat \
	| awk '{if(NR==1 || $1!="target") print $0}' \
	| voronota-js --no-setup-defaults "js:voronota_tournament_sort('-input-file _stdin -output-file _stdout -columns cadscore model_area target_area -multipliers 1 1 1 -tolerances 0.0 0.0 0.0 -no-tournament');" \
	> "$TMPLDIR/full_output_table"
	
	if [ -n "$OUTPUT_TABLE_FILE" ] && [ "$OUTPUT_TABLE_FILE" != "_stdout" ]
	then
		mkdir -p "$(dirname "$OUTPUT_TABLE_FILE")"
		cat "$TMPLDIR/full_output_table" > "$OUTPUT_TABLE_FILE"
	else
		cat "$TMPLDIR/full_output_table"
	fi
	
	exit 0
fi

TARGET_INFILE_BASENAME="$(basename $TARGET_INFILE)"

{
cat << EOF
var common_params={}
common_params.target_input_file='$TARGET_INFILE';
common_params.target_input_file_name='$TARGET_INFILE_BASENAME';
common_params.target_input_is_script='$TARGET_INPUT_IS_SCRIPT';
common_params.model_input_is_script='$MODEL_INPUT_IS_SCRIPT';
common_params.input_as_assembly='$AS_ASSEMBLY';
common_params.input_include_heteroatoms='$INCLUDE_HETEROATOMS';
common_params.restrict_input_atoms='$RESTRICT_INPUT';
common_params.ignore_residue_names='$IGNORE_RESIDUE_NAMES';
common_params.test_common_ids='$TEST_COMMON_IDS';
common_params.contacts_subselection='$SUBSELECT_CONTACTS';
common_params.remap_chains='$REMAP_CHAINS';
common_params.remap_chains_logging='$REMAP_CHAINS_LOGGING';
common_params.crude_mode='$CRUDE_MODE';
common_params.lt_mode='$VORONOTALT_MODE';
common_params.max_chains_to_fully_permute='$PERMUTATION_ALLOWANCE';
common_params.output_table_file='$OUTPUT_TABLE_FILE';
common_model_mod_params={}
common_model_mod_params.run_faspr='$RUN_FASPR';
common_model_mod_params.shuffle_chains='$SHUFFLE_CHAINS';
common_model_mod_params.invert_case_of_chains='$INVERT_CASE_OF_CHAINS';
var input_info_array=[];
EOF

{
if [ "$MODEL_INFILE" == "_list" ]
then
	cat_stdin "$STDIN_FILE" | egrep . | sort | uniq
else
	echo "$MODEL_INFILE"
fi
} | while read -r SUBINFILE
do
SUBINFILE_BASENAME="$(basename "$SUBINFILE")"
cat << EOF
input_info_array.push({"model_input_file": "$SUBINFILE", "model_input_file_name": "$SUBINFILE_BASENAME"});
EOF
done

cat << 'EOF'
prepare_atoms=function(params, model_mod_params)
{
	voronota_restrict_atoms("-use", params.restrict_input_atoms);
	voronota_assert_full_success("Failed to restrict input atoms by the input query");
	
	var initial_number_of_accepted_atoms=voronota_last_output().results[0].output.atoms_summary_new.number_total;
	
	if(model_mod_params!==null)
	{
		if(model_mod_params.run_faspr!="")
		{
			voronota_faspr("-lib-file", model_mod_params.run_faspr);
			voronota_assert_full_success("Failed to run FASPR");
		}
		
		if(model_mod_params.shuffle_chains!="")
		{
			voronota_setup_random_seed("-seed", model_mod_params.shuffle_chains);
			voronota_assert_full_success("Failed to set random seed");
			voronota_set_chain_name("_shuffle");
			voronota_assert_full_success("Failed to shuffle chains");
			voronota_sort_atoms_by_residue_id();
			voronota_assert_full_success("Failed reorder atoms by residue ids after shuffling chains");
		}
		
		if(model_mod_params.invert_case_of_chains=="true")
		{
			voronota_set_chain_name("_invert_case");
			voronota_assert_full_success("Failed to invert case of chains");
		}
	}
	
	if(params.input_include_heteroatoms!="true")
	{
		if(params.crude_mode=="true")
		{
			voronota_restrict_atoms("-use", "([-protein -aname CA] or [-nucleic])");
		}
		else
		{
			voronota_restrict_atoms("-use", "([-protein] or [-nucleic])");
		}
		voronota_assert_full_success("Failed to restrict input atoms to protein or nucleic only");
		initial_number_of_accepted_atoms=voronota_last_output().results[0].output.atoms_summary_new.number_total;
	}
	
	return initial_number_of_accepted_atoms;
}

prepare_contacts=function(params)
{
	if(params.lt_mode=="true")
	{
		var raw_contacts_subselection=params.contacts_subselection.replace(/\s+/g, '').replace("[--", "[-");
		if(raw_contacts_subselection=="[-inter-chain]")
		{
			if(params.crude_mode=="true")
			{
				voronota_construct_contacts_radically_fast("-no-intra-chain -probe 4.5");
			}
			else
			{
				voronota_construct_contacts_radically_fast("-no-intra-chain");
			}
		}
		else
		{
			if(params.crude_mode=="true")
			{
				voronota_construct_contacts_radically_fast("-no-intra-residue -probe 4.5");
			}
			else
			{
				voronota_construct_contacts_radically_fast("-no-intra-residue");
			}
		}
	}
	else
	{
		if(params.crude_mode=="true")
		{
			voronota_construct_contacts("-skip-sas -no-calculate-volumes -no-tag-peripherial -probe 4.5");
		}
		else
		{
			voronota_construct_contacts("-skip-sas -no-calculate-volumes -no-tag-peripherial");
		}
	}
	voronota_assert_full_success("Failed to construct contacts");
	
	voronota_select_contacts("-use", "([-min-seq-sep 1] and "+params.contacts_subselection+")", "-name", "relevant_contacts");
	voronota_assert_full_success("Failed to select contacts");
}

analyze_interface=function(params, target_object, model_object, initial_summary)
{
	voronota_cad_score("-target", target_object, "-model", model_object, "-t-sel", "[relevant_contacts]", "-remap-chains", params.remap_chains, "-remap-chains-logging", params.remap_chains_logging, "-ignore-residue-names", params.ignore_residue_names, "-max-chains-to-fully-permute", params.max_chains_to_fully_permute);
	voronota_assert_full_success("Failed to compute CAD-score");
	result_cadscore=voronota_last_output().results[0].output.residue_level_result;
	
	summary={};
	summary.target=initial_summary.target;
	summary.model=initial_summary.model;
	
	summary.cadscore=result_cadscore.score;
	summary.target_area=result_cadscore.target_area_sum;
	summary.model_area=result_cadscore.model_target_area_sum;
	
	summary.target_atoms=initial_summary.target_atoms;
	summary.model_atoms=initial_summary.model_atoms;
	
	var summary_table={}
	summary_table.header="";
	summary_table.row="";
	
	Object.keys(summary).forEach(function(key)
	{
			summary_table.header+=key+" ";
	});
	
	Object.keys(summary).forEach(function(key)
	{
		value=summary[key];
		if(typeof value === 'number')
		{
			summary_table.row+=parseFloat(value.toFixed(5))+" ";
		}
		else
		{
			summary_table.row+=value+" ";
		}
	});
	
	summary_table.header=summary_table.header.trim();
	summary_table.row=summary_table.row.trim();
	
	return summary_table;
}

voronota_setup_defaults("-no-load-voromqa-potentials -no-load-alt-voromqa-potential -no-load-more-atom-types -no-load-mock-voromqa-potential");

if(common_params.target_input_file===undefined || common_params.target_input_file==="")
{
	throw ("No target input file");
}

if(common_params.target_input_is_script===undefined || common_params.target_input_is_script==="")
{
	common_params.target_input_is_script="false";
}

if(common_params.model_input_is_script===undefined || common_params.model_input_is_script==="")
{
	common_params.model_input_is_script="false";
}

if(common_params.input_as_assembly===undefined || common_params.input_as_assembly==="")
{
	common_params.input_as_assembly="false";
}

if(common_params.input_include_heteroatoms===undefined || common_params.input_include_heteroatoms==="")
{
	common_params.input_include_heteroatoms="false";
}

if(common_params.restrict_input_atoms===undefined || common_params.restrict_input_atoms==="")
{
	common_params.restrict_input_atoms='[]';
}

if(common_params.ignore_residue_names===undefined || common_params.ignore_residue_names==="")
{
	common_params.ignore_residue_names="false";
}

if(common_params.test_common_ids===undefined || common_params.test_common_ids==="")
{
	common_params.test_common_ids="false";
}

if(common_params.contacts_subselection===undefined || common_params.contacts_subselection==="")
{
	common_params.contacts_subselection='[]';
}

if(common_params.remap_chains===undefined || common_params.remap_chains==="")
{
	common_params.remap_chains="false";
}

if(common_params.output_table_file===undefined || common_params.output_table_file==="")
{
	common_params.output_table_file="_stdout";
}

if(common_params.target_input_is_script=="true")
{
	voronota_source("-file", common_params.target_input_file);
	voronota_assert_partial_success("Failed when running provided target input script");
}
else
{
	voronota_import("-file", common_params.target_input_file, "-as-assembly", common_params.input_as_assembly, "-include-heteroatoms", common_params.input_include_heteroatoms);
	voronota_assert_partial_success("Failed to import target file");
}

voronota_list_objects();
voronota_assert_full_success("Failed to list objects");
if(voronota_last_output().results[0].output.objects.length!=1)
{
	throw ("Not exactly one structure loaded as target");
}
target_object=voronota_last_output().results[0].output.objects[0].name;

voronota_pick_objects("-names", target_object);

var target_initial_number_of_accepted_atoms=prepare_atoms(common_params, null);

if(common_params.test_common_ids=="true")
{
	voronota_export_selection_of_atoms("-on-objects", target_object, "-no-serial", "-no-name", "-file", "_virtual/target_residue_ids", "-no-resName", common_params.ignore_residue_names);
	voronota_assert_full_success("Failed to export target residue ids");
}

prepare_contacts(common_params);

var full_summary_table="";

for(var i=0;i<input_info_array.length;i++)
{
	var subinput=input_info_array[i];
	var model_object="";
	
	try
	{
		voronota_unpick_objects();
		
		var prev_number_of_objects=0;
		if(i>0)
		{
			voronota_list_objects();
			voronota_assert_full_success("Failed to list objects");
			prev_number_of_objects=voronota_last_output().results[0].output.objects.length;
		}
		
		if(common_params.model_input_is_script=="true")
		{
			voronota_source("-file", subinput.model_input_file);
			voronota_assert_full_success("Failed when running provided model input script");
		}
		else
		{
			voronota_import("-file", subinput.model_input_file, "-as-assembly", common_params.input_as_assembly, "-include-heteroatoms", common_params.input_include_heteroatoms);
			voronota_assert_full_success("Failed to import model file");
		}
		
		voronota_list_objects();
		voronota_assert_full_success("Failed to list objects");
		if(voronota_last_output().results[0].output.objects.length!=2)
		{
			throw ("Not exactly one structure loaded as model from "+subinput.model_input_file);
		}
		model_object=voronota_last_output().results[0].output.objects[1].name;
		
		voronota_pick_objects("-names", model_object);
		
		var model_initial_number_of_accepted_atoms=prepare_atoms(common_params, common_model_mod_params);
		
		if(common_params.test_common_ids=="true")
		{
			voronota_import_selection_of_atoms("-on-objects", model_object, "-file", "_virtual/target_residue_ids", "-name", "common_residues");
			voronota_assert_full_success("No common residue ids");
		}
		
		prepare_contacts(common_params);
		
		var initial_summary={};
		initial_summary.target=common_params.target_input_file_name;
		initial_summary.model=subinput.model_input_file_name;
		initial_summary.target_atoms=target_initial_number_of_accepted_atoms;
		initial_summary.model_atoms=model_initial_number_of_accepted_atoms;
		
		var summary_table=analyze_interface(common_params, target_object, model_object, initial_summary);
		if(full_summary_table=="")
		{
			full_summary_table+=summary_table.header+"\n";
		}
		full_summary_table+=summary_table.row+"\n";
	}
	catch(error)
	{
		log("Failed with '"+subinput.model_input_file_name+"': "+error);
	}
	
	if(model_object!="")
	{
		voronota_delete_objects('-names', model_object);
		model_object="";
	}
}

fwrite('_virtual/summary', full_summary_table);

if(common_params.output_table_file!=="_stdout")
{
	shell('mkdir -p "$(dirname '+common_params.output_table_file+')"');
}

voronota_tournament_sort('-input-file', '_virtual/summary', '-output-file', common_params.output_table_file, '-columns', ['cadscore', 'model_area', 'target_area'], '-multipliers', [1, 1, 1], '-tolerances', [0.0, 0.0, 0.0], '-no-tournament');

EOF

} \
| voronota-js --no-setup-defaults

