Introduce special RWK structure parser

Change-Id: Ibfc00f106851c2c37bde7a63bfeaac10a6260cf2
diff --git a/lib/KorAP/XML/Annotation/RWK/Structure.pm b/lib/KorAP/XML/Annotation/RWK/Structure.pm
new file mode 100644
index 0000000..791f43d
--- /dev/null
+++ b/lib/KorAP/XML/Annotation/RWK/Structure.pm
@@ -0,0 +1,111 @@
+package KorAP::XML::Annotation::RWK::Structure;
+use KorAP::XML::Annotation::Base;
+
+sub parse {
+  my $self = shift;
+
+  my %milestones = (
+    s => [],
+    p => [],
+  );
+
+  my ($p_start, $o_start) = (0,0);
+  my ($last_p, $last_o) = (0,0);
+
+  $$self->add_spandata(
+    foundry => 'struct',
+    layer => 'structure',
+    cb => sub {
+      my ($stream, $span) = @_;
+
+      # Read feature
+      my $feature = $span->hash->{fs}->{f};
+      my $attrs;
+
+      # Get attributes
+      if (ref $feature eq 'ARRAY') {
+        $attrs = $feature->[1]->{fs}->{f};
+        $attrs = ref $attrs eq 'ARRAY' ? $attrs : [$attrs];
+        $feature = $feature->[0];
+      };
+
+      # Get term label
+      my $name = $feature->{'#text'};
+
+      # Check only for anchors
+      if ($name eq 's') {
+        push @{$milestones{s}}, [ $span->p_start, $span->o_start ];
+      }
+      elsif ($name eq 'p') {
+        push @{$milestones{p}}, [ $span->p_start, $span->o_start ];
+      }
+      else {
+        $last_p = $span->p_start;
+        $last_o = $span->o_end;
+      }
+    }
+  ) or return;
+
+  my ($sentences, $paragraphs) = (0, 0);
+
+  # Add final position
+  push @{$milestones{s}}, [$last_p, $last_o];
+  push @{$milestones{p}}, [$last_p, $last_o];
+
+  my $stream = $$self->stream;
+  foreach my $type ('s', 'p') {
+
+    # Sort and unique milestones
+    @{$milestones{$type}} = sort {
+      $a->[0] <=> $b->[0]
+    } @{$milestones{$type}};
+
+    # Iterate overs milestones
+    foreach (@{$milestones{$type}}) {
+
+      if (($_->[0] == $p_start) || ($_->[1] == $o_start)) {
+        next;
+      };
+
+      my $mtt = $stream->pos($p_start);
+
+      # Add the base sentence
+      my $mt = $mtt->add(
+        term    => '<>:base/s:' . $type,
+        o_start => $o_start,
+        o_end   => $_->[1],
+        p_start => $p_start,
+        p_end   => $_->[0],
+        pti     => 64
+      );
+      $mt->payload('<b>1');
+
+      if ($type eq 's') {
+        $sentences++;
+      } else {
+        $paragraphs++;
+      };
+
+      $p_start = $_->[0];
+      $o_start = $_->[1];
+    };
+
+    # Set meta information about sentence count
+    if ($type eq 's') {
+      $stream->add_meta('base/sentences', '<i>' . $sentences);
+    }
+    else {
+      $stream->add_meta('base/paragraphs', '<i>' . $paragraphs);
+    };
+  };
+
+  return 1;
+};
+
+sub layer_info {
+  [];
+};
+
+
+1;
+__END__
diff --git a/t/real/redew.t b/t/real/redew.t
index 2d52610..8a907cd 100644
--- a/t/real/redew.t
+++ b/t/real/redew.t
@@ -196,24 +196,39 @@
 
 is(substr($output->{data}->{text}, 0, 100), 'Er hatte den Kopf weit nach rückwärts gebeugt, seine langen schwarzen Haare lockten sich über den li', 'Primary Data');
 
+use Log::Log4perl;
+
+Log::Log4perl->init({
+  'log4perl.rootLogger' => 'WARN, STDERR',
+  'log4perl.appender.STDERR' => 'Log::Log4perl::Appender::ScreenColoredLevels',
+  'log4perl.appender.STDERR.layout' => 'PatternLayout',
+  'log4perl.appender.STDERR.layout.ConversionPattern' => '[%r] %F %L %c - %m%n'
+});
+
+
 # Add annotations
-$tokens->add('RWK', 'Morpho');
-$tokens->add('DeReKo', 'Structure');
+ok($tokens->add('RWK', 'Morpho'));
+ok($tokens->add('RWK', 'Structure'));
 
 $output = decode_json( $tokens->to_json );
 
 $first = $output->{data}->{stream}->[0];
 
-is('-:tokens$<i>522',$first->[0]);
-is('<>:base/s:t$<b>64<i>0<i>3062<i>522<b>0',$first->[2]);
-is('i:er',$first->[6]);
-is('rwk/l:er',$first->[7]);
-is('rwk/m:PRO.Pers.Subst.3.Nom.Sg.Masc',$first->[8]);
-is('rwk/norm:Er',$first->[9]);
-is('rwk/p:PPER',$first->[10]);
-is('s:Er',$first->[11]);
-
+is('-:base/paragraphs$<i>2',$first->[0]);
+is('-:base/sentences$<i>21',$first->[1]);
+is('-:tokens$<i>522',$first->[2]);
+is('<>:base/s:s$<b>64<i>0<i>139<i>23<b>1',$first->[3]);
+is('<>:base/s:p$<b>64<i>0<i>2631<i>449<b>1',$first->[4]);
+is('<>:base/s:t$<b>64<i>0<i>3062<i>522<b>0',$first->[5]);
+is('_0$<i>0<i>2',$first->[6]);
+is('i:er',$first->[7]);
+is('rwk/l:er',$first->[8]);
+is('rwk/m:PRO.Pers.Subst.3.Nom.Sg.Masc',$first->[9]);
+is('rwk/norm:Er',$first->[10]);
+is('rwk/p:PPER',$first->[11]);
+is('s:Er',$first->[12]);
 
 done_testing;
+
 __END__