#!/usr/bin/perl -w

use lib qw(. ./ddc-perl ./DDC-perl);
use DDC::Concordance;
use JSON;
use Encode qw(encode decode);
use Getopt::Long qw(:config no_ignore_case);
use File::Basename qw(basename dirname);
use CGI qw(:standard :cgi-lib);

use strict;

##======================================================================
## Constants & Globals

our $prog = basename($0);
our $progdir = dirname($0);
(our $rcfile = "$progdir/$prog") =~ s/\.perl$/.rc/i;

## $cfg: site configuration & defaults (loaded from $rcfile if available)
our $cfg =
  {
   ##-- user options
   server   => 'localhost:50250', ##-- ddc server
   mode     => 'json',            ##-- ddc query mode (json,html,table,text)
   corpus   => '',
   start    => 1,
   limit    => 10,

   ##-- client options
   timeout  => 60,
   encoding=>'utf8',
   parseMeta=>1,
   parseContext=>1,
   keepRaw=>0,
   fieldNames=>undef,
   fieldSeparator=>"\x{1f}",
   tokenSeparator=>"\x{1e}",
   dropFields => [],
   expandFields => 1,
  };

## @defaults: user-level keys in $cfg with a default value
our @defaults = qw(server corpus mode start limit);

##======================================================================
## Subs: Configuration

## \%cfg = loadConfig($jsonFile)
## \%cfg = loadConfig($jsonFile,\%cfg)
sub loadConfig {
  my ($rcfile,$cfg)=@_;

  open(RC,"<$rcfile") or die("$prog: open failed for config file '$rcfile': $!");
  local $/=undef;
  my $rcstr = <RC>;
  close(RC) or die("$prog: close failed for config file '$rcfile': $!");

  ##-- remove comments
  $rcstr =~ s/^\#.*$//mg;

  ##-- decode
  my $rcdata = decode_json($rcstr)
    or die("$prog: could not decode config data from '$rcfile': $!");

  ##-- merge (clobber)
  %$cfg = (%$cfg,%$rcdata);

  return $cfg;
}



##======================================================================
## MAIN

##-- site configuration
$cfg = loadConfig($rcfile,$cfg) if (-r $rcfile);

##-- CGI init
charset($cfg->{encoding}); ##-- initialize CGI charset
my $vars = {};
if (param()) {
  $vars = Vars();
}

my ($dclient,$content);
eval {
  ##-- get query
  my $query = $vars->{'q'};
  die("$prog: no 'q' (query) parameter specified!") if (($query//'') eq '');
  $query  = decode($cfg->{encoding},$query) if (defined($cfg->{qencoding}));

  ##-- defaults
  $vars->{$_} = $cfg->{$_} foreach (grep {!exists($vars->{$_})} @defaults);

  ##-- create client
  my $server = $vars->{server}
    or die("$prog: no 'server' (ddc server) parameter defined!");
  $dclient = DDC::Client::Distributed->new(%$cfg,
					   connect=>{PeerAddr=>$server},
					   mode=>$vars->{mode},
					   start=>($vars->{start} > 0 ? ($vars->{start}-1) : 0),
					   limit=>$vars->{limit},
					  )
    or die("$prog: could not create DDC::Client::Distributed: $!");
  $dclient->open()
    or die("$prog: could not connect to DDC server at $server: $!");

  ##-- append subcorpus clause to query if requested
  my @corpora = grep {defined($_) && $_ ne ''} split(/[\s\,\:\+]+/,$vars->{corpus});
  $query .= ' :'.join(',',@corpora) if (@corpora);

  ##-- send query
  $content = $dclient->queryRaw($query)
    or die("$prog: query ($query) failed: $!");
};

##-- check for errors
if ($@) {
  print
    (header(-status=>500),
     start_html('Error'),
     h1('Error'),"\n",
     pre(escapeHTML($@)),
     end_html);
  exit 1;
}

##-- dump content
my %mode_opts =
  (
   html => {type=>'text/html'},
   text => {type=>'text/plain',headers=>{'-Content-Disposition'=>"inline; filename=\"ddc.txt\""}},
   table  => {type=>'text/plain',headers=>{'-Content-Disposition'=>"inline; filename=\"ddc.tab\""}},
   json => {type=>'application/json',headers=>{'-Content-Disposition'=>"inline; filename=\"ddc.json\""}},
  );
my $modeh = $mode_opts{$dclient->{mode}};
if ($vars->{raw} || $vars->{debug} || $dclient->{mode} eq 'req') {
  delete $modeh->{headers}{'-Content-Disposition'};
  $modeh->{type} = 'text/plain';
}
print
  header($vars->{debug}
	 ? (-type=>'text/plain')
	 : (-type=>$modeh->{type},%{$modeh->{headers}||{}})),
  $content;