#!/usr/bin/env perl

use v5.20;
use warnings;
no warnings 'once';
use autodie;
use File::Slurp;
use Scalar::Util qw(blessed);
use Attean;
use Attean::RDF;
use Attean::SimpleQueryEvaluator;
use AtteanX::RDFQueryTranslator;
use RDF::Query;
use Data::Dumper;
use Getopt::Long;
use Try::Tiny;
use Benchmark qw(timethese);

BEGIN { $Error::TypeTiny::StackTrace	= 1; }

if (scalar(@ARGV) < 1) {
	print STDERR <<"END";
Usage: $0 query.rq [data.ttl ...]

Uses RDF::Query to parse the supplied SPARQL query, translates the parsed query
form to an Attean::Algebra object, and executes it against a model containing
the RDF data parsed from the data file using Attean::SimpleQueryEvaluator.

END
	exit(0);
}

my $dryrun			= 0;
my $check_syntax	= 0;
my $verbose			= 0;
my $debug			= 0;
my $benchmark		= 0;
my $print_sparql	= 0;
my $print_plan		= 0;
my $print_algebra	= 0;
my $out_format		= '';
my $result			= GetOptions(
	"verbose"	=> \$verbose,
	"debug"		=> \$debug,
	"benchmark"	=> \$benchmark,
	'algebra'	=> \$print_algebra,
	'plan'		=> \$print_plan,
	"sparql"	=> \$print_sparql,
	'n'			=> \$dryrun,
	'c'			=> \$check_syntax,
	'output=s'	=> \$out_format,
);

my $qfile	= shift;

try {
	warn "Constructing model...\n" if ($verbose);
	my $store	= Attean->get_store('Memory')->new();
	my $model	= Attean::MutableQuadModel->new( store => $store );
	my $graph	= Attean::IRI->new('http://example.org/graph');

	while (my $data = shift(@ARGV)) {
		my $base	= Attean::IRI->new('file://' . File::Spec->rel2abs($data));
		open(my $fh, '<:encoding(UTF-8)', $data);
		warn "Parsing data from $data...\n" if ($verbose);
		my $pclass	= Attean->get_parser( filename => $data ) // 'AtteanX::Parser::Turtle';
		my $parser	= $pclass->new(base => $base);
		my $iter	= $parser->parse_iter_from_io($fh);
		my $quads	= $iter->as_quads($graph);
		$model->add_iter($quads);
	}
	
	if ($debug) {
		my $iter	= $model->get_quads();
		while (my $q = $iter->next) {
			say $q->as_string;
		}
	}

	warn "Parsing query...\n" if ($verbose);
	my $sparql;
	if ($qfile eq '-') {
		local($/) = undef;
		$sparql	= <STDIN>;
	} else {
		$sparql	= read_file($qfile);
	}
	my $query	= RDF::Query->new($sparql);
	unless ($query) {
		if ($check_syntax) {
			warn RDF::Query->error;
			print "Syntax invalid: $qfile\n---\n$sparql\n---\n";
			exit(1);
		}
		die RDF::Query->error;
	}

	warn "Translating query...\n" if ($verbose);
	my $t	= AtteanX::RDFQueryTranslator->new();
	my $a	= $t->translate_query($query);
	if ($print_algebra) {
		print "# Algebra:\n" . $a->as_string;
	}
	
	if ($check_syntax) {
		print "Syntax OK: $qfile\n";
		exit(0);
	}
	
	if ($print_sparql) {
		print "# $qfile\n";
		print $a->as_sparql;
	}
	
	unless ($dryrun) {
		my $default_graphs	= [$graph];
		my $planner	= Attean::IDPQueryPlanner->new();
		my $plan	= $planner->plan_for_algebra($a, $model, $default_graphs);
		if ($print_plan) {
			print "# Plan:\n" . $plan->as_string;
		}
		my $iter	= $plan->evaluate($model);
		my $count	= 1;
		my $s		= Attean->get_serializer($out_format);
		if ($out_format and $s) {
			$s->serialize_iter_to_io(\*STDOUT, $iter);
		} else {
			while (my $r = $iter->next) {
				printf("%3d %s\n", $count++, $r->as_string);
			}
		}
	}
} catch {
	my $exception	= $_;
	warn "Caught error: $exception";
	warn $exception->stack_trace;
	exit(1);
};
