#!/usr/bin/perl

# ---------------------------------------------------------------
# Prontus CMS
# http://www.prontus.cl
# by Altavoz.net
#
# licensed under LGPL license.
# http://www.prontus.cl/license.html
# ---------------------------------------------------------------

# -------------------------------COMENTARIO GLOBAL---------------
# ---------------------------------------------------------------
# PROPOSITO.
# -----------
# Funciones para utilizar amazon s3
# ---------------------------------------------------------------

# ---------------------------------------------------------------
# DECLARACIONES GLOBALES.
# ------------------------

package lib_s3;

use strict;
use utf8;

our $CONN;

sub check_config_s3 {
    if ($prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_HABILITAR'} eq 'SI' &&
        $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_ENDPOINT'} ne '' &&
        $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_ACCESS_KEY'} ne '' &&
        $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_SECRET_KEY'} ne '' &&
        $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_BUCKET_NAME'} ne '' ) {

        if ($Net::Amazon::S3::VERSION > 0.9) {
            # parcha la funcion incorrecta de la libreria
            *Net::Amazon::S3::Client::Object::put_part = sub {
                my $self = shift;

                my %args = ref($_[0]) ? %{$_[0]} : @_;

                #work out content length header
                $args{headers}->{'Content-Length'} = length $args{value}
                    if(defined $args{value});

                my $response = $self->_perform_operation (
                    'Net::Amazon::S3::Operation::Object::Upload::Part',

                    upload_id   => $args{upload_id},
                    part_number => $args{part_number},
                    headers     => $args{headers},
                    value       => $args{value},
                );

                return $response->http_response;
            };
        }

        return 1;
    }
    return 0;
}

sub connect_s3 {
    $CONN = undef;
    $CONN = Net::Amazon::S3->new({
        aws_access_key_id     => $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_ACCESS_KEY'},
        aws_secret_access_key => $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_SECRET_KEY'},
        host                  => $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_ENDPOINT'},
        secure                => 1,
        retry                 => 1,
    });

    $CONN->ua->ssl_opts (
        verify_hostname => 0,
        SSL_verify_mode => 0,
    );

    my $default_headers = HTTP::Headers->new('user-agent' => 'Prontus CMS');
    $CONN->ua->default_headers($default_headers);
    # evita error MissingContentLength al cambiar acl
    $CONN->ua->default_header('Content-Length' => "0");
}


