various things; headline change is reworking of node positions
[scpubgit/stemmatology.git] / lib / Text / Tradition / Collation / Segment.pm
CommitLineData
b15511bf 1package Text::Tradition::Collation::Segment;
2
3use Moose;
4use MooseX::NonMoose;
910a0a6d 5use Text::Tradition::Collation::Position;
b15511bf 6
7extends 'Graph::Easy::Node';
8
9# A segment is a special 'invisible' node that is a set of Readings.
10# We should never display these, but it is useful to have them
11# available for many-to-many relationship mappings.
12
13has 'members' => (
14 is => 'rw',
15 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
16 required => 1,
17);
18
910a0a6d 19has 'position' => (
20 is => 'rw',
21 isa => 'Text::Tradition::Collation::Position',
22 predicate => 'has_position',
23);
24
b15511bf 25sub FOREIGNBUILDARGS {
26 my $class = shift;
27 my %args = @_;
28
29 # Name the segment after its member elements.
30 my $nodename = join( ' ', map { $_->name } @{$args{'members'}} );
31 return ( 'name', $nodename );
32}
33
34sub BUILD {
35 my( $self, $args ) = @_;
36 $self->set_attribute( 'class', 'segment' );
910a0a6d 37 my $ctr = 1;
38 foreach my $r ( @{$args->{members}} ) {
39 my $seg_edge = $r->parent->add_edge( $r, $self, $ctr++ );
40 $seg_edge->set_attribute( 'class', 'segment' );
41 }
42 unless ( grep { !$_->has_position } @{$args->{members}} ) {
43 $self->set_position;
44 }
45}
b15511bf 46
910a0a6d 47# We use our 'members' array for the initialization, but afterward we
48# go by graph edges. This ensures that merged nodes stay merged.
49around 'members' => sub {
50 my $orig = shift;
51 my $self = shift;
52 my @members;
53 foreach my $sl ( sort { $a->name <=> $b->name }
54 grep { $_->sub_class eq 'segment' } $self->incoming ) {
55 push( @members, $sl->from );
56 }
57 return \@members;
58};
59
60sub set_position {
61 my $self = shift;
62 my( $common, $min, $max );
63 my $readings = $self->members;
b15511bf 64 foreach my $r ( @{$self->members} ) {
910a0a6d 65 if( $r->has_position ) {
66 if( $common && $common != $r->position->common ) {
67 warn "Segment adding node with position skew";
68 } elsif( !$common ) {
69 $common = $r->position->common;
70 }
71 $min = $r->position->min unless $min && $min < $r->position->min;
72 $max = $r->position->max unless $max && $max > $r->position->max;
73 } else {
74 warn "Called set_position on segment which has an unpositioned reading";
75 }
b15511bf 76 }
910a0a6d 77 $self->position( Text::Tradition::Collation::Position->new(
78 common => $common, min => $min, max => $max
79 ) );
b15511bf 80}
910a0a6d 81sub neighbor_readings {
82 my( $self, $direction ) = @_;
83 $direction = 'both' unless $direction;
84 my @answer;
85 if( $direction !~ /^back/ ) {
86 # We want forward readings.
87 push( @answer, $self->members->[0]->neighbor_readings( 'forward' ) );
88 }
89 if( $direction ne 'forward' ) {
90 # We want backward readings.
91 push( @answer, $self->members->[0]->neighbor_readings( 'back' ) );
92 }
93 return @answer;
b15511bf 94}
95
96no Moose;
97__PACKAGE__->meta->make_immutable;
98
991;
100
101######################################################
102## copied from Graph::Easy::Parser docs
103######################################################
104# when overriding nodes, we also need ::Anon
105
106package Text::Tradition::Collation::Segment::Anon;
107use Moose;
108use MooseX::NonMoose;
109extends 'Text::Tradition::Collation::Segment';
110extends 'Graph::Easy::Node::Anon';
111no Moose;
112__PACKAGE__->meta->make_immutable;
113
1141;
115# use base qw/Text::Tradition::Collation::Segment/;
116# use base qw/Graph::Easy::Node::Anon/;
117
118######################################################
119# and :::Empty
120
121package Text::Tradition::Collation::Segment::Empty;
122use Moose;
123use MooseX::NonMoose;
124extends 'Graph::Easy::Node::Empty';
125no Moose;
126__PACKAGE__->meta->make_immutable;
127
1281;
129# use base qw/Text::Tradition::Collation::Segment/;
130
131######################################################