// Next events
function overview_next_events()
{
    global $mybb, $settings, $db, $templates, $theme, $lang, $trow;
    $trow = alt_trow();
    $table_heading = $lang->overview_next_events;
    $column1_heading = $lang->overview_event;
    $column2_heading = $lang->overview_author;
    if($mybb->usergroup['canviewcalendar'] == 1)
    {
        // Permissions
        $query = $db->query("SELECT cid
                             FROM ".TABLE_PREFIX."calendarpermissions
                             WHERE gid = '".intval($mybb->user['usergroup'])."'
                             AND canviewcalendar = '0';");
        $cids = $sep = "";
        if($db->num_rows($query) != 0)
        {
            while($groups = $db->fetch_array($query))
            {
                $cids .= $sep.$groups['cid'];
                $sep = ",";
            }
            $cids = "AND e.cid NOT IN ({$cids})";
        }
        // TODO: Instead of substracting 24 hours, align to the users timezone boundary.
        $today = TIME_NOW - 60*60*24;
        // Decide whether we can include private events or not.
        if(intval($settings['overview_cache']) > 0)
        {
            $private = "e.private='0'";
        }
        else
        {
            $private = "(e.private='0' OR e.uid='".intval($mybb->user['uid'])."')";
        }
        // Fetch data; Raphael: we need more from the db for repeated events
        $query = $db->query("SELECT e.eid, e.name, e.starttime, e.endtime, e.uid, e.repeats, u.username, u.usergroup, u.displaygroup
                             FROM ".TABLE_PREFIX."events e
                             LEFT JOIN ".TABLE_PREFIX."users u ON (e.uid=u.uid)
                             WHERE e.visible = '1' AND {$private} AND (e.starttime > '{$today}' OR e.endtime > '{$today}') {$cids}
                             ORDER BY starttime ASC
                             LIMIT 0,{$settings['overview_max']};");
       
        /* NEW DATE CHECKING MECHANISM by Raphael */
        $event_dates = array();
        while( $events = $db->fetch_array($query) ){
            $repeat_data = unserialize($events['repeats']);
           
            //Check, if repeated event
            if( isset($repeat_data) ){
                //Create timestamps of this events for the next starts
               
                //Get the starttime for the loop, set to today, if in the past
                if( $events['starttime'] < TIME_NOW )
                    $starttime = mktime(0,0,0,date('m'),date('d'),date('Y'));
                else
                    $starttime = strtotime( date("Y-m-d", $events['starttime']) ); //Truncate -> without time
               
                //Optimized date-generation strategy based on repeat-type
                $elements_added = 0; //Control Variable for performance optimized breakpoint
                //"Truncate" starttime; get only d.m.Y without time for easy checking
                $truncated_starttime = strtotime( date("Y-m-d", $events['starttime']) );
                $time_of_starttime = $events['starttime'] - $truncated_starttime;
               
                switch($repeat_data['repeats']){
                   
                    //No Repeat / DB-Relict
                    case "0":
                        array_push($event_dates, array( $events['starttime'] => $events ) );
                        break;
                   
                    //Daily repeated event on x days
                    case "1":
                        if( !isset($repeat_data['days']) )
                            $days = 1;
                        else
                            $days = $repeat_data['days'];
                       
                        //Divider for Rule
                        $divider = $days * (60*60*24);
                        
                        for( $i = $starttime; $i <= $events['endtime']; $i = $i + (60*60*24) ){
                            //Check, if current timestamp meet requirements of repeatment rule
                            //Rule = day_difference is multiple of $days
                            if( ( $i - $truncated_starttime ) % ($divider) == 0){
                               
                                //Add Event to list with time for exact sorting
                                $event_date_time = $i + $time_of_starttime;
                                array_push($event_dates, array( $event_date_time => $events ) );
                                $elements_added++;
                               
                                if( $elements_added == $settings['overview_max']){
                                    break;//break loop, if enough dates 
                                }
                            }
                           
                        }
                        break;
                   
                    //Weekly repeated event on Workdays (Mo-Fr)
                    case "2":
                        
                        //Go through daily
                        for( $i = $starttime; $i <= $events['endtime']; $i = $i + (60*60*24) ){
                            //Check, if current timestamp meet requirements of repeatment rule
                            //Rule = each workday
                            $number_of_day = date("w", $i);
                            if( $number_of_day > 0 && $number_of_day < 6 ){
                                //Add Event to list with time for exact sorting
                                $event_date_time = $i + $time_of_starttime;
                                array_push($event_dates, array( $event_date_time => $events ) );
                                $elements_added++;
                                 
                                if( $elements_added == $settings['overview_max']){
                                    break;//break loop, if enough dates 
                                }
                            }
                             
                        }
                        break;
                   
                    //Weekly repeated event on x weeks per y days
                    case "3":
                        $days = $repeat_data['days']; //Array date("w")
                        $weeks = $repeat_data['weeks'];
                        
                        //Multipler for Rule
                        $multipler = (60*60*24*7);
                        $kw_startevent = date("W", $truncated_starttime);
                        
                        //If event_startime is not in $days, but in future, add it
                        if( !in_array( date("w", $truncated_starttime), $days) && $truncated_starttime >= $starttime ){
                            //Add Event to list with time for exact sorting
                            array_push($event_dates, array( $events['starttime'] => $events ) );
                            $elements_added++;
                        }
                            
                        
                        //First loop: Each week
                        for( $w = $starttime; $w <= $events['endtime']; $w = $w + $multipler ){
                            
                            //If current week is multiple from start_week + weeks
                            if( (date("W", $w) - $kw_startevent) % $weeks != 0 )
                                continue;
                            
                            
                            //Calc weekbeginning
                            $weekday = date("N", $w);
                            if( $weekday != 0 ){
                                $subtractor = ($weekday -1) * 60*60*24;
                            } else
                                $subtractor = 0;
                            
                            if( ($w - $subtractor) < $starttime ){
                                $weekbeginning = $w;
                            } else {
                                $weekbeginning = $w - $subtractor;
                            }
                            
                            $weekend = $w + (7 - $weekday) * 24*60*60;
                            
                            
                            //Second loop: Days
                            for( $i = $weekbeginning; $i <= $weekend; $i = $i + (60*60*24) ){
                                //Check, if current timestamp meet requirements of repeatment rule
                                //Rule = day is in $days
                                if( in_array( date("w", $i) , $days) ){
                                     
                                    //Add Event to list with time for exact sorting
                                    $event_date_time = $i + $time_of_starttime;
                                    array_push($event_dates, array( $event_date_time => $events ) );
                                    $elements_added++;
                                     
                                    if( $elements_added == $settings['overview_max']){
                                        break;//break day loop, if enough dates
                                    }
                                }
                                 
                            }
                            
                            if( $elements_added == $settings['overview_max']){
                                break;//break weekloop, if enough dates
                            }
                            
                        }
                        break;
                   
                    //Monthly repeated , 2 Suboptions
                    case "4":
                        $day = $repeat_data['day'];
                        $month = $repeat_data['months'];
                        $occurance = $repeat_data['occurance'];
                        $weekday = $repeat_data['weekday'];
                        $event_month_start = date("m", $truncated_starttime);
                        $counter = 0;
                        $correction = 0;
                        
                        //Option 1 - Repeat on day x of month y
                        if( isset($repeat_data['day']) ){                        
                            //Go through monthly
                            for( $i = $starttime; $i <= $events['endtime']; $i = mktime(0,0,0,date("m",$i)+$month,1,date("Y",$i)) ){
                                //Check, if current timestamp meet requirements of repeatment rule
                                //Rule = each day x of month y
                                $event_date_time = mktime(0,0,0,date("m",$i) - $correction, $day, date("Y",$i), false) + $time_of_starttime;                      
                                
                                //Correction for bigger starttime in month than first date-day of beginning
                                if( $truncated_starttime > $event_date_time )
                                    $correction = $month - 1;
                                
                                if( $event_date_time >= $starttime && $event_date_time < $events['endtime'] ){
                                    //Add Event to list with time for exact sorting
                                    array_push($event_dates, array( $event_date_time => $events ) );
                                    $elements_added++;
                            
                                    if( $elements_added == $settings['overview_max']){
                                        break;//break loop, if enough dates
                                    }
                                }
                            }
                        } else {
                            //Option 2 - Repeat on x-th y-day of z months
                            //Go through monthly
                            for( $i = $starttime; $i <= $events['endtime']; $i = mktime(0,0,0,date("m",$i)+$month,1,date("Y",$i)) ){
                                //Check, if current timestamp meet requirements of repeatment rule
                                //Rule = each day x of month y
                                
                                //Calc day of month
                                if( $occurance != "last" ){
                                    $first_weekday_of_month = date("N", mktime(0,0,0,date("m",$i) - $correction,1,date("Y",$i)) );
                                    $day_part = 7 - $first_weekday_of_month + $weekday;
                                    if( $day_part >= 7 )
                                        $day_part -= 7;
                                    $day = $day_part + (($occurance - 1) *7) + 1;
                                } else {
                                    //MyBB "last of month" Core Calendar has bugs. (E.G. last of month = first of next month); We do it the right way.
                                    $temp_occurance = 5;
                                    $first_weekday_of_month = date("N", mktime(0,0,0,date("m",$i) - $correction,1,date("Y",$i)) );
                                    $last_weekday_of_month_date = date("d", mktime(0,0,0,date("m",$i)+1 - $correction,0,date("Y",$i)) );
                                    
                                    $day_part = 7 - $first_weekday_of_month + $weekday;
                                    if( $day_part >= 7 )
                                        $day_part -= 7;
                                    
                                    $day = $day_part + (($temp_occurance - 1) *7) + 1;
                                    //If calulated day bigger then last_weekday, reduce occurance to 4
                                    if( $day > $last_weekday_of_month_date)
                                        $day = $day_part + ((4 - 1) *7) + 1;
                                    
                                }
                                
                                $event_date_time = mktime(0,0,0,date("m",$i) - $correction, $day, date("Y",$i), false) + $time_of_starttime;
                                 
                                //Correction for bigger starttime in month than first date-day of beginning
                                if( $truncated_starttime > $event_date_time )
                                    $correction = $month - 1;
                                 
                                if( $event_date_time >= $starttime && $event_date_time < $events['endtime'] ){
                                    //Add Event to list with time for exact sorting
                                    array_push($event_dates, array( $event_date_time => $events ) );
                                    $elements_added++;
                            
                                    if( $elements_added == $settings['overview_max']){
                                        break;//break loop, if enough dates
                                    }
                                }
                            }
                            
                        }
                        break;
                   
                    //Yearly repeated event on x date of y years
                    case "5":
                        $year = $repeat_data['years'];
                        $month = $repeat_data['month'];
                        $day = $repeat_data['day'];
                        $occurance = $repeat_data['occurance'];
                        $weekday = $repeat_data['weekday'];
                        $correction = 0;
                        
                        
                        //Go through yearly
                        //Option 1 repeat on day x of month y all z years
                        if( !isset($repeat_data['occurance']) ){
                            for( $i = $starttime; $i <= $events['endtime']; $i = mktime(0,0,0,date("m",$i),1,date("Y",$i)+$year) ){
                                //Check, if current timestamp meet requirements of repeatment rule
                                //Rule = each day x of month y in year z
                                $event_date_time = mktime(0,0,0,$month, $day, date("Y",$i) - $correction, false) + $time_of_starttime;
                                 
                                //Correction for bigger starttime in month than first date-day of beginning
                                if( $truncated_starttime > $event_date_time )
                                    $correction = $year - 1;
                                 
                                if( $event_date_time >= $starttime && $event_date_time < $events['endtime'] ){
                                    //Add Event to list with time for exact sorting
                                    array_push($event_dates, array( $event_date_time => $events ) );
                                    $elements_added++;
                            
                                    if( $elements_added == $settings['overview_max']){
                                        break;//break loop, if enough dates
                                    }
                                }
                            }
                        } else {
                            //Option 2: repeat on a-th occurance of b-day each c-month every d years
                            //Go through yearly
                            for( $i = $starttime; $i <= $events['endtime']; $i = mktime(0,0,0,$month,1,date("Y",$i)+$year) ){
                                //Check, if current timestamp meet requirements of repeatment rule
                                //Rule
                                 
                                //Calc day of month
                                if( $occurance != "last" ){
                                    $first_weekday_of_month = date("N", mktime(0,0,0,$month,1,date("Y",$i)- $correction) );
                                    $day_part = 7 - $first_weekday_of_month + $weekday;
                                    if( $day_part >= 7 )
                                        $day_part -= 7;
                                    $day = $day_part + (($occurance - 1) *7) + 1;
                                } else {
                                    //MyBB "last of month" Core Calendar has bugs. (E.G. last of month = first of next month); We do it the right way.
                                    $temp_occurance = 5;
                                    $first_weekday_of_month = date("N", mktime(0,0,0,$month,1,date("Y",$i)  - $correction) );
                                    $last_weekday_of_month_date = date("d", mktime(0,0,0,$month+1,0,date("Y",$i) - $correction) );
                            
                                    $day_part = 7 - $first_weekday_of_month + $weekday;
                                    if( $day_part >= 7 )
                                        $day_part -= 7;
                            
                                    $day = $day_part + (($temp_occurance - 1) *7) + 1;
                                    //If calulated day bigger then last_weekday, reduce occurance to 4
                                    if( $day > $last_weekday_of_month_date)
                                        $day = $day_part + ((4 - 1) *7) + 1;
                            
                                }
                                 
                                $event_date_time = mktime(0,0,0,date("m",$i), $day, date("Y",$i) - $correction, false) + $time_of_starttime;
                            
                                //Correction for bigger starttime in month than first date-day of beginning
                                if( $truncated_starttime > $event_date_time )
                                    $correction = $year - 1;
                            
                                if( $event_date_time >= $starttime && $event_date_time < $events['endtime'] ){
                                    //Add Event to list with time for exact sorting
                                    array_push($event_dates, array( $event_date_time => $events ) );
                                    $elements_added++;
                            
                                    if( $elements_added == $settings['overview_max']){
                                        break;//break loop, if enough dates
                                    }
                                }
                            }
                            
                        }
                        break;
                }
               
               
            } else {
                //Non repeated Events
                array_push($event_dates, array( $events['starttime'] => $events ) );        
            }
           
        }
       
        //Sort by time asc
        usort($event_dates, "sortArrayByDate");
       
        // Print data
        foreach( $event_dates as $key => $event ){
            
            if($key == $settings['overview_max'])
                break; //Display only as much as needed
            $starttime = key($event);
            $events = $event[$starttime];
           
            $events['name'] = my_date($settings['dateformat'], $starttime).": ".$events['name'];
            $val1 = overview_parsesubject($events['name'], 0, 0, 0, 0, $events['eid'], 0);
            $val2 = overview_parseuser($events['uid'], $events['username'], $events['usergroup'], $events['displaygroup']);
            eval("\$table_content .= \"".$templates->get("overview_2_columns_row")."\";");
           
        }
    }
    eval("\$output = \"".$templates->get("overview_2_columns")."\";");
    return $output;
}
//Helper for Events
function sortArrayByDate( $a, $b ){
   
    if( key($a) < key($b) )
        return -1;
    elseif ( key($a) == key($b) )
        return 0;
    elseif ( key($a) > key($b) )
        return 1;
   
}