package Common::DB::Deploy::RepositoryManager;

use strict;
use warnings;

use Carp;
use File::Spec;

# 2018-07-01_15-34_UTC_RSD-111_short_description_litnev.sql
use constant RE_SCRIP_VERSION => qr/^(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}_UTC_[a-zA-Z]+-\d+).*\.sql/i;
use constant RE_SCRIPT_EXT    => qr/\.(?:sql|gz|bz2)$/i;

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

    my $self = bless {
        oLogger             => $args{oLogger},
        repository_dirs     => $args{repository_dirs} || {},
        allowed_dir_pattern => '',
        repository_scripts  => {},
    }, $class;

    $self->_init(\%args);
    return $self;
}

sub logger {
    return shift->{oLogger};
}

sub getAllowedDirPattern {
    return shift->{allowed_dir_pattern};
}

sub getAllowedScriptExtentionPattern {
    return RE_SCRIPT_EXT;
}

sub getRepositoryScripts{
    return shift->{repository_scripts};
}

sub _init {
    my ($self, $hOption) = @_;

    $self->_createAllowedDirPattern($hOption);
    $self->_parseRepositoryForScripts();

    return 1;
}

sub _createAllowedDirPattern {
    my ($self, $hOption) = @_;

    my $allowedDirs = $hOption->{allowed_dir_prefix} || '';
    my $pattern = join '|', grep {$_} $allowedDirs =~ /(\w+)/g;
    $self->{allowed_dir_pattern} = qr/^$pattern/i;

    return 1;
}

sub _parseRepositoryForScripts {
    my $self = shift;

    $self->logger->debug("Preparing the scripts list from the repository.");

    while ( my ($catalog, $rootDir) = each %{ $self->{repository_dirs} } ) {
        unless ( -d $rootDir ) {
            my $e = "Directory '$rootDir' doesn't exist.";
            $self->logger->error($e); croak $e;
        }

        foreach my $dbDir ( $self->_getRootDirContent($rootDir) ) {
            my $pathToScript = File::Spec->catdir($rootDir, $dbDir);
            my @scripts = $self->_getParentDirContent($pathToScript);

            # create a list of repository sripts
            foreach my $script (@scripts) {
                my $scriptVersion = $self->getVersionByScriptName($script);
                $self->{repository_scripts}{$catalog}{$pathToScript}{$scriptVersion} = $script;
            }
        }
    }

    return 1;
}

sub _getRootDirContent {
    my ($self, $dir) = @_;
    return $self->_getDirContent($dir, '-d', $self->getAllowedDirPattern);
}

sub _getParentDirContent {
    my ($self, $dir) = @_;
    return $self->_getDirContent($dir, '-f', $self->getAllowedScriptExtentionPattern);
}

sub _getDirContent{
    my ($self, $dir, $type, $pattern) = @_;
    $type    ||= '-e';
    $pattern ||= qr/.+/;

    my @content;
    opendir my $dh, $dir or die "Can't open dir: $!";
    @content = grep { !/^\.+$/ && -d File::Spec->catdir($dir, $_) && $_ =~ $pattern } readdir $dh if $type eq '-d';
    @content = grep { !/^\.+$/ && -f File::Spec->catdir($dir, $_) && $_ =~ $pattern } readdir $dh if $type eq '-f';
    @content = grep { !/^\.+$/ && -e File::Spec->catdir($dir, $_) && $_ =~ $pattern } readdir $dh if $type eq '-e';
    closedir $dh;

    return wantarray ? @content : \@content;
}

sub getVersionByScriptName {
    my ($self, $scriptName) = @_;

    return lc $1 if $scriptName =~ RE_SCRIP_VERSION;
    croak "Can't to detect version for the script '$scriptName'";
}


1;