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

# ----------------------------------------------------------------------------
# ����� ����� ��������� ��� ���������������� ������ Contenido...
# ��� �� ������, ��� ������ ����� � �����������...
# ----------------------------------------------------------------------------

use strict;
use warnings;
use locale;

use vars qw($VERSION);
$VERSION = '4.1';

# ����������� �������... �����...
use Utils;
use IO::File;
use Image::Size;
use Data::Dumper;
use Convert::Cyrillic;
use POSIX qw(:locale_h);


# ����������� ������� Contenido...
use Contenido::Globals;
use Contenido::Logger;
use Contenido::User;
use Contenido::Project;
use Contenido::Request;
use Contenido::State;
use Contenido::Document;
use Contenido::Link;
use Contenido::Section;
use Contenido::Keeper;
use Contenido::Image;
# ���� ������
use Contenido::Type::File;

# ��������� ���������� ��������� ��������� Contenido/ElTexto/Arte
# �� ���� ������ ��� ������ ���������, ���� ����� �������������� �������������� ����������.
sub module_structure {
    return (
        ['documents', '������ ����������', 'Contenido::Document'],
        ['sections', '������ ������', 'Contenido::Section'],
        ['users', '������ �������������', 'Contenido::User'],
        ['links', '������ ������', 'Contenido::Link'],
    );
}


sub init {
    warn "Contenido Init: ������������� Contenido\n" if $DEBUG;

    my $R = contenido_init();

    if ($state->locale) {
        setlocale(LC_COLLATE, $state->locale);
        setlocale(LC_CTYPE,   $state->locale);
    }

    $keeper = Contenido::Keeper->new($state);
    # ���� �� ����� keepalive ����� ����� ����������� � �����, ���� ��� ������������ ��������
    unless ($state->db_type eq 'none') {
        $keeper->db_connect unless $keeper->is_connected;
    }

        $log->info("�������� ������� Contenido::Project") if $DEBUG;
        $project = Contenido::Project->new($state);

    $R += plugins_load();
    $R += modules_load();
    utils_load();

    init_classes();
    clear_not_available();

    # PREAMBLE_HANDLER stuff - load and initialize
    #
	if ( $state->{preamble_handler} ) {
		my $module = $state->{preamble_handler};      # main preamble hanler
		my $path   = $state->{preamble_handler_path}; # extra preamble handlers relative path
		eval "use $module";
		if ( $@ ) {
            $R++; $log->error("Cannot load module $module because of '$@'");
		}
		$state->{preamble_handler_obj} = $module->new( $path ? (load_modules => $path) : () );
    }

    unless ($state->db_type eq 'none') {
        $keeper->shutdown;
    }

    if ($R) {
        $log->error("��� ������������� Contenido ��������� ������ (���������� - $R)") if $DEBUG;
    } else {
        $log->info("������������� Contenido ������ �������") if $DEBUG;
    }

    return ($R ? 1 : 0);
}

sub init_classes {
    foreach (&module_structure, ['locals', '��������� ������', $keeper->state()->project() ]) {
        my $tag = $_->[0];
        $state->{'available_'.$tag} ||= [];
        if (ref($state->{'available_'.$tag}) eq 'ARRAY') {
            foreach my $class (@{$state->{'available_'.$tag}}) {
                $class->class_init;
            }
        } else {
            $log->error("Wrong structure in \$state->{available_$tag} (".$state->{'available_'.$tag}."), must be ARRAY REF");
            die;
        }
    }
}

sub clear_not_available {
    foreach (&module_structure, ['locals', '��������� ������', $keeper->state()->project() ]) {
        my $tag = $_->[0];
        next unless ref $state->{'available_'.$tag} eq 'ARRAY';
        for (my $i = 0; $i <= $#{$state->{'available_'.$tag}} ; $i++) {
            my $class = $state->{'available_'.$tag}->[$i];
            unless ($class->contenido_is_available) {
                splice(@{$state->{'available_'.$tag}}, $i--, 1);
                $log->debug('������ ����� ' . $class . ' �� $state->{available_' . $tag . '}') if $DEBUG;
            }
        }
    }
}

