package ConclaveIdsProcessor;
use Dancer ':syntax';

use Conclave::Utils::OTK;
use Conclave::Utils::OTK::PC;

use Conclave::Utils::ISplitter;
use JSON;
use File::Slurp qw/write_file read_file/;
use Lingua::PTD;
use Data::Dumper;

our $VERSION = '0.1';

our $HOME = '/home/smash/conclave-website-root';
our $OWLROOT = "$HOME/owl";
our $PKGROOT = "$HOME/packages";
our $DATAROOT = "$HOME/data";

hook before_template => sub {
  my $tokens = shift;
  my $path = request->base->path;
  my @packages = __package_list($PKGROOT);

  $tokens->{uri_base} = $path eq '/' ? $path : $path.'/';
  $tokens->{packages} = [@packages];
};

get '/' => sub {
  my @packages = __package_list($PKGROOT);

  template 'index' => { packages =>[@packages] };
};

get '/package/:pkgid' => sub {
  my $pkgid = param 'pkgid';

  my $o = Conclave::Utils::OTK->new($pkgid, 'program');
  my $sparql = <<"EOQ";
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT ?id ?str ?file ?line ?type
FROM <http://conclave.di.uminho.pt/owl/$pkgid/program>
WHERE {
  ?id rdf:type <http://conclave.di.uminho.pt/owl/$pkgid/program#Identifier> .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#hasIdString> ?str .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#inFile> ?file .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#hasLineBegin> ?line .
  ?e <http://conclave.di.uminho.pt/owl/$pkgid/program#hasIdentifier> ?id .
  ?e rdf:type ?type .
}
EOQ
  my @ids = $o->get_instances("http://conclave.di.uminho.pt/owl/$pkgid/program#Identifier");
  my $r = $o->__query($sparql);

  my $ids = {};
  foreach (split /\n/, $r) {
    if ($_ =~ m/\s*(<.*?>)\s+\"(.*?)\"\S*\s+(<.*?>)\s+\"(.*?)\"/) {
      my $type = Conclave::Utils::OTK::PC::get_id_type($o, $1); # FIXME

      $ids->{$1} = [$2, $3, $4, $type];
    }
  }

  template 'package' => { pkgid => $pkgid, ids => $ids };
};

get '/package/:pkgid/splits/:which' => sub {
  my $pkgid = param 'pkgid';
  my $which = param 'which';
  my $filename = "$HOME/data/$pkgid/splits_$which.json";

  my $json = read_file($filename, {binmode=>':utf8'});
  my $data = decode_json $json;

  template 'splits' => { pkgid=>$pkgid, which=>$which, data=>$data };
};

get '/package/:pkgid/pss' => sub {
  my $pkgid = param 'pkgid';
  my $filename = "$HOME/data/$pkgid/pss.json";

  my $json = read_file($filename, {binmode=>':utf8'});
  my $data = decode_json $json;

  template 'pss' => { pkgid=>$pkgid, data=>$data };
};

post '/actions' => sub {
  my $pkgid = param 'pkgid';
  my $action = param 'action';

  print STDERR "post action $pkgid $action\n";
  if ($action eq 'splits') {
    __compute_splits("$HOME/data/$pkgid", $pkgid);
  }
  if ($action eq 'pss') {
    __compute_pss("$HOME/data/$pkgid", $pkgid);
  }

  return "Done!";
};

sub __package_list {
  my $root = shift;

  my @packages;
  opendir(my $dh, $root) or die "can't opendir $root: $!";
  while(readdir $dh) {
    next if $_ =~ m/^\.{1,2}$/;
    next unless -d "$root/$_";

    push @packages, $_;
  }
  closedir $dh;

  return @packages;
}

sub __package_available_list {
  my ($root, $pkgid) = @_;

  my %available;
  opendir(my $dh, "$root/$pkgid") or die "can't opendir $root/$pkgid: $!";
  while(readdir $dh) {
    next if $_ =~ m/^\.{1,2}$/;

    $_ =~ s/\..*?$//;
    $available{$_}++;
  }
  closedir $dh;

  return keys %available;
}

sub __compute_splits {
  my ($root, $pkgid) = @_;
  my $filename = "$root/splits_conclave.json";
  mkdir $root unless -e $root;

  # get ids
  my $o = Conclave::Utils::OTK->new($pkgid, 'program');
  my $sparql = <<"EOQ";
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT ?id ?str ?file ?line ?type
FROM <http://conclave.di.uminho.pt/owl/$pkgid/program>
WHERE {
  ?id rdf:type <http://conclave.di.uminho.pt/owl/$pkgid/program#Identifier> .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#hasIdString> ?str .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#inFile> ?file .
  ?id <http://conclave.di.uminho.pt/owl/$pkgid/program#hasLineBegin> ?line .
  ?e <http://conclave.di.uminho.pt/owl/$pkgid/program#hasIdentifier> ?id .
  ?e rdf:type ?type .
}
EOQ
  my @ids = $o->get_instances("http://conclave.di.uminho.pt/owl/$pkgid/program#Identifier");
  my $r = $o->__query($sparql);

  my $splitter = Conclave::Utils::ISplitter->new();
  my $ids = {};

  foreach (split /\n/, $r) {
    if ($_ =~ m/\s*(<.*?>)\s+\"(.*?)\"\S*\s+(<.*?>)\s+\"(.*?)\"/) {
      my @r = $splitter->split(lc $2);
      my $splits = join ',', map {$_->{s}} @r;
      my $terms = join ',', map {$_->{t}} @r;

      $ids->{$1} = {
          uid    => $1,
          name   => $2,
          file   => $3,
          line   => $4,
          splits => $splits,
          terms  => $terms,
        };
    }
  }

  my $json = encode_json $ids;
  write_file($filename,{binmode => ':utf8'}, $json);
  print STDERR "Saved $filename\n";
}

sub __compute_pss {
  my ($root, $pkgid) = @_;
  my $filename = "$root/pss.json";
  mkdir $root unless -e $root;

  # get ids
  my $source = "$root/splits_conclave.json";
  my $json = read_file($source, {binmode => ':utf8'});
  my $ids = decode_json $json;

  my $ptdA = Lingua::PTD->new('/home/smash/conclave-website-root/aux/ptd.en-pt.sqlite');
  my $ptdB = Lingua::PTD->new('/home/smash/conclave-website-root/aux/ptd.pt-en.sqlite');

  my $res;
  foreach my $i (keys %$ids) {
    my $final;

    foreach my $t (split /,/, $ids->{$i}->{terms}) {
      my $pss = __calc_pss($ptdA, $ptdB, $t, 0.2);

      foreach my $x (keys %$pss) {
        if (exists $final->{$x}) {
          my $min = $pss->{$x} <= $final->{$x} ? $pss->{$x} : $final->{$x};
          $final->{$x} = $min;
        }
        else {
          $final->{$x} = $pss->{$x};
        }
      }
    }

    $res->{$i} = $final;
  }

  $json = encode_json $res;
  write_file($filename,{binmode => ':utf8'}, $json);
  print STDERR "Saved $filename\n";
}

sub __calc_pss {
  my ($ptdA, $ptdB, $term, $minp) = @_;

  my $pss;
  my %trans = $ptdA->transHash($term);
  foreach (keys %trans) {
    $pss->{$_} = $trans{$_} if $trans{$_} >= $minp;
    my %transI = $ptdB->transHash($_);
    foreach my $j (keys %transI) {
      $pss->{$j} = $transI{$j} if $transI{$j} >= $minp;
    }
  }

  return $pss;
}

true;
