/**
 * get all repeating events/bookings?
 * TODO: change function name, in a distinct view bookings are events too
 * use constants for repeat ids (better readable)
 *
 * Maybe rewrite function:
 * look at php date objects like DatePeriod, DateInterval:
 * $period = new DatePeriod($start, $interval, $recurrences);
 * foreach ($period as $date) {
 *     echo $date->format('Y-m-d')."\n";
 * }
 * you can use dates like "first tuesday of july 2008", "next Monday 2012-04-01"
 * http://de1.php.net/manual/de/datetime.formats.relative.php
 *
 * @param object $r
 * @param int $_from; default: -1, days to add to fromDate
 * @param int $_to; default: 1, days to add to fromDate
 * @return
 */
function getAllDatesWithRepeats($r, $_from = -1, $_to = 1, $fromDate = null)
{
    // $dates later will contain all date occurence.
    $dates = array();
    // $max prevents an endless loop on erors
    $max = 999;
    if ($fromDate == null) {
        $fromDate = new DateTime();
    } else {
        $fromDate = new DateTime($fromDate->format('d.m.Y'));
    }
    $to = new DateTime($fromDate->format('d.m.Y H:i'));
    $fromDate->modify("+{$_from} days");
    $to->modify("+{$_to} days");
    $r->startdate = new DateTime($r->startdate instanceof DateTime ? $r->startdate->format('d.m.Y H:i') : $r->startdate);
    $d = clone $r->startdate;
    $r->enddate = new DateTime($r->enddate instanceof DateTime ? $r->enddate->format('d.m.Y H:i') : $r->enddate);
    $e = clone $r->enddate;
    if (!isset($r->repeat_until)) {
        $r->repeat_until = $d->format("d.m.Y H:i");
    }
    $repeat_until = new DateTime($r->repeat_until);
    $repeat_until = $repeat_until->modify('+1 day');
    // include given day!
    if ($to < $repeat_until) {
        $repeat_until = $to;
    }
    if (!empty($r->additions)) {
        $additions = $r->additions;
    } else {
        $additions = array();
    }
    // Add addition date for Start date, so we only need one foreach loop
    $my = new stdClass();
    $my->add_date = $d->format('d.m.Y H:i');
    $my->with_repeat_yn = 1;
    $additions[0] = $my;
    // array_unshift($additions, $my);
    //  print_r($additions);
    foreach ($additions as $key => $add_unkownFormat) {
        $add = (object) $add_unkownFormat;
        // Parameter can be Arrays from HTTP Input or Objects from DB
        $d = new DateTime(substr($add->add_date, 0, 10) . " " . $d->format('H:i:s'));
        $e = new DateTime(substr($add->add_date, 0, 10) . " " . $e->format('H:i:s'));
        // Mark exception as used, so datesInConflict() will be called only for new exceptions to save time!
        if (!empty($r->exceptions)) {
            foreach ($r->exceptions as $key => $exc) {
                if (is_array($r->exceptions[$key])) {
                    $r->exceptions[$key] = (object) $r->exceptions[$key];
                }
                $r->exceptions[$key]->used = false;
            }
        }
        do {
            $exception = false;
            if (!empty($r->exceptions)) {
                foreach ($r->exceptions as $exc) {
                    // if exception is not used proof conflict with exception date
                    if (!$exception && !$exc->used && datesInConflict(new DateTime($exc->except_date_start), new DateTime($exc->except_date_end), $d, $e)) {
                        $exception = true;
                        $exc->used = true;
                    }
                }
            }
            if (!$exception) {
                //why two ifs?
                if ($d <= $fromDate && $e >= $fromDate || $e >= $fromDate && $e <= $to) {
                    $dates[] = new DateTime($d->format('Y-m-d H:i:s'));
                }
            }
            // f.e. each second week is 7*2 => 14 days
            if ($r->repeat_id == 1 || $r->repeat_id == 7) {
                $repeat = $r->repeat_id * $r->repeat_frequence;
                $d->modify("+{$repeat} days");
                $e->modify("+{$repeat} days");
            } else {
                if ($r->repeat_id == 31) {
                    $counter = 0;
                    do {
                        $tester = new DateTime($d->format('Y-m-d H:i:s'));
                        $modify = "+ " . ($counter + 1 * $r->repeat_frequence) . " month";
                        $tester->modify($modify);
                        if ($tester->format('d') == $d->format('d')) {
                            $d->modify($modify);
                            $e->modify($modify);
                            $counter = 999;
                            //TODO: why not using break here?
                        }
                        $counter = $counter + 1;
                    } while ($counter < 99);
                } else {
                    if ($r->repeat_id == 32) {
                        // first find last weekday
                        if ($r->repeat_option_id == 6) {
                            // go some days back, so we dont jump into the next month and therefor miss one month
                            $d->modify("- 5 days");
                            $e->modify("- 5 days");
                            // add months
                            $d->modify("+ " . (1 + 1 * $r->repeat_frequence) . " month");
                            // what means 1 + 1 * x?
                            $e->modify("+ " . (1 + 1 * $r->repeat_frequence) . " month");
                            // first go back to first day of month
                            //TODO: use sort of $d->setDate(2014, 12, 1) and calculate value for $e?;
                            while ($d->format('d') > 1) {
                                $d->modify("-1 day");
                                $e->modify("-1 day");
                            }
                            $d->modify("-1 day");
                            $e->modify("-1 day");
                            // then search for same weekday
                            while ($d->format('N') != $r->startdate->format('N')) {
                                $d->modify("-1 day");
                                $e->modify("-1 day");
                            }
                        } else {
                            $counter = 0;
                            // add months
                            $d->setDate($d->format('Y'), $d->format('m') + 1 * $r->repeat_frequence, 0);
                            $e->setDate($e->format('Y'), $e->format('m') + 1 * $r->repeat_frequence, 0);
                            while ($counter < $r->repeat_option_id) {
                                $m = $d->format("m");
                                $d->modify("+1 day");
                                $e->modify("+1 day");
                                // test if jumped in next month, then the month has to few days and the event is dropped, f.e. on 5th
                                // weekday/month
                                if ($d->format("m") != $m) {
                                    $counter = 0;
                                }
                                if ($d->format("N") == $r->startdate->format("N")) {
                                    $counter = $counter + 1;
                                }
                            }
                        }
                    } else {
                        if ($r->repeat_id == 365) {
                            $counter = 0;
                            $d->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " year");
                            $e->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " year");
                        }
                    }
                }
            }
            $max = $max - 1;
            if ($max == 0) {
                addErrorMessage("Zu viele Wiederholungen in getAllDatesWithRepeats! [{$r->id}]");
                return false;
            }
        } while ($d < $repeat_until && $add->with_repeat_yn == 1 && isset($r->repeat_id) && $r->repeat_id > 0 && isset($r->repeat_frequence) && $r->repeat_frequence > 0);
    }
    return $dates;
}
function getAllDatesWithRepeats($r, $_von = -1, $_bis = 1)
{
    // $dates later will contain all date occurence.
    $dates = array();
    // $max prevents an endless loop on erors
    $max = 999;
    $from = new DateTime();
    $from->modify("+{$_von} days");
    $to = new DateTime();
    $to->modify("+{$_bis} days");
    $d = new DateTime($r->startdate->format('d.m.Y H:i'));
    $e = new DateTime($r->enddate->format('d.m.Y H:i'));
    $repeat_until = new DateTime($r->repeat_until);
    $repeat_until = $repeat_until->modify('+1 day');
    // Da der Tag ja mit gelten soll!
    if ($to < $repeat_until) {
        $repeat_until = $to;
    }
    if (isset($r->additions)) {
        $additions = $r->additions;
    } else {
        $additions = array();
    }
    $my = new stdClass();
    $my->add_date = $d->format('d.m.Y H:i');
    $my->with_repeat_yn = 1;
    $additions[0] = $my;
    //array_unshift($additions, $my);
    foreach ($additions as $key => $add) {
        $d = new DateTime(substr($add->add_date, 0, 10) . " " . $d->format('H:i:s'));
        $e = new DateTime(substr($add->add_date, 0, 10) . " " . $e->format('H:i:s'));
        // Mark exception as used, so the "datesInConflict" will be called only for fresh exceptions to save time!
        if (isset($r->exceptions)) {
            foreach ($r->exceptions as $exc) {
                $exc->used = false;
            }
        }
        do {
            $exception = false;
            if (isset($r->exceptions)) {
                foreach ($r->exceptions as $exc) {
                    // if exception is not used then proof conflict with exception date
                    if (!$exception && !$exc->used && datesInConflict(new DateTime($exc->except_date_start), new DateTime($exc->except_date_end), $d, $e)) {
                        $exception = true;
                        $exc->used = true;
                    }
                }
            }
            if (!$exception) {
                if ($d <= $from && $e >= $from || $e >= $from && $e <= $to) {
                    $dates[] = new DateTime($d->format('Y-m-d H:i:s'));
                }
            }
            if ($r->repeat_id == 1 || $r->repeat_id == 7) {
                $repeat = $r->repeat_id * $r->repeat_frequence;
                // f.e. each second week is 7*2 => 14 days
                $d->modify("+{$repeat} days");
                $e->modify("+{$repeat} days");
            } else {
                if ($r->repeat_id == 31) {
                    $counter = 0;
                    do {
                        $tester = new DateTime($d->format('Y-m-d H:i:s'));
                        $tester->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " month");
                        if ($tester->format('d') == $d->format('d')) {
                            $d->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " month");
                            $e->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " month");
                            $counter = 999;
                        }
                        $counter = $counter + 1;
                    } while ($counter < 99);
                } else {
                    if ($r->repeat_id == 32) {
                        // first find last weekday
                        if ($r->repeat_option_id == 6) {
                            // go some days back, so we dont jump into the next month and therefor miss one month
                            $d->modify("- 5 days");
                            $e->modify("- 5 days");
                            // add months
                            $d->modify("+ " . (1 + 1 * $r->repeat_frequence) . " month");
                            $e->modify("+ " . (1 + 1 * $r->repeat_frequence) . " month");
                            // first go back to first day of month
                            while ($d->format('d') > 1) {
                                $d->modify("-1 day");
                                $e->modify("-1 day");
                            }
                            $d->modify("-1 day");
                            $e->modify("-1 day");
                            // then search for same weekday
                            while ($d->format('N') != $r->startdate->format('N')) {
                                $d->modify("-1 day");
                                $e->modify("-1 day");
                            }
                        } else {
                            $counter = 0;
                            // add months
                            $d->setDate($d->format('Y'), $d->format('m') + 1 * $r->repeat_frequence, 0);
                            $e->setDate($e->format('Y'), $e->format('m') + 1 * $r->repeat_frequence, 0);
                            while ($counter < $r->repeat_option_id) {
                                $m = $d->format("m");
                                $d->modify("+1 day");
                                $e->modify("+1 day");
                                // test if jumped in next month, then the month has to few days and the event is dropped, f.e. on 5th weekday/month
                                if ($d->format("m") != $m) {
                                    $counter = 0;
                                }
                                if ($d->format("N") == $r->startdate->format("N")) {
                                    $counter = $counter + 1;
                                }
                            }
                        }
                    } else {
                        if ($r->repeat_id == 365) {
                            $counter = 0;
                            $d->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " year");
                            $e->modify("+ " . ($counter + 1 * $r->repeat_frequence) . " year");
                        }
                    }
                }
            }
            $max = $max - 1;
            if ($max == 0) {
                addErrorMessage("Zu viele Wiederholungen in getAllDatesWithRepeats! [{$r->id}]");
                return false;
            }
        } while ($d < $repeat_until && $add->with_repeat_yn == 1 && isset($r->repeat_id) && $r->repeat_id > 0 && isset($r->repeat_frequence) && $r->repeat_frequence > 0);
    }
    return $dates;
}