+ if ( @vals ) {
+ $filters->{$name} = [ @vals ];
+ warn "# filter + $name $#vals\n";
+
+ my $filter_hash;
+ $filter_hash->{$_}++ foreach @vals;
+
+ warn "# filter_hash ",dump( $filter_hash );
+
+ my $items = $self->_loaded('data')->{items};
+
+ my $include_missing = defined $filter_hash->{_missing};
+ my $filtered_items;
+
+ foreach my $i ( 0 .. $#$items ) {
+
+ if ( defined $items->[$i]->{$name} ) {
+ foreach my $v ( @{ $items->[$i]->{$name} } ) {
+ if ( defined $filter_hash->{ $v } ) {
+ $filtered_items->{$i}++;
+ }
+ }
+ } elsif ( $include_missing ) {
+ $filtered_items->{$i}++;
+ }
+ }
+
+ warn "# filter $name ",dump($filtered_items);
+
+ $loaded->{$path}->{filters}->{$name} = $filtered_items;
+
+ } else {
+ warn "# filter - $name\n";
+ delete $filters->{$name};
+ delete $loaded->{$path}->{filters}->{$name};
+ }
+
+ warn "# filters ",dump($filters);
+
+ $self->session( 'offset' => 0 );
+
+ $self->redirect_to('/data/items');
+}
+
+
+sub _data_items {
+ my ( $self, $all ) = @_;
+ my $data = $self->_loaded( 'data' );
+
+ return @{ $data->{items} } if $all == 1;
+
+ my $filters = $self->_current_filters;
+ my $filter_value;
+ foreach my $f ( keys %$filters ) {
+ foreach my $n ( @{ $filters->{$f} } ) {
+ $filter_value->{$f}->{$n} = 1;
+ }
+ }
+ my @items = @{ $data->{items} };
+ @items = grep {
+ my $i = $_;
+ my $pass = 1;
+ foreach my $n ( keys %$filter_value ) {
+ if ( ! exists $i->{$n} ) {
+ if ( defined $filter_value->{$n}->{_missing} ) {
+ $pass = 1;
+ next;
+ } else {
+ $pass = 0;
+ last;
+ }
+ }
+ # and match any of values in element
+ my $have_values = 0;
+ foreach my $v ( @{ $i->{$n} } ) { # FIXME not array?
+ $have_values ||= 1 if defined $filter_value->{$n}->{$v};
+ }
+ if ( ! $have_values ) {
+ $pass = 0;
+ last;
+ }
+ }
+ $pass;
+ } @items if $filter_value;
+ return @items;
+}
+
+
+sub _current_filters {
+ my $self = shift;
+ my $current_filters;
+ $current_filters->{ $_ } = $filters->{ $_ }
+ foreach (
+ grep { defined $filters->{ $_ } }
+ @{ $self->_loaded('header') }
+ );
+ warn "# current_filters ",dump($current_filters);
+ return $current_filters;
+}
+
+sub _data_sorted_by {
+ my ( $self, $order ) = @_;
+
+ my $path = $self->session('path');
+
+ if ( defined $loaded->{$path}->{sorted}->{$order} ) {
+ return $loaded->{$path}->{sorted}->{$order};
+ }
+
+ my $data = $self->_loaded( 'data' );
+ my $numeric = $self->_is_numeric($order);
+ my $missing = $numeric ? 0 : '';
+ no warnings qw(numeric);
+ my $nr = 0;
+ my @sorted = map {
+ $_->[0]
+ } sort {
+ if ( $numeric ) {
+ $a->[1] <=> $b->[1]
+ } else {
+ $a->[1] cmp $b->[1]
+ }
+ } map {
+ [ $nr++, exists $_->{$order} ? join('', @{$_->{$order}}) : $missing ]
+ } @{ $data->{items} }
+ ;
+
+ warn "sorted $order"; # ,dump( @sorted );
+
+ $loaded->{$path}->{sorted}->{$order} = [ @sorted ];
+}
+
+
+sub items {
+ my $self = shift;
+
+ my $path = $self->session('path');
+ $self->redirect_to('/data/index') unless defined $loaded->{ $path };