/**
  * Format an event to comply with the fullcalendar format
  * @param Event $event
  */
 public static function format_event_for_fullcalendar($event)
 {
     $bgColor = '#999';
     //default
     $textColor = '#FFF';
     //default
     $borderColor = '#555';
     $arr = array('id' => $event->ID, 'title' => $event->Title, 'start' => self::format_datetime_for_fullcalendar($event->StartDateTime), 'end' => self::format_datetime_for_fullcalendar($event->EndDateTime), 'allDay' => $event->isAllDay(), 'className' => $event->ClassName, 'backgroundColor' => $bgColor, 'textColor' => '#FFFFFF', 'borderColor' => $borderColor);
     return $arr;
 }
function query_events($user, $want_repeated, $date_filter, $cat_id = '', $is_task = false)
{
    global $db_connection_info, $jumpdate, $layers, $login, $max_until, $PUBLIC_ACCESS_DEFAULT_VISIBLE, $result, $thismonth, $thisyear;
    global $OVERRIDE_PUBLIC, $OVERRIDE_PUBLIC_TEXT;
    // New multiple categories requires some checking to see if this cat_id is
    // valid for this cal_id. It could be done with nested SQL,
    // but that may not work for all databases. This might be quicker also.
    $catlist = $cloneRepeats = $layers_byuser = $result = array();
    $sql = 'SELECT DISTINCT( cal_id ) FROM webcal_entry_categories ';
    // None was selected...return only events without categories.
    if ($cat_id == -1) {
        $rows = dbi_get_cached_rows($sql, array());
    } elseif (!empty($cat_id)) {
        $cat_array = explode(',', $cat_id);
        $placeholders = '';
        for ($p_i = 0, $cnt = count($cat_array); $p_i < $cnt; $p_i++) {
            $placeholders .= $p_i == 0 ? '?' : ', ?';
        }
        $rows = dbi_get_cached_rows($sql . 'WHERE cat_id IN ( ' . $placeholders . ' )', $cat_array);
    }
    if (!empty($cat_id)) {
        // $rows = dbi_get_cached_rows ( $sql, array ( $cat_id ) );
        if ($rows) {
            for ($i = 0, $cnt = count($rows); $i < $cnt; $i++) {
                $row = $rows[$i];
                $catlist[$i] = $row[0];
            }
        }
    }
    $catlistcnt = count($catlist);
    $query_params = array();
    $sql = 'SELECT we.cal_name, we.cal_description, we.cal_date, we.cal_time,
    we.cal_id, we.cal_ext_for_id, we.cal_priority, we.cal_access,
    we.cal_duration, weu.cal_status, we.cal_create_by, weu.cal_login,
    we.cal_type, we.cal_location, we.cal_url, we.cal_due_date, we.cal_due_time,
    weu.cal_percent, we.cal_mod_date, we.cal_mod_time ' . ($want_repeated ? ', wer.cal_type, wer.cal_end, wer.cal_frequency,
      wer.cal_days, wer.cal_bymonth, wer.cal_bymonthday,
      wer.cal_byday, wer.cal_bysetpos, wer.cal_byweekno,
      wer.cal_byyearday, wer.cal_wkst, wer.cal_count, wer.cal_endtime
      FROM webcal_entry we, webcal_entry_repeats wer, webcal_entry_user weu
      WHERE we.cal_id = wer.cal_id AND ' : 'FROM webcal_entry we, webcal_entry_user weu WHERE ') . 'we.cal_id = weu.cal_id AND weu.cal_status IN ( \'A\',\'W\' ) ';
    if ($catlistcnt > 0) {
        $placeholders = '';
        for ($p_i = 0; $p_i < $catlistcnt; $p_i++) {
            $placeholders .= $p_i == 0 ? '?' : ', ?';
            $query_params[] = $catlist[$p_i];
        }
        if ($cat_id > 0) {
            $sql .= 'AND we.cal_id IN ( ' . $placeholders . ' ) ';
        } elseif ($cat_id == -1) {
            // Eliminate events with categories.
            $sql .= 'AND we.cal_id NOT IN ( ' . $placeholders . ' ) ';
        }
    } else {
        if (!empty($cat_id)) {
            // Force no rows to be returned. No matching entries in category.
            $sql .= 'AND 1 = 0 ';
        }
    }
    $sql .= 'AND we.cal_type IN ' . ($is_task == false ? '( \'E\',\'M\' ) ' : '( \'N\',\'T\' ) AND ( we.cal_completed IS NULL ) ') . (strlen($user) > 0 ? 'AND ( weu.cal_login = ? ' : '');
    $query_params[] = $user;
    if ($user == $login && strlen($user) > 0 && $layers) {
        foreach ($layers as $layer) {
            $layeruser = $layer['cal_layeruser'];
            $sql .= 'OR weu.cal_login = ? ';
            $query_params[] = $layeruser;
            // While we are parsing the whole layers array, build ourselves
            // a new array that will help when we have to check for dups.
            $layers_byuser[$layeruser] = $layer['cal_dups'];
        }
    }
    $rows = dbi_get_cached_rows($sql . ($user == $login && strlen($user) && $PUBLIC_ACCESS_DEFAULT_VISIBLE == 'Y' ? 'OR weu.cal_login = \'__public__\' ' : '') . (strlen($user) > 0 ? ') ' : '') . $date_filter . (!$is_task ? ' ORDER BY we.cal_time, we.cal_name' : ''), $query_params);
    if ($rows) {
        $i = 0;
        $checkdup_id = $first_i_this_id = -1;
        for ($ii = 0, $cnt = count($rows); $ii < $cnt; $ii++) {
            $row = $rows[$ii];
            if ($row[9] == 'D' || $row[9] == 'R') {
                continue;
            }
            // Don't show deleted/rejected ones.
            // Get primary category for this event, used for icon and color.
            $categories = get_categories_by_id($row[4], $user);
            $cat_keys = array_keys($categories);
            $primary_cat = empty($cat_keys[0]) ? '' : $cat_keys[0];
            if ($login == '__public__' && !empty($OVERRIDE_PUBLIC) && $OVERRIDE_PUBLIC == 'Y') {
                $evt_name = $OVERRIDE_PUBLIC_TEXT;
                $evt_descr = $OVERRIDE_PUBLIC_TEXT;
            } else {
                $evt_name = $row[0];
                $evt_descr = $row[1];
            }
            if ($want_repeated && !empty($row[20])) {
                // row[20] = cal_type
                $item = new RepeatingEvent($evt_name, $evt_descr, $row[2], $row[3], $row[4], $row[5], $row[6], $row[7], $row[8], $row[9], $row[10], $primary_cat, $row[11], $row[12], $row[13], $row[14], $row[15], $row[16], $row[17], $row[18], $row[19], $row[20], $row[21], $row[22], $row[23], $row[24], $row[25], $row[26], $row[27], $row[28], $row[29], $row[30], $row[31], $row[32], array(), array(), array());
            } else {
                $item = new Event($evt_name, $evt_descr, $row[2], $row[3], $row[4], $row[5], $row[6], $row[7], $row[8], $row[9], $row[10], $primary_cat, $row[11], $row[12], $row[13], $row[14], $row[15], $row[16], $row[17], $row[18], $row[19]);
            }
            if ($item->getID() != $checkdup_id) {
                $checkdup_id = $item->getID();
                $first_i_this_id = $i;
            }
            if ($item->getLogin() == $user) {
                // Insert this one before all other ones with this ID.
                array_splice($result, $first_i_this_id, 0, array($item));
                $i++;
                if ($first_i_this_id + 1 < $i) {
                    // There's another one with the same ID as the one we inserted.
                    // Check for dup and if so, delete it.
                    $other_item = $result[$first_i_this_id + 1];
                    if (!empty($layers_byuser[$other_item->getLogin()]) && $layers_byuser[$other_item->getLogin()] == 'N') {
                        // NOTE:  array_splice requires PHP4
                        array_splice($result, $first_i_this_id + 1, 1);
                        $i--;
                    }
                }
            } else {
                if ($i == $first_i_this_id || !empty($layers_byuser[$item->getLogin()]) && $layers_byuser[$item->getLogin()] != 'N') {
                    // This item either is the first one with its ID, or allows dups.
                    // Add it to the end of the array.
                    $result[$i++] = $item;
                }
            }
            // Does event go past midnight?
            if (date('Ymd', $item->getDateTimeTS()) != date('Ymd', $item->getEndDateTimeTS()) && !$item->isAllDay() && $item->getCalTypeName() == 'event') {
                getOverLap($item, $i, true);
                $i = count($result);
            }
        }
    }
    if ($want_repeated) {
        // Now load event exceptions/inclusions and store as array.
        // TODO:  Allow passing this max_until as param in case we create
        // a custom report that shows N years of events.
        if (empty($max_until)) {
            $max_until = mktime(0, 0, 0, $thismonth + 2, 1, $thisyear);
        }
        for ($i = 0, $resultcnt = count($result); $i < $resultcnt; $i++) {
            if ($result[$i]->getID() != '') {
                $rows = dbi_get_cached_rows('SELECT cal_date, cal_exdate
          FROM webcal_entry_repeats_not
          WHERE cal_id = ?', array($result[$i]->getID()));
                for ($ii = 0, $rowcnt = count($rows); $ii < $rowcnt; $ii++) {
                    $row = $rows[$ii];
                    // If this is not a clone, add exception date.
                    if (!$result[$i]->getClone()) {
                        $except_date = $row[0];
                    }
                    if ($row[1] == 1) {
                        $result[$i]->addRepeatException($except_date, $result[$i]->getID());
                    } else {
                        $result[$i]->addRepeatInclusion($except_date);
                    }
                }
                // Get all dates for this event.
                // If clone, we'll get the dates from parent later.
                if (!$result[$i]->getClone()) {
                    $until = $result[$i]->getRepeatEndDateTimeTS() ? $result[$i]->getRepeatEndDateTimeTS() : $max_until;
                    // Try to minimize the repeat search by shortening
                    // until if BySetPos is not used.
                    if (!$result[$i]->getRepeatBySetPos() && $until > $max_until) {
                        $until = $max_until;
                    }
                    $rpt_count = 999;
                    //Some BIG number.
                    // End date... for year view and some reports we need whole year...
                    // So, let's do up to 365 days after current month.
                    // TODO:  Add this end time as a parameter in case someone creates
                    // a custom report that asks for N years of events.
                    // $jump = mktime ( 0, 0, 0, $thismonth -1, 1, $thisyear);
                    if ($result[$i]->getRepeatCount()) {
                        $rpt_count = $result[$i]->getRepeatCount() - 1;
                    }
                    $date = $result[$i]->getDateTimeTS();
                    if ($result[$i]->isAllDay() || $result[$i]->isUntimed()) {
                        $date += 43200;
                    }
                    //A simple hack to prevent DST problems.
                    // TODO get this to work
                    // C heck if this event id has been cached.
                    // $file = '';
                    // if ( ! empty ( $db_connection_info['cachedir'] ) ){
                    // $hash = md5 ( $result[$i]->getId () . $until . $jump );
                    // $file = $db_connection_info['cachedir'] . '/' . $hash . '.dat';
                    // }
                    // if ( file_exists ( $file ) ) {
                    // $dates =  unserialize ( file_get_contents ( $file ) );
                    // } else {
                    $dates = get_all_dates($date, $result[$i]->getRepeatType(), $result[$i]->getRepeatFrequency(), array($result[$i]->getRepeatByMonth(), $result[$i]->getRepeatByWeekNo(), $result[$i]->getRepeatByYearDay(), $result[$i]->getRepeatByMonthDay(), $result[$i]->getRepeatByDay(), $result[$i]->getRepeatBySetPos()), $rpt_count, $until, $result[$i]->getRepeatWkst(), $result[$i]->getRepeatExceptions(), $result[$i]->getRepeatInclusions(), $jumpdate);
                    $result[$i]->addRepeatAllDates($dates);
                    // Serialize and save in cache for later use.
                    // if ( ! empty ( $db_connection_info['cachedir'] ) ) {
                    // $fd = @fopen ( $file, 'w+b', false );
                    // if ( empty ( $fd ) ) {
                    // dbi_fatal_error ( "Cache error: could not write file $file" );
                    // }
                    // fwrite ( $fd, serialize ( $dates ) );
                    // fclose ( $fd );
                    // chmod ( $file, 0666 );
                    // }
                    // }
                } else {
                    // Process clones if any.
                    if (count($result[$i - 1]->getRepeatAllDates()) > 0) {
                        $parentRepeats = $result[$i - 1]->getRepeatAllDates();
                        $cloneRepeats = array();
                        for ($j = 0, $parentRepeatscnt = count($parentRepeats); $j < $parentRepeatscnt; $j++) {
                            $cloneRepeats[] = gmdate('Ymd', date_to_epoch($parentRepeats[$j]) + ONE_DAY);
                        }
                        $result[$i]->addRepeatAllDates($cloneRepeats);
                    }
                }
            }
        }
    }
    return $result;
}