Add matchinfo to rewritten backend

Change-Id: I3a14dbb23da5071751a31d50881f7084e0a24d22
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index 854edf1..8a3274a 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -228,6 +228,8 @@
   my $text   = $doc->get('/:text_id')->to('search#text_info')->name('text');
   my $match  = $doc->get('/:text_id/:match_id')->to('search#match_info')->name('match');
 
+  $r->route('/corpus2/:corpus_id/:doc_id/:text_id/:match_id')->to('search2#match_info')->name('match');
+
   # User Management
   my $user = $r->any('/user')->to(controller => 'User');
   $user->post('/login')->to(action => 'login')->name('login');
diff --git a/lib/Kalamar/Controller/Search2.pm b/lib/Kalamar/Controller/Search2.pm
index 7440444..af9d0b5 100644
--- a/lib/Kalamar/Controller/Search2.pm
+++ b/lib/Kalamar/Controller/Search2.pm
@@ -190,6 +190,10 @@
   # Get query
   my $query = $v->param('q');
 
+
+  # TODO:
+  #   Check for validation errors!
+
   # No query
   unless ($query) {
     return $c->render($c->loc('Template_intro', 'intro'));
@@ -400,11 +404,144 @@
         start_page => $query{p},
       );
     }
-  )->wait;
+  )
+
+  # Start IOLoop
+  ->wait;
 
 
   return 1;
 };
 
 
+sub match_info {
+  my $c = shift;
+
+  # Validate user input
+  my $v = $c->validation;
+  $v->optional('foundry');
+  $v->optional('layer');
+  $v->optional('spans')->in(qw/true false/);
+
+  # Old API foundry/layer usage
+  my $foundry = '*';
+  my %query = (foundry => '*');
+  if ($v->param('foundry')) {
+    $query{foundry} = $v->param('foundry');
+    $query{layer} = $v->param('layer') if $v->param('layer');
+    $query{spans} = $v->param('spans') if $v->param('spans');
+  };
+
+  # Create new request API
+  my $url = Mojo::URL->new($c->api);
+
+  # Use stash information to create url path
+  $url->path(
+    join('/', (
+      'corpus',
+      $c->stash('corpus_id'),
+      $c->stash('doc_id'),
+      $c->stash('text_id'),
+      $c->stash('match_id'),
+      'matchInfo'
+    ))
+  );
+
+  # Set query parameters
+  $url->query(\%query);
+
+  $c->app->log->debug('Text info: ' . $url);
+
+  $c->render_later;
+
+  # TODO: Add caching!
+  $c->user->auth_request_p(
+    get => $url
+  )
+  ->then(\&_catch_http_errors)
+  ->then(
+    sub {
+      my $json = shift->json;
+      unless ($json) {
+        return Mojo::Promise->new->reject([
+          [undef, 'JSON response is invalid']
+        ]);
+      };
+
+      $c->stash(results => _map_match($json));
+#      $c->stash(results => $json);
+      return $json;
+    }
+  )
+  ->then(
+    \&_catch_koral_errors
+  )
+  # Deal with errors
+  ->catch(
+    sub {
+      $c->_notify_on_errors(shift);
+    }
+  )
+
+  ->finally(
+    sub {
+      # Add notifications to the matching json
+      # TODO: There should be a special notification engine doing that!
+
+      my $json = $c->stash('results');
+      my $notes = $c->notifications(json => $json);
+      return $c->render(
+        json => $notes,
+        status => 200
+      );
+    }
+  )
+
+  # Start IOLoop
+  ->wait;
+
+  return 1;
+};
+
 1;
