Add new get_combined_holdings() method to MFHD.pm
authorDan Wells <dbw2@calvin.edu>
Tue, 7 May 2013 22:19:34 +0000 (18:19 -0400)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Fri, 9 Aug 2013 15:19:38 +0000 (11:19 -0400)
This commit adds a new method to the MFHD module which creates an
array of compressed holdings from all holdings for a given caption,
combining as needed.

NOTE: This method is similar to, but much less aggressive/strict than
get_compressed_holdings(). Ultimately, get_compressed_holdings()
might be deprecated in favor of this.

Signed-off-by: Dan Wells <dbw2@calvin.edu>
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHD.pm

index 32ea066..dff0066 100644 (file)
@@ -502,6 +502,90 @@ sub get_decompressed_holdings {
     return @return_holdings;
 }
 
+#
+# create an array of compressed holdings from all holdings for a given caption,
+# combining as needed
+#
+# NOTE: this sub is similar to, but much less aggressive/strict than
+# get_compressed_holdings(). Ultimately, get_compressed_holdings() might be
+# deprecated in favor of this
+#
+# TODO: gap marking, gap preservation
+#
+# TODO: some of this could be moved to the Caption (and/or Holding) object to
+# allow for combining in the absense of an overarching MFHD object
+#
+sub get_combined_holdings {
+    my $self = shift;
+    my $caption = shift;
+
+    my @holdings = $self->holdings_by_caption($caption);
+    return () if !@holdings;
+
+    # basic check for necessary pattern information
+    if (!scalar keys %{$caption->pattern}) {
+        carp "Cannot combine without pattern data, returning original holdings";
+        return @holdings;
+    }
+
+    my @sorted_holdings = sort {$a cmp $b} @holdings;
+
+    my @combined_holdings = (shift(@sorted_holdings));
+    my $seqno = 1;
+    $combined_holdings[0]->seqno($seqno);
+    foreach my $holding (@sorted_holdings) {
+        # short-circuit: if we hit an open-ended holding,
+        # it 'includes' all the rest, so just exit the loop
+        if ($combined_holdings[-1]->is_open_ended) {
+            last;
+        } elsif ($holding eq $combined_holdings[-1]) {
+            # duplicate, skip
+            next;
+        } else {
+            # at this point, we know that $holding is gt $combined_holdings[-1]
+            # we just need to figure out if they overlap or not
+
+            # first, get the end (or only) holding of [-1]
+            my $last_holding_end = $combined_holdings[-1]->is_compressed ?
+                $combined_holdings[-1]->clone->compressed_to_last
+                : $combined_holdings[-1]->clone;
+
+            # next, make sure $holding isn't fully contained
+            my $holding_end = $holding->is_compressed ?
+                $holding->clone->compressed_to_last
+                : $holding;
+            # if $holding is fully contained, skip it
+            if ($holding_end le $last_holding_end) {
+                next;
+            }
+
+            # now, get the beginning (or only) holding of $holding
+            my $holding_start = $holding->is_compressed ?
+                $holding->clone->compressed_to_first
+                : $holding;
+
+            if ($last_holding_end->increment ge $holding_start) {
+                # they overlap, combine them
+                my $holding_end;
+                if ($holding->is_compressed) {
+                    $holding_end = $holding->is_open_ended ?
+                    undef
+                    : $holding->compressed_to_last;
+                } else {
+                    $holding_end = $holding;
+                }
+                $combined_holdings[-1]->compressed_end($holding_end);
+            } else {
+                # no overlap, start a new group
+                $holding->seqno(++$seqno);
+                push(@combined_holdings, $holding);
+            }
+        }
+    }
+
+    return @combined_holdings;
+}
+
 ##
 ## close any open-ended holdings which are followed by another holding by
 ## combining them