package JSTAPd::ContentsBag;
use strict;
use warnings;

use JSTAPd::Contents;

sub dir { $_[0]->{dir} }

sub new {
    my($class, %args) = @_;

    my $self = bless { dir => $args{dir}, run_file => $args{run_file} }, $class;
    $self;
}

sub _loader {
    my($self, $base) = @_;

    my $dir = +{ children => +{}, map => +{}, path => $base };
    my @contents;
    for my $path ($base->children) {
        if ($path->is_dir) {
            my $name  = $path->dir_list(-1);
            my $stuff = $self->_loader($path);
            $stuff->{name} = $name;
            push @contents, $stuff;
            $dir->{children}->{$name} = $stuff;
            next;
        }
        my $basename = $path->basename;
        next unless $path =~ /\.t$/ || $basename eq 'index';
        if ($self->{run_file} && $basename ne 'index') {
            next unless $path->relative($self->{dir}) eq $self->{run_file};
        }
        my $stuff = JSTAPd::Contents->new( $basename => $path );
        push @contents, $stuff;
        $dir->{map}->{$basename} = $stuff;
    }
    $dir->{contents} = \@contents;
    $dir;
}

sub load {
    my $self = shift;
    $self->{contents} = $self->_loader( $self->{dir} );
}

sub fetch_file {
    my($self, $basename, $chain, $is_inherit) = @_;

    my $dir = $self->{contents};
    my $parent = $dir->{map}->{$basename};
    for my $name (@{ $chain || [] }) {
        unless ($dir = $dir->{children}->{$name}) {
            return;
        }
        $parent = $dir->{map}->{$basename} || $parent;;
    }
    my $content = $dir->{map}->{$basename};
    $content = $parent if !$content && $is_inherit;
    return $content;
}

sub fetch_dir {
    my($self, $chain) = @_;

    my $dir = $self->{contents};
    for my $name (@{ $chain || [] }) {
        unless ($dir = $dir->{children}->{$name}) {
            return;
        }
    }
    return $dir;
}

sub each {
    my($self, $chain, $cb) = @_;
    my $dir   = $self->fetch_dir($chain);
    for my $contents (@{ $dir->{contents} }) {
        my $is_dir = ref($contents) eq 'HASH';
        $cb->($contents->{name}, $is_dir);
    }
}

sub _visitor {
    my($self, $path, $contents, $cb) = @_;
    for my $child (@{ $contents }) {
        my $current = $path;
        $current .= '/' if $current;
        $current .= $child->{name};
        my $is_dir = (ref($child) eq 'HASH');
        $cb->({
            name   => $child->{name},
            path   => $current,
            is_dir => $is_dir,
        });
        $self->_visitor($current, $child->{contents}, $cb) if $is_dir;
    }
}

sub visitor {
    my($self, $cb) = @_;
    $self->_visitor('', $self->{contents}->{contents}, $cb);
}

1;