+
+
+__END__
+
+  # Async
+  $c->render_later;
+
+  # Use the API for fetching matching information non-blocking
+  $c->search->match(
+    corpus_id => $c->stash('corpus_id'),
+    doc_id    => $c->stash('doc_id'),
+    text_id   => $c->stash('text_id'),
+    match_id  => $c->stash('match_id'),
+    %query,
+
+    # Callback for async search
+    sub {
+      my $index = shift;
+      return $c->respond_to(
+
+        # Render json if requested
+        json => sub {
+          # Add notifications to the matching json
+          # TODO: There should be a special notification engine doing that!
+          my $notes = $c->notifications(json => $index->results->[0]);
+          $c->render(
+            json => $notes,
+            status => $index->status
+          );
+        },
+
+        # Render html if requested
+        html => sub {
+          return $c->render(
+            layout   => 'default',
+            template => 'match_info'
+          )
+        }
+      );
+    }
+  );
diff --git a/t/fixture.t b/t/fixture.t
index 6fac855..ba795f7 100644
--- a/t/fixture.t
+++ b/t/fixture.t
@@ -39,6 +39,10 @@
   ->json_is('/matches/0/docSigle', "GOE/AGI")
   ;
 
+$t->get_ok('/corpus/WPD15/232/39681/p2133-2134/matchInfo?spans=false&foundry=*')
+  ->status_is(200)
+  ->json_is('/textSigle', 'WPD15/232/39681')
+  ;
 
 done_testing;
 __END__
diff --git a/t/fixtures/fake_backend.pl b/t/fixtures/fake_backend.pl
index e7fc518..9573f3f 100644
--- a/t/fixtures/fake_backend.pl
+++ b/t/fixtures/fake_backend.pl
@@ -105,6 +105,23 @@
 };
 
 
+# Matchinfo fixtures
+get '/corpus/:corpusId/:docId/:textId/:matchId/matchInfo' => sub {
+  my $c = shift;
+
+  my $file = join('_', (
+    'matchinfo',
+    $c->stash('corpusId'),
+    $c->stash('docId'),
+    $c->stash('textId'),
+    $c->stash('matchId')
+  ));
+
+  # Get response based on query parameter
+  my $response = $c->load_response(slugify($file));
+  return $c->render(%$response);
+};
+
 
 ############
 # Auth API #
