package Catalyst::Controller::DBIC::API::JoinBuilder;

#ABSTRACT: Provides a helper class to automatically keep track of joins in complex searches
use Moose;
use MooseX::Types::Moose(':all');
use Catalyst::Controller::DBIC::API::Types(':all');
use namespace::autoclean;

=attribute_public parent is: ro, isa: 'Catalyst::Controller::DBIC::API::JoinBuilder'

parent stores the direct ascendant in the datastructure that represents the join

=cut

has parent =>
(
    is => 'ro',
    isa => JoinBuilder,
    predicate => 'has_parent',
    weak_ref => 1,
    trigger => sub { my ($self, $new) = @_; $new->add_child($self); },
);

=attribute_public children is: ro, isa: ArrayRef['Catalyst::Controller::DBIC::API::JoinBuilder'], traits => ['Array']

children stores the immediate descendants in the datastructure that represents the join.

Handles the following methods:

    all_children => 'elements'
    has_children => 'count'
    add_child => 'push'

=cut

has children =>
(
    is => 'ro',
    isa => ArrayRef[JoinBuilder],
    traits => ['Array'],
    default => sub { [] },
    handles =>
    {
        all_children => 'elements',
        has_children => 'count',
        add_child => 'push',
    }
);

=attribute_public joins is: ro, isa: HashRef, lazy_build: true

joins holds the cached generated join datastructure.

=cut

has joins =>
(
    is => 'ro',
    isa => HashRef,
    lazy_build => 1,
);

=attribute_public name is: ro, isa: Str, required: 1

Sets the key for this level in the generated hash

=cut

has name =>
(
    is => 'ro',
    isa => Str,
    required => 1,
);

=method_private _build_joins

_build_joins finds the top parent in the structure and then recursively iterates the children building out the join datastructure

=cut

sub _build_joins
{
    my ($self) = @_;

    my $parent;
    while(my $found = $self->parent)
    {
        if($found->has_parent)
        {
            $self = $found;
            next;
        }
        $parent = $found;
    }

    my $builder;
    $builder = sub
    {
        my ($node) = @_;
        my $foo = {};
        map { $foo->{$_->name} = $builder->($_) } $node->all_children;
        return $foo;
    };

    return $builder->($parent || $self);
}

=head1 DESCRIPTION

JoinBuilder is used to keep track of joins automgically for complex searches. It accomplishes this by building a simple tree of parents and children and then recursively drilling into the tree to produce a useable join attribute for ->search.

=cut

1;