sub load_classes {
    shift;
    for (@_) {
        eval "use $_";
        #����� ������ eval ���� �� ��������� ����� $@ ?
        $log->error("Cannot load class $_ because of $@") if ($@);
        if ($_->can('class_init')) {
            eval {$_->class_init};
            $log->error("Error on class_init for class $_ because of $@") if ($@);
        }
        $log->info("�������� ����� $_") if $DEBUG;
    }
}

sub plugins_load {
    my $LR = 0;

    # ----------------------------------------------------------------------------
    # ������ ��� ���� ���������� ��� ��������� ������...
    for my $plugin ($state->project, split(/\s+/, $state->plugins)) {
        my $class = $plugin.'::Init';
        eval ("use $class");
        $log->error("������ ��� �������� ������.\n$@!") if $@;

        {
            package HTML::Mason::Commands;
            eval ("use $class");
        }

        
        if ( $@ ) {
            $log->error("�� ���� ���������� ������ $plugin (������������� $class) �� ������� '$@'");
            $LR++;
        } else {
            $log->info("�������� ����� $class ��� ������� $plugin") if $DEBUG;
            eval {
                $LR += $class->init( $keeper );
            };
            if ( $@ ) {
                $log->error("�� ���� ��������� ������������� ������� $plugin (������������� $class) �� ������� '$@'");
                $LR++;
            }
        }
    }

    return $LR;
}

sub utils_load {
    Utils::load_modules( ['Utils::HTML'] );
}


sub modules_load {
    my $path = __FILE__;
    $path =~ s|/[^/]*$||;
    $path =~ s|/Contenido$||;

    my $LR = 0;

    my @ms = ();

    # ��������� �������� ��������� �������...
    push (@ms, ['locals', '��������� ������', $keeper->state()->project() ] );


    foreach my $ms (@ms) {
        $log->info("���������� ".$ms->[1]) if $DEBUG;

        my $pathlib = $path.'/'.$ms->[2];
        $pathlib =~ s|::|/|gi;
        if (! -s $pathlib) {
            $log->warning("���������� ${pathlib} �� ����������. ���������!");
        } else {
            opendir(DIR, $pathlib) || do { $log->error("�� ���� ������� ���������� ${pathlib} ��� ����������� �������"); die };
            my @modules = grep {/\.pm$/} readdir(DIR);
            closedir(DIR);

            foreach my $module (@modules) {
                $module =~ s/\.pm$//;

                my $class = $ms->[2]."::".$module;

                eval("
                    package TestPackage::$class;
                    use $class;
                    1;
                ");

                if ( $@ ) {
                    $log->error("�� ���� ���������� ������ $module (����� $class) �� ������� '$@'");
                    $LR++;
                } else {
                    $log->info("�������� ����� $class") if $DEBUG;
                    next unless $class->isa('Contenido::Object');
                    foreach (&module_structure()) {
                        my ($tag, $name, $proto) = @$_;
                        if ($class->isa($proto)) {
                            push (@{ $state->{'available_'.$tag} }, $class);
                            $log->info("����� $class ���� $name '".$class->class_name()."' (�������� $proto)") if $DEBUG;
                        }
                    }
                }
            }
        }
    }

    # ��� �������� ���������� ��� ������� - Contenido::User, Contenido::Section... ������ ������� �� � ������ ������������
    push (@{ $state->{'available_sections'} }, 'Contenido::Section');
    push (@{ $state->{'available_users'} }, 'Contenido::User');
    push (@{ $state->{'available_links'} }, 'Contenido::Link');

    return $LR;
}

# �������� �������� Contenido...
sub contenido_init {
    warn "Contenido Init: �������� ������� Contenido::State\n" if $DEBUG;
    $state = Contenido::State->new();
    $log = Contenido::Logger->new(
        log_format  => $state->{__debug_format__}      || '%d %C:%L (%P) [%l]: "%m"%n',
        max_level   => $state->{__debug_max_level__}   || 'emergency',
        min_level   => $state->{__debug_min_level__}   || 'debug',
        stack_trace => $state->{__debug_stack_trace__} || 0,
    );

    return 1 unless ref $state && ref $log;
    $log->info("������ ������ Contenido::Logger") if $DEBUG;

    $state->debug($DEBUG);
    $state->info() if $DEBUG;

    return 0;
}

1;