Revision 3 (by ahitrov@rambler.ru, 2010/03/24 15:19:32) The CORE
package Contenido::MVC::Dispatcher;

use strict;
use Utils;
use Data::Dumper;

# ���� ����������� (��������� ����, ������� ����)
my @DISPATCH_TYPES = qw(Path Regex);

sub init {
        my $proto = shift;
        my %opts = @_;
        my $class = ref($proto) || $proto;
        
        my $self = {};
        bless $self, $class;

        $self->load_dispatch_types( %opts );
        $self->load_actions( %opts );

        return $self;
}

# ������ ��������� �����������
sub get_dispatch_types {
        return @DISPATCH_TYPES;
}

# �������� ����� �����������
sub load_dispatch_types {
        my $self = shift;

        foreach my $typename ( $self->get_dispatch_types() ) {

                my $class = 'Contenido::MVC::DispatchType::'.$typename;
                Utils::load_modules( [ $class ] );
                $self->{dispatch_types}->{ $typename } = new $class;

        }

}

# �������� actions �����������
sub load_actions {
        my $self = shift;
        my %opts = @_;

        my $controller_class = $opts{controller_class};
        $controller_class = [ $controller_class ] unless ref($opts{controller_class}) eq 'ARRAY';

        Utils::load_modules( $controller_class );

        foreach my $class (@$controller_class) {

                # ���������� �����������
                my $controller = $class->init();
                $self->register_controller( $controller );

                foreach my $typename ( $self->get_dispatch_types() ) {

                        my $dispatch_type = $self->{dispatch_types}->{ $typename };

                        my $method = 'get_'.lc($typename).'_actions';
                        my $actions = $controller->$method;
                
                        next unless $actions && ref($actions) eq 'ARRAY';
                
                        foreach my $action (@$actions) {
                                next unless $action && ref($action) eq 'HASH';

                                # ���������� ������ �� ������������ ����������� ������ action
                                $action->{'controller_class'} = $class;

                                # �������� �� ��, ����� �� ���� �������� �����
                                next unless $controller->can( $action->{'sub'} );

                                # ����������� ������
                                $dispatch_type->register( $action );
                        }
                
                }
        }

        # ���� ��������� (������ ����������� ��� ���������� ������� � ����������)
        # � �������: ���� �� �������� ����������� ���� ������� � 10 ���,
        # ��� ����� � �������������� ��������� sorder ����� ������� ��������� ���������
        # ����������, ������� � 0 - ������������

        foreach my $typename ( $self->get_dispatch_types() ) {
                my $dispatch_type = $self->{dispatch_types}->{ $typename };
                $dispatch_type->after_register();
        }

        return 1;
}

# ����������� �����������
sub register_controller {
        my $self = shift;
        my $controller = shift;

        my $class = ref($controller);
        $self->{controllers}->{$class} = $controller;
}

# ��������� ����������� � ����������� �� action
sub get_controller {
        my $self = shift;
        my $action = shift;

        my $controller = $self->{controllers}->{ $action->{'controller_class'} };
        $controller->set_action( $action );
        return $controller;
}


# ��������� �������� ����������
sub get_main_controller {
        my $self = shift;
        return $self->{controllers}->{'main'};
}

# ��������� �������� �����������
sub set_main_controller {
        my $self = shift;
        my %opts = @_;
        my $controller = $opts{controller_class}->init();
        $self->{controllers}->{'main'} = $controller;
}

# ���������� action
sub get_action {
        my $self = shift;
        my $r	= shift;

        my $path = $r->uri();
        $path =~ s/\/+/\//;
        $path =~ s/index\.\w+$//i;

        my $action = undef;

        # �������� �� ���� ����� �����������
        DP: foreach my $typename ( $self->get_dispatch_types() ) {

                my $dispatch_type = $self->{dispatch_types}->{ $typename };
                if ($action = $dispatch_type->match( $path )) {
                        last DP;
                }
        }
        return $action; 
}

1;