#/*
# *  Copyright 2007-2010 hkrn <hikarin@users.sourceforge.jp>
# *
# *  Licensed under the Apache License, Version 2.0 (the "License");
# *  you may not use this file except in compliance with the License.
# *  You may obtain a copy of the License at
# *
# *      http://www.apache.org/licenses/LICENSE-2.0
# *
# *  Unless required by applicable law or agreed to in writing, software
# *  distributed under the License is distributed on an "AS IS" BASIS,
# *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# *  See the License for the specific language governing permissions and
# *  limitations under the License.
# */
#
# $Id: Message.pm 1901 2009-12-31 02:40:20Z hikarin $
#

package Zeromin::Message;

use strict;

BEGIN {
    my $class = __PACKAGE__;
    for my $methodName (qw( get_read get_unread receive )) {
        no strict 'refs';
        *{"${class}::${methodName}_with_page"} = sub {
            my ( $zMessage, $item_per_page, $offset ) = @_;
            require Data::Page;
            my $entries = $zMessage->$methodName();
            my $page = Data::Page->new( scalar @$entries, $item_per_page,
                $offset );
            return ( [ $page->splice($entries) ], $page );
            }
    }
}

sub new {
    my ( $zClass, $iKernel, $sender ) = @_;
    my $repos = $iKernel->get_repos_path('zeromin_message');

    bless {
        __kernel => $iKernel,
        __now    => time(),
        _repos   => $iKernel->get_repos($repos),
        _sender  => $sender,
    }, $zClass;
}

sub set_sender {
    my ( $zMessage, $sender ) = @_;
    $zMessage->{_sender} = $sender;
    return;
}

sub send {
    my ( $zMessage, $send_to, $title, $message ) = @_;
    my $sender = $zMessage->{_sender} || return 0;
    my $iRepos = $zMessage->{_repos};
    my $top    = $iRepos->get_int("Z:M.${send_to}._") + 1;
    my $prefix = join '.', 'Z:M', $send_to, $top;

    $iRepos->set( "${prefix}.from", $sender );
    $iRepos->set( "${prefix}.read", 0 );
    $iRepos->set( "${prefix}.sent", $zMessage->{__now} );
    $iRepos->set_binary( "${prefix}.title",   $title );
    $iRepos->set_binary( "${prefix}.message", $message );
    $iRepos->set( "Z:M.${send_to}._", $top );
    $iRepos->save();

    return 1;
}

sub receive {
    my ($zMessage) = @_;
    my $sender = $zMessage->{_sender} || return 0;
    my $iRepos = $zMessage->{_repos};
    my $ret    = [];

SENDER:
    for my $receiver ( '*', $sender ) {
        my $top = $iRepos->get_int("Z:M.${receiver}._");

    MESSAGE:
        for ( my $i = 1; $i <= $top; $i++ ) {
            my $data = $zMessage->get( $i, $receiver );
            $data->{sent} or next MESSAGE;
            push @$ret, $data;
        }
    }

    return [
        map  { $_->[1] }
        sort { $b->[0] <=> $a->[0] }
        map  { [ $_->{sent}, $_ ] } @$ret
    ];
}

sub get_unread {
    my ($zMessage) = @_;
    return [ grep { !$_->{is_read} } @{ $zMessage->receive() } ];
}

sub get_read {
    my ($zMessage) = @_;
    return [ grep { $_->{is_read} } @{ $zMessage->receive() } ];
}

sub get {
    my ( $zMessage, $id, $sender ) = @_;
    my $iRepos = $zMessage->{_repos};
    $sender ||= $zMessage->{_sender};

    my $prefix = join '.', 'Z:M', $sender, $id;
    if ( my $from = $iRepos->get("${prefix}.from") ) {
        return {
            id      => $id,
            from    => $from,
            subject => $iRepos->get_binary("${prefix}.title"),
            message => $iRepos->get_binary("${prefix}.message"),
            sent    => $iRepos->get("${prefix}.sent"),
            is_read => $iRepos->get_int("${prefix}.read"),
            is_all  => ( $sender eq '*' ? 1 : 0 ),
        };
    }
    else {
        return {
            id      => undef,
            from    => '',
            subject => '',
            message => '',
            sent    => 0,
            is_read => 0,
            is_all  => 0,
        };
    }
}

sub remove {
    my ( $zMessage, $id, $sender ) = @_;
    $sender ||= $zMessage->{_sender} || return 0;

    my $iRepos = $zMessage->{_repos};
    my $prefix = join '.', 'Z:M', $sender, $id;

    if ( $iRepos->remove("${prefix}.sent") ) {
        $iRepos->remove("${prefix}.from");
        $iRepos->remove("${prefix}.read");
        $iRepos->remove("${prefix}.title");
        $iRepos->remove("${prefix}.message");
        $iRepos->save();
        return 1;
    }

    return 0;
}

sub read { _read( 1, @_ ) }

sub unread { _read( 0, @_ ) }

sub _read {
    my ( $flag, $zMessage, $id, $receiver, $sender ) = @_;

    my $iRepos = $zMessage->{_repos};
    my $prefix = join '.', 'Z:M', $receiver, $id;
    my $from   = $iRepos->get("${prefix}.from");

    if ( $iRepos->get("${prefix}.sent") and $from eq $sender ) {
        $iRepos->set( "${prefix}.read", $flag );
        $iRepos->save();
        return $zMessage->get( $id, $receiver );
    }
    elsif ( $iRepos->get("Z:M.*.${id}.from") ) {
        $iRepos->set( "Z:M.*.${id}.read", $flag );
        $iRepos->save();
        return $zMessage->get( $id, '*' );
    }

    return $zMessage->get(0);
}

1;
__END__