sub connect_bucket {
    my $client = Net::Amazon::S3::Client->new( s3 => $lib_s3::CONN );
    my $bucket = $client->bucket( name => $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_BUCKET_NAME'} );
    return $bucket;
}

# lista todos las archivos asociadas a este patron
sub list_files_pattern {
    my ($bucket, $prefix) = @_;
    print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Listar S3: $prefix\n";
    my @list;
    my $stream = $bucket->list( { prefix => $prefix } );
    until ( $stream->is_done ) {
        foreach my $object ( $stream->items ) {
            if ($CONN->err){
                print STDERR $CONN->err . ": " . $CONN->errstr;
                return [];
            }
            push(@list, $object);
        }
    }
    return @list;
}

# borrar todos las archivos asociados a un patron
sub delete_files_pattern {
    my ($bucket, $prefix) = @_;
    my $stream = $bucket->list( { prefix => $prefix } );
    until ( $stream->is_done ) {
        foreach my $object ( $stream->items ) {
            $object->delete;
            if ($CONN->err){
                print STDERR $CONN->err . ": " . $CONN->errstr;
                return 0;
            }
            print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Borrar S3: ". $object->key. " - ".  &lib_prontus::bytes2kb($object->size) ."\n";
        }
    }
    return 1;
}

# borra un archivo
sub delete_file_key {
    my ($bucket, $key) = @_;
    my $object = $bucket->object(key => $key);
    $object->delete;
    if ($CONN->err) {
        print STDERR $CONN->err . ": " . $CONN->errstr;
        return 0;
    }
    print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Borrar S3: ". $object->key. " - ".  &lib_prontus::bytes2kb($object->size) ."\n";
    return 1;
}

sub upload_multipart {
    my ($bucket, $file, $file_name) = @_;
    if (!-s $file) {
        print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Tamaño 0 $file, se omite\n";
        return 1;
    }
    print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Cargar $file ",  &lib_prontus::bytes2kb(-s $file) ,"\n";
    if (open(my $fh, '<', $file)) {
        $file =~ /\.(\w+)$/;
        my $ext = $1;
        my $object = $bucket->object(
            key          => $file_name,
            acl_short    => 'public-read',
            content_type => mime_types::ext_2_type($ext)
        );

        my $upload_id = $object->initiate_multipart_upload;
        binmode $fh;
        my $chunk_content;
        my $counter = 1;
        my @etags;
        my @part_numbers;
        while (read $fh, $chunk_content, 50*1048576) {
            print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] ", "Parte [$counter] ", length $chunk_content ,"\n";
            #add a part to a multipart upload
            my $put_part_response = $object->put_part(
                upload_id      => $upload_id,
                part_number    => $counter,
                value          => $chunk_content,
            );
            my $part_etag = $put_part_response->header('ETag');
            push(@etags, $part_etag);
            push(@part_numbers, $counter);
            $counter++;
            $chunk_content = undef;
            if ($lib_s3::CONN->err) {
                print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Error",  $lib_s3::CONN->err . ": " . $lib_s3::CONN->errstr ."\n";
                return 0;
            }
        }

        # complete a multipart upload
        $object->complete_multipart_upload(
            upload_id       => $upload_id,
            etags           => \@etags,
            part_numbers    => \@part_numbers,
        );
        close $fh;
        if ($lib_s3::CONN->err) {
            print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Error",  $lib_s3::CONN->err . ": " . $lib_s3::CONN->errstr ."\n";
            return 0;
        }

        # legacy interface
        my $legacy_bucket = $lib_s3::CONN->bucket($prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'S3_BUCKET_NAME'});

        $legacy_bucket->edit_metadata($file_name, {
            content_type   => mime_types::ext_2_type($ext),
            acl_short => 'public-read',
        });
        if ($lib_s3::CONN->err) {
            print STDERR "[" , &glib_hrfec_03::get_dtime_pack4() , "] Error ",  $lib_s3::CONN->err . ": " . $lib_s3::CONN->errstr ."\n";
            return 0;
        }
        return 1;
    }
    return 0;
}

sub get_art_size {
    my ($ts, $bucket) = @_;

    my @prefixes;
    my $dst_base = $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'DIR_SITE'} . "$prontus_varglb::DIR_EXMEDIA/" . substr($ts, 0, 8) . "$prontus_varglb::DIR_MMEDIA/";
    $dst_base = substr($dst_base, 1);
    my $s3_media_size = 0;
    my @s3_files = lib_s3::list_files_pattern($bucket, $dst_base);
    foreach my $remote (@s3_files) {
        next if ($remote->key !~ /$ts/);
        print STDERR $remote->key . " - ". $remote->uri . " - ". lib_prontus::bytes2kb($remote->size) ."\n";
        $s3_media_size += $remote->size;
    }

    $dst_base = $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'DIR_SITE'} . "$prontus_varglb::DIR_ASOCFILE/" . substr($ts, 0, 8) . "/$ts/";
    $dst_base = substr($dst_base, 1);
    @s3_files = ();
    my $s3_asset_size = 0;
    @s3_files = lib_s3::list_files_pattern($bucket, $dst_base);
    foreach my $remote (@s3_files) {
        print STDERR $remote->key . " - ". $remote->uri . " - ". lib_prontus::bytes2kb($remote->size) ."\n";
        $s3_asset_size += $remote->size;
    }
    return ($s3_media_size, $s3_asset_size);
}

1;