diff --git a/t/fixtures/response_matchinfo_wpd15_232_39681_p2133-2134.json b/t/fixtures/response_matchinfo_wpd15_232_39681_p2133-2134.json
new file mode 100644
index 0000000..9f4d6bd
--- /dev/null
+++ b/t/fixtures/response_matchinfo_wpd15_232_39681_p2133-2134.json
@@ -0,0 +1,29 @@
+{
+  "status" : 200,
+  "json" : {
+    "@context":"http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
+    "meta":{
+      "version":"Krill-0.58.0"
+    },
+    "field":"tokens",
+    "textClass":"kultur film",
+    "pubPlace":"URL:http://de.wikipedia.org",
+    "textSigle":"WPD15/232/39681",
+    "docSigle":"WPD15/232",
+    "corpusSigle":"WPD15",
+    "title":"2nd Infantry Division (Vereinigte Staaten)",
+    "author":"Boshomi, u.a.",
+    "availability":"CC-BY-SA",
+    "layerInfos":"corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans opennlp/p=tokens opennlp/s=spans",
+    "startMore":false,
+    "endMore":false,
+    "license":"CC-BY-SA",
+    "snippet":"<span class=\"context-left\"></span><span class=\"match\"><span title=\"corenlp/p:CARD\"><span title=\"opennlp/p:CARD\">1976</span></span> <span title=\"corenlp/p:ADJA\"><span title=\"opennlp/p:VVFIN\">erschlugen</span></span> <span title=\"corenlp/p:ADJA\"><span title=\"opennlp/p:ADJA\">nordkoreanische</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Grenzsoldaten</span></span> <span title=\"corenlp/p:APPR\"><span title=\"opennlp/p:APPR\">in</span></span> <span title=\"corenlp/p:ART\"><span title=\"opennlp/p:ART\">einem</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Handgemenge</span></span> <span title=\"corenlp/p:CARD\"><span title=\"opennlp/p:CARD\">zwei</span></span> <span title=\"corenlp/p:ADJA\"><span title=\"opennlp/p:ADJA\">amerikanische</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Soldaten</span></span>, <span title=\"corenlp/p:PRELS\"><span title=\"opennlp/p:PRELS\">die</span></span> <span title=\"corenlp/p:APPRART\"><span title=\"opennlp/p:APPRART\">im</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Rahmen</span></span> <span title=\"corenlp/p:ART\"><span title=\"opennlp/p:ART\">eines</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Routineeinsatzes</span></span> <span title=\"corenlp/p:ART\"><span title=\"opennlp/p:ART\">einen</span></span> <mark><span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Baum</span></span></mark> <span title=\"corenlp/p:APPR\"><span title=\"opennlp/p:APPR\">an</span></span> <span title=\"corenlp/p:ART\"><span title=\"opennlp/p:ART\">der</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">Demarkationslinie</span></span> <span title=\"corenlp/p:VVPP\"><span title=\"opennlp/p:VVPP\">beschnitten</span></span>.&lt;<span title=\"opennlp/p:ADJA\">ref</span>&gt;''…<span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">On</span></span> <span title=\"corenlp/p:CARD\"><span title=\"opennlp/p:CARD\">18</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:NN\">August</span></span> <span title=\"corenlp/p:CARD\"><span title=\"opennlp/p:CARD\">1976</span></span>, <span title=\"corenlp/p:VVFIN\"><span title=\"opennlp/p:NE\">during</span></span> <span title=\"corenlp/p:XY\"><span title=\"opennlp/p:NE\">a</span></span> <span title=\"corenlp/p:ADJA\"><span title=\"opennlp/p:NE\">routine</span></span> <span title=\"corenlp/p:ADJA\"><span title=\"opennlp/p:VVFIN\">tree</span></span> <span title=\"corenlp/p:NN\"><span title=\"opennlp/p:FM\">trimming</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:FM\">operation</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:ADV\">within</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">the</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">DMZ</span></span>, <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">North</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">Korean</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">border</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:APPR\">guards</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:ADJA\">bludgeoned</span></span> <span title=\"corenlp/p:XY\"><span title=\"opennlp/p:PWAV\">two</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">American</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">officers</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">to</span></span> <span title=\"corenlp/p:FM\"><span title=\"opennlp/p:NE\">death</span></span> <span title=\"corenlp/p:APPR\"><span title=\"opennlp/p:APPR\">in</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">a</span></span> <span title=\"corenlp/p:VVFIN\"><span title=\"opennlp/p:NE\">melee</span></span> <span title=\"corenlp/p:APPR\"><span title=\"opennlp/p:APPR\">in</span></span> <span title=\"corenlp/p:NE\"><span title=\"opennlp/p:NE\">the</span></span> Joint Security Area, what resulted is known as Operation PAUL BUNYAN.<span class=\"cutted\"></span></span><span class=\"context-right\"></span>",
+    "matchID":"match-WPD15/232/39681-p2133-2134",
+    "pubDate":"2015-05-01",
+    "context":{
+      "left":["token",0],
+      "right":["token",0]
+    }
+  }
+}
diff --git a/t/match_info.t b/t/match_info.t
new file mode 100644
index 0000000..42a1aa7
--- /dev/null
+++ b/t/match_info.t
@@ -0,0 +1,33 @@
+use Mojo::Base -strict;
+use Test::Mojo;
+use Test::More;
+use Mojo::File qw/path/;
+
+
+#####################
+# Start Fake server #
+#####################
+my $mount_point = '/api/';
+$ENV{KALAMAR_API} = $mount_point;
+
+my $t = Test::Mojo->new('Kalamar');
+
+# Mount fake backend
+# Get the fixture path
+my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, 'fixtures');
+my $fake_backend = $t->app->plugin(
+  Mount => {
+    $mount_point =>
+      $fixtures_path->child('fake_backend.pl')
+  }
+);
+# Configure fake backend
+$fake_backend->pattern->defaults->{app}->log($t->app->log);
+
+# Query passed
+$t->get_ok('/corpus2/WPD15/232/39681/p2133-2134?spans=false&foundry=*')
+  ->status_is(200)
+  ->json_is('/textSigle', 'WPD15/232/39681')
+  ;
+
+done_testing;