# --
# Kernel/System/CIAttachmentStorage/AttachmentStorageDB.pm - attachment storage in local data base
# Copyright (C) 2006-2011 c.a.p.e. IT GmbH, http://www.cape-it.de
#
# written/edited by:
# * Torsten(dot)Thau(at)cape-it(dot)de
# * Anna(dot)Litvinova(at)cape-it(dot)de
# --
# $Id: AttachmentStorageDB.pm,v 1.2 2011-03-14 09:06:06 alitvinova Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
# --

package Kernel::System::CIAttachmentStorage::AttachmentStorageDB;

use strict;
use MIME::Base64;
use Kernel::System::Encode;
use Kernel::System::DB;
use Digest::MD5 qw(md5_hex);
use Encode qw(encode_utf8);


use vars qw($VERSION);
$VERSION = '$Revision: 1.2 $';
$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;

=head1 NAME

Kernel::System::CIAttachmentStorage::AttachmentStorageDB 

=head1 SYNOPSIS

Provides attachment handling for data base backend - local, OTRS-data base.

=head1 PUBLIC INTERFACE

=over 4

=cut

=item new()

create AttachmentStorageDB object

    use Kernel::Config;
    use Kernel::System::Log;
    use Kernel::System::DB;
    use Kernel::System::CIAttachmentStorage::AttachmentStorage;

    my $ConfigObject = Kernel::Config->new();
    my $LogObject = Kernel::System::Log->new(
        ConfigObject => $ConfigObject,
    );
    my $DBObject = Kernel::System::DB->new(
        ConfigObject => $ConfigObject,
        MainObject => $MainObject,
        LogObject => $LogObject,
    );
    my $AttachmentObject = Kernel::System::CIAttachmentStorage::AttachmentStorageDB->new(
        ConfigObject => $ConfigObject,
        DBObject => $DBObject,
        LogObject => $LogObject,
    );

=cut

sub new {
    my $Type  = shift;
    my %Param = @_;

    # allocate new hash for object
    my $Self = {};
    bless( $Self, $Type );

    # get common objects
    foreach ( keys %Param ) {
        $Self->{$_} = $Param{$_};
    }

    # check all needed objects
    foreach (qw(DBObject ConfigObject LogObject)) {
        die "Got no $_" if ( !$Self->{$_} );
    }

    $Self->{EncodeObject} = Kernel::System::Encode->new(%Param);

    $Self->{DBObject2} = Kernel::System::DB->new(%Param);

    return $Self;
}

=item AttachmentAdd()

create a new std. attachment

    my $ID = $AttachmentObject->AttachmentAdd(
        AttDirID => 123,
        DataRef  => \$SomeContent,
    );

=cut

sub AttachmentAdd {
    my $Self  = shift;
    my %Param = @_;
    my $ID    = 0;

    #check required stuff...
    foreach (qw(AttDirID DataRef)) {
        if ( !$Param{$_} ) {
            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
            return;
        }
    }

    #encode attachment if it's a postgresql backend...
    if ( !$Self->{DBObject2}->GetDatabaseFunction('DirectBlob') ) {
        $Self->{EncodeObject}->EncodeOutput( $Param{DataRef} );

        #overwrite existing value instead of using another filesize of memory...
        ${ $Param{DataRef} } = encode_base64( ${ $Param{DataRef} } );
    }

    #db quoting...
    foreach (qw( AttDirID)) {
        $Param{$_} = $Self->{DBObject2}->Quote( $Param{$_}, 'Integer' );
    }

    #build sql...
    my $SQL = "";
    if ( $Self->{DBObject2}->{Backend}->{'DB::Type'} =~ /oracle/ ) {
        $SQL = "INSERT INTO attachment_storage " .
            " (attachment_directory_id, data) " .
            " VALUES " .
            " ( $Param{AttDirID}, EMPTY_CLOB())";

    }
    else {
        $SQL = "INSERT INTO attachment_storage " .
            " (attachment_directory_id, data) " .
            " VALUES " .
            " ( $Param{AttDirID}, ?)";
    }

    #run sql...
    my $DoResult = 0;
    $DoResult = $Self->{DBObject2}->Do(
        SQL => $SQL, Bind => [ $Param{DataRef} ],    # AttDirID => $Param{AttDirID}
    );

    if ($DoResult) {

        #return ID...
        $Self->{DBObject2}->Prepare(
            SQL => "SELECT id FROM attachment_storage WHERE " .
                "attachment_directory_id = $Param{AttDirID}",
        );
        while ( my @Row = $Self->{DBObject2}->FetchrowArray() ) {
            $ID = $Row[0];
        }
        return $ID;
    }
    else {
        $Self->{LogObject}
            ->Log( Priority => 'error', Message => "Failed to insert attachment data!" );
        return;
    }
}

