# Copyright 2004-2004, Fred Steinberg, Brown Bear Software

# Check event for things like 'in the past', time conflicts

package Database;
use strict;
use Calendar::TimeConflict;

sub validateEvent {
    my $self = shift;
    my %args = (event           => undef,
                op              => undef,
                dateObj         => undef,
                editedEventID   => undef,
                ignorePast      => undef,
                ignoreFuture    => undef,
                ignoreConflicts => undef,
                @_);
    my $event           = $args{event};
    my $prefs           = Preferences->new ($self);
    my $dateObj         = $args{dateObj};
    my $ignoreFuture    = $args{ignoreFuture};
    my $ignoreConflicts = $args{ignoreConflicts};
    my $ignorePast      = $args{ignorePast};
    my $editedEventID   = $args{editedEventID};
    my $hasAdmin = $args{op} && Permissions->new ($self)->permitted
                                            ($args{op}->getUsername, 'Admin');

    $event->Prefs ($prefs);     # needed for Time Periods

    my %errHash;

    # Check for required fields
    my $requireds = $prefs->RequiredFields || '';
    my @reqErrs;
    foreach (split ',', $requireds) {
        if (/category/i) {
            push @reqErrs, $_ unless defined $event->category;
        }
        if (/details/i) {
            push @reqErrs, $_ unless defined ($event->popup or $event->link);
        }
        if (/time/i) {
            push @reqErrs, $_ unless $event->hasTime;
        }
    }
    $errHash{'missing required fields'} = join (',', @reqErrs)
        if @reqErrs;

    # Make sure repeating stuff actually makes sense
    if ($event->isRepeating) {
        my $instances = $event->repeatInfo->nextNOccurrences
                              ($event, 1, $dateObj, $prefs);
        $errHash{'repeating w/no instances'} = 1
            unless keys %$instances;
    }

    $errHash{'past event'} = 1
        if (!($ignorePast and $hasAdmin) and
            $dateObj < Date->new and $prefs->NoPastEditing);

    $errHash{'future limit'} = 1
        if $self->_checkFutureLimit ($event, $prefs, $dateObj, $ignoreFuture,
                                     $hasAdmin);

    $errHash{'time conflict'} =
        $self->_checkTimeConflicts ($event, $prefs, $dateObj, $editedEventID,
                                    $ignoreConflicts, $hasAdmin);
    return %errHash;
}

sub _checkFutureLimit {
    my ($self, $event, $prefs, $date, $ignoreFuture, $hasAdmin) = @_;

    return unless $prefs->FutureLimit;
    return if ($prefs->FutureLimit =~ /allow/i);
    return if ($prefs->FutureLimit =~ /warn/i and $ignoreFuture);
    return if ($hasAdmin and $ignoreFuture);       # admin can always do it

    my $futureDate = Date->new;
    my $amount = ($prefs->FutureLimitAmount || 0) + 0;

    my $units = $prefs->FutureLimitUnits;
    ($units =~ /day/i   and $futureDate->addDays   ($amount)) or
    ($units =~ /week/i  and $futureDate->addWeeks  ($amount)) or
    ($units =~ /month/i and $futureDate->addMonths ($amount)) or
    ($units =~ /year/i  and $futureDate->addYears  ($amount));

    return 1 if ($date > $futureDate or
                 ($event->isRepeating and
                  $event->repeatInfo->endDate > $futureDate));
    return;
}

sub _checkTimeConflicts {
    my ($self, $event, $prefs, $date, $editedEventID, $ignore, $hasAdmin) = @_;

    return unless defined $event->hasTime; # if no time, no conflicts!

    my @dateOccurs = ($date);
    my $alreadyFoundRepeaters;

    my @conflicts;

    return unless $prefs->TimeConflicts;
    return if ($prefs->TimeConflicts =~ /allow/i);
    return if ($prefs->TimeConflicts =~ /warn/i and $ignore);
    return if ($hasAdmin and $ignore);       # admin can always do it

    # if we're a repeating event, must check many instances, not just one.
    # check up to 5 years in advance
    if ($event->isRepeating) {
        my $repeatObject = $event->repeatInfo;
        my %occurences;
        my $endDate = $repeatObject->endDate;
        $endDate = $repeatObject->startDate + 365*5
            if ($repeatObject->startDate->deltaDays ($endDate) > 365*5);
        $event->addToDateHash (\%occurences, $repeatObject->startDate,
                              $endDate, $prefs);
        my @dates = map {Date->new ($_)} keys %occurences;
        @dateOccurs = sort {$a <=> $b} @dates;
    }

    foreach my $thisDate (@dateOccurs) {
       if (my @conflicters = $event->conflicts ($self, $thisDate,
                                                $editedEventID)) {
            foreach (@conflicters) {
                push @conflicts, [$_, $thisDate];
            }
        }
    }

    # Return list of conflicting event/date pairs. oy.
    return \@conflicts
        if @conflicts;
    return;
}

1;