=item AttachmentGet()

returns an entry in attachment_storage

    my %Data = $AttachmentObject->AttachmentGet(
        ID => 123, #(some attachment storage id) 
        # ...OR...
        AttDirID => 123 #(some attachment directory id),
    );
=cut

sub AttachmentGet {
    my $Self  = shift;
    my %Param = @_;
    my %Data  = ();
    my $WHERE = "";

    #check required stuff...
    if ( !$Param{ID} && !$Param{AttDirID} ) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "Need AttDirID or ID!" );
        return \%Data;
    }

    #db quoting...
    foreach (qw( AttDirID ID)) {
        $Param{$_} = $Self->{DBObject2}->Quote( $Param{$_}, 'Integer' );
    }

    #build sql...
    if ( defined( $Param{AttDirID} ) && $Param{AttDirID} ) {
        $WHERE = " WHERE attachment_directory_id = $Param{AttDirID}";
    }
    else {
        $WHERE = " WHERE id = $Param{ID}";
    }

    my $SQL = "SELECT id, attachment_directory_id FROM attachment_storage " . $WHERE;

    if ( !$Self->{DBObject2}->Prepare( SQL => $SQL, Encode => [ 0, 0, 1 ] ) ) {
        return \%Data;
    }

    my @Data = $Self->{DBObject2}->FetchrowArray();

    if (@Data) {
        my $SQL = "SELECT data FROM attachment_storage " . $WHERE;

        if ( !$Self->{DBObject2}->Prepare( SQL => $SQL ) ) {
            $Self->{LogObject}->Log(
                Priority => 'error',
                Message  => "Failed to prepare SQL for FetchrowArray!"
            );
            return \%Data;
        }

        my @AttachData = $Self->{DBObject2}->FetchrowArray();

        my $AttachDataRef = \$AttachData[0];

        if ( !$AttachDataRef ) {
            $Self->{LogObject}->Log(
                Priority => 'error',
                Message  => "Failed to FetchrowArray!"
            );
            return \%Data;
        }

        #decode attachment if it's a postgresql backend...
        if ( !$Self->{DBObject2}->GetDatabaseFunction('DirectBlob') ) {
            ${$AttachDataRef} = decode_base64( ${$AttachDataRef} );
        }

        %Data = (
            ID       => $Data[0],
            AttDirID => $Data[1],

            #DataType => $Data[2],
            DataRef => $AttachDataRef,
        );

        $AttachDataRef = undef;
    }

    return \%Data;
}

=item AttachmentGetRealProperties()

returns the size of the attachment in the storage backend and the md5sum.

    my RealProperties = AttachmentStorageObject->AttachmentGetRealProperties(
        AttDirID => 123, #(some attachment directory id) 
        #..OR...
		ID => 123, #(some attachment storage id)    
    );

=cut

sub AttachmentGetRealProperties {
    my $Self  = shift;
    my %Param = @_;

    my %RealProperties;

    #check required stuff...
    if ( !$Param{AttDirID} ) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "Need AttDirID!" );
        return %RealProperties;
    }

    my $Data = $Self->AttachmentGet(
        AttDirID => $Param{AttDirID}
    );

    my $Content = ${ $Data->{DataRef} };

    my $RealFileSize = bytes::length($Content);
    my $RealMD5Sum   = md5_hex(encode_utf8($Content));

    $RealProperties{RealFileSize} = $RealFileSize;
    $RealProperties{RealMD5Sum}   = $RealMD5Sum;

    return %RealProperties;
}

1;

=back

=head1 TERMS AND CONDITIONS

This software is part of the OTRS project (http://otrs.org/).

This software comes with ABSOLUTELY NO WARRANTY. For details, see
the enclosed file COPYING for license information (GPL). If you
did not receive this file, see http://www.gnu.org/licenses/gpl.txt.

=cut

=head1 VERSION

$Revision: 1.2 $ $Date: 2011-03-14 09:06:06 $

=cut
