function timetable_add_events_custom_box()
{
    $timetable_events_settings = timetable_events_settings();
    add_meta_box("event_hours", __("Event hours", 'timetable'), "timetable_inner_events_custom_box_side", $timetable_events_settings["slug"], "normal");
    add_meta_box("event_config", __("Options", 'timetable'), "timetable_inner_events_custom_box_main", $timetable_events_settings["slug"], "normal", "high");
}
/**
 * Generates the Timetable HTML code
 * 
 * @param type $atts - timetable options
 * @param type $event - events that will be displayed
 * @return string - Timetable HTML code
 */
function tt_get_timetable($atts, $event = null)
{
    $timetable_events_settings = timetable_events_settings();
    extract(shortcode_atts(array("events_page" => "", "measure" => 1, "filter_style" => "dropdown_list", "filter_label" => "All Events", "hour_category" => "", "columns" => "", "time_format" => "H.i", "hide_hours_column" => 0, "show_end_hour" => 0, "event_layout" => 1, "box_bg_color" => "00A27C", "box_hover_bg_color" => "1F736A", "box_txt_color" => "FFFFFF", "box_hover_txt_color" => "FFFFFF", "box_hours_txt_color" => "FFFFFF", "box_hours_hover_txt_color" => "FFFFFF", "row1_color" => "F0F0F0", "row2_color" => "", "hide_empty" => 0, "disable_event_url" => 0, "text_align" => "center", "row_height" => 31, "id" => "", "responsive" => 1, "event_description_responsive" => "none", "collapse_event_hours_responsive" => 0), $atts));
    //remove leading '#' hash character
    $color_params = array('box_bg_color', 'box_hover_bg_color', 'box_txt_color', 'box_hover_txt_color', 'box_hours_txt_color', 'box_hours_hover_txt_color', 'filter_color', 'row1_color', 'row2_color');
    foreach ($color_params as $color_param) {
        if (!empty(${$color_param})) {
            ${$color_param} = ltrim(${$color_param}, "#");
        }
    }
    $measure = (double) $measure;
    global $wpdb;
    if ($columns != "") {
        $weekdays_explode = explode(",", $columns);
        $weekdays_in_query = "";
        foreach ($weekdays_explode as $weekday_explode) {
            $weekdays_in_query .= "'" . tt_strtolower_urlencode($weekday_explode) . "'" . ($weekday_explode != end($weekdays_explode) ? "," : "");
        }
    }
    if ($hour_category != null && $hour_category != "-") {
        $hour_category = array_values(array_diff(array_filter(array_map('trim', explode(",", $hour_category))), array("-")));
    }
    $output = "";
    $query = "SELECT TIME_FORMAT(t1.start, '%H.%i') AS start, TIME_FORMAT(t1.end, '%H.%i') AS end, t1.tooltip AS tooltip, t1.before_hour_text AS before_hour_text, t1.after_hour_text AS after_hour_text, t2.ID AS event_id, t2.post_title AS event_title, t2.post_name AS post_name, t3.post_title, t3.menu_order FROM " . $wpdb->prefix . "event_hours AS t1 \r\n\t\t\tLEFT JOIN {$wpdb->posts} AS t2 ON t1.event_id=t2.ID \r\n\t\t\tLEFT JOIN {$wpdb->posts} AS t3 ON t1.weekday_id=t3.ID \r\n\t\t\tWHERE \r\n\t\t\tt2.post_type='" . $timetable_events_settings['slug'] . "'\r\n\t\t\tAND t2.post_status='publish'";
    if (is_array($event) && count($event)) {
        $query .= "\r\n\t\t\tAND t2.post_name IN('" . implode("','", array_map("tt_strtolower_urlencode", $event)) . "')";
    } else {
        if ($event != null) {
            $query .= "\r\n\t\t\tAND t2.post_name='" . tt_strtolower_urlencode($event) . "'";
        }
    }
    if ($hour_category != null && $hour_category != "-") {
        $query .= "\r\n\t\t\tAND t1.category IN('" . join("','", $hour_category) . "')";
    }
    $query .= "\r\n\t\t\tAND \r\n\t\t\tt3.post_type='timetable_weekdays'\r\n\t\t\tAND\r\n\t\t\tt3.post_status='publish'";
    if (isset($weekdays_in_query) && $weekdays_in_query != "") {
        $query .= " AND t3.post_name IN(" . $weekdays_in_query . ")";
    }
    //$query .= " ORDER BY FIELD(t3.menu_order,2,3,4,5,6,7,1), t1.start, t1.end";
    $query .= " ORDER BY t3.menu_order, t1.start, t1.end, t2.post_name";
    $event_hours = $wpdb->get_results($query);
    if (!count($event_hours)) {
        return __('No event hours available!', 'timetable');
    }
    $event_hours_tt = array();
    foreach ($event_hours as $event_hour) {
        //$event_hours_tt[($event_hour->menu_order>1 ? $event_hour->menu_order-1 : 7)][] = array(
        $event_hours_tt[$event_hour->menu_order][] = array("start" => $event_hour->start, "end" => $event_hour->end, "tooltip" => $event_hour->tooltip, "before_hour_text" => $event_hour->before_hour_text, "after_hour_text" => $event_hour->after_hour_text, "tooltip" => $event_hour->tooltip, "id" => $event_hour->event_id, "title" => $event_hour->event_title, "name" => $event_hour->post_name);
    }
    $output .= '<table class="tt_timetable">
				<thead>
					<tr class="row_gray"' . ($row1_color != "" ? ' style="background-color: ' . ($row1_color != "transparent" ? '#' : '') . $row1_color . ' !important;"' : '') . '>';
    if (!(int) $hide_hours_column) {
        $output .= '<th></th>';
    }
    //get weekdays
    $query = "SELECT post_title, menu_order FROM {$wpdb->posts}\r\n\t\t\tWHERE \r\n\t\t\tpost_type='timetable_weekdays'\r\n\t\t\tAND post_status='publish'";
    if (isset($weekdays_in_query) && $weekdays_in_query != "") {
        $query .= " AND post_name IN(" . $weekdays_in_query . ")";
    }
    //$query .= " ORDER BY FIELD(menu_order,2,3,4,5,6,7,1)";
    $query .= " ORDER BY menu_order";
    $weekdays = $wpdb->get_results($query);
    foreach ($weekdays as $weekday) {
        $output .= '	<th>' . $weekday->post_title . '</th>';
    }
    $output .= '	</tr>
				</thead>
				<tbody>';
    //get min anx max hour
    $query = "SELECT min(TIME_FORMAT(t1.start, '%H.%i')) AS min, max(REPLACE(TIME_FORMAT(t1.end, '%H.%i'), '00.00', '24.00')) AS max FROM " . $wpdb->prefix . "event_hours AS t1\r\n\t\t\tLEFT JOIN {$wpdb->posts} AS t2 ON t1.event_id=t2.ID \r\n\t\t\tLEFT JOIN {$wpdb->posts} AS t3 ON t1.weekday_id=t3.ID \r\n\t\t\tWHERE \r\n\t\t\tt2.post_type='" . $timetable_events_settings['slug'] . "'\r\n\t\t\tAND t2.post_status='publish'";
    if (is_array($event) && count($event)) {
        $query .= "\r\n\t\t\tAND t2.post_name IN('" . implode("','", array_map("tt_strtolower_urlencode", $event)) . "')";
    } else {
        if ($event != null) {
            $query .= "\r\n\t\t\tAND t2.post_name='" . tt_strtolower_urlencode($event) . "'";
        }
    }
    if ($hour_category != null && $hour_category != "-") {
        $query .= "\r\n\t\t\tAND t1.category IN('" . join("','", $hour_category) . "')";
    }
    $query .= "\r\n\t\t\tAND \r\n\t\t\tt3.post_type='timetable_weekdays'\r\n\t\t\tAND\r\n\t\t\tt3.post_status='publish'";
    if (isset($weekdays_in_query) && $weekdays_in_query != "") {
        $query .= " AND t3.post_name IN(" . $weekdays_in_query . ")";
    }
    $hours = $wpdb->get_row($query);
    $drop_columns = array();
    $l = 0;
    $increment = 1;
    $hours_min = (int) $hours->min;
    if ((int) $measure == 1) {
        $max_explode = explode(".", $hours->max);
        $max_hour = (int) $hours->max + (!empty($max_explode[1]) && (int) $max_explode[1] > 0 ? 1 : 0);
    } else {
        $max_hour = $hours->max;
        $max_hour = to_decimal_time($max_hour);
        $max_hour = get_next_row_hour($max_hour, $measure);
        $increment = (double) $measure;
        $hours_min = to_decimal_time(roundMin($hours->min, $measure, to_decimal_time($hours_min)));
    }
    for ($i = $hours_min; $i < $max_hour; $i = $i + $increment) {
        if ((int) $measure == 1) {
            $start = str_pad($i, 2, '0', STR_PAD_LEFT) . '.00';
            $end = str_replace("24", "00", str_pad($i + 1, 2, '0', STR_PAD_LEFT)) . '.00';
        } else {
            $i = number_format($i, 2);
            $hourIExplode = explode(".", $i);
            $hourI = $hourIExplode[0] . "." . ((int) $hourIExplode[1] > 0 ? (int) $hourIExplode[1] * 60 / 100 : "00");
            $start = number_format($i, 2);
            $end = number_format(str_replace("24", "00", $i + $measure), 2);
            $startExplode = explode(".", $start);
            $start = str_pad($startExplode[0], 2, '0', STR_PAD_LEFT) . "." . ((int) $startExplode[1] > 0 ? (int) $startExplode[1] * 60 / 100 : "00");
            $endExplode = explode(".", $end);
            $end = str_pad($endExplode[0], 2, '0', STR_PAD_LEFT) . "." . ((int) $endExplode[1] > 0 ? (int) $endExplode[1] * 60 / 100 : "00");
        }
        if ($time_format != "H.i") {
            $start = date($time_format, strtotime($start));
            $end = date($time_format, strtotime($end));
        }
        /*$max_explode = explode(".", $hours->max);
        	$max_hour = (int)$hours->max + ((int)$max_explode[1]>0 ? 1 : 0);
        	for($i=(int)$hours->min; $i<$max_hour; $i++)
        	{
        		$start = str_pad($i, 2, '0', STR_PAD_LEFT) . '.00';
        		$end = str_replace("24", "00", str_pad($i+1, 2, '0', STR_PAD_LEFT)) . '.00';
        		if($time_format!="H.i")
        		{
        			$start = date($time_format, strtotime($start));
        			$end = date($time_format, strtotime($end));
        		}*/
        $row_empty = true;
        $temp_empty_count = 0;
        $row_content = "";
        for ($j = 0; $j < count($weekdays); $j++) {
            //$weekday_fixed_number = ($weekdays[$j]->menu_order>1 ? $weekdays[$j]->menu_order-1 : 7);
            $weekday_fixed_number = $weekdays[$j]->menu_order;
            if (!in_array($weekday_fixed_number, (array) (isset($drop_columns[$i]["columns"]) ? $drop_columns[$i]["columns"] : array()))) {
                if (tt_hour_in_array($i, isset($event_hours_tt[$weekday_fixed_number]) ? $event_hours_tt[$weekday_fixed_number] : array(), $measure, $hours_min)) {
                    $rowspan = tt_get_rowspan_value($i, $event_hours_tt[$weekday_fixed_number], 1, $measure, $hours_min);
                    if ($rowspan > 1) {
                        if ((int) $measure == 1) {
                            for ($k = 1; $k < $rowspan; $k++) {
                                $drop_columns[$i + $k]["columns"][] = $weekday_fixed_number;
                            }
                        } else {
                            for ($k = $measure; $k < $rowspan * $measure; $k = $k + $measure) {
                                $tmp = number_format($i + $k, 2);
                                $drop_columns["{$tmp}"]["columns"][] = $weekday_fixed_number;
                            }
                        }
                    }
                    $array_count = count($event_hours_tt[$weekday_fixed_number]);
                    $hours = array();
                    if ((int) $measure == 1) {
                        for ($k = (int) $i; $k < (int) $i + $rowspan; $k++) {
                            $hours[] = $k;
                        }
                    } else {
                        for ($k = (double) $i; $k < (double) $i + $rowspan * $measure; $k = $k + $measure) {
                            $hours[] = $k;
                        }
                    }
                    $events = array();
                    for ($k = 0; $k < $array_count; $k++) {
                        if ((int) $measure == 1 && in_array((int) $event_hours_tt[$weekday_fixed_number][$k]["start"], $hours) || (int) $measure != 1 && in_array(to_decimal_time(roundMin($event_hours_tt[$weekday_fixed_number][$k]["start"], $measure, $hours_min)), $hours)) {
                            /*$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["name"] = $event_hours_tt[$weekday_fixed_number][$k]["name"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["title"] = $event_hours_tt[$weekday_fixed_number][$k]["title"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["tooltip"][] = $event_hours_tt[$weekday_fixed_number][$k]["tooltip"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["before_hour_text"][] = $event_hours_tt[$weekday_fixed_number][$k]["before_hour_text"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["after_hour_text"][] = $event_hours_tt[$weekday_fixed_number][$k]["after_hour_text"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["id"] = $event_hours_tt[$weekday_fixed_number][$k]["id"];
                            		$events[$event_hours_tt[$weekday_fixed_number][$k]["name"]]["hours"][] = $event_hours_tt[$weekday_fixed_number][$k]["start"] . " - " . $event_hours_tt[$weekday_fixed_number][$k]["end"];*/
                            $events[$k]["name"] = $event_hours_tt[$weekday_fixed_number][$k]["name"];
                            $events[$k]["title"] = $event_hours_tt[$weekday_fixed_number][$k]["title"];
                            $events[$k]["tooltip"][] = $event_hours_tt[$weekday_fixed_number][$k]["tooltip"];
                            $events[$k]["before_hour_text"][] = $event_hours_tt[$weekday_fixed_number][$k]["before_hour_text"];
                            $events[$k]["after_hour_text"][] = $event_hours_tt[$weekday_fixed_number][$k]["after_hour_text"];
                            $events[$k]["id"] = $event_hours_tt[$weekday_fixed_number][$k]["id"];
                            $events[$k]["hours"][] = $event_hours_tt[$weekday_fixed_number][$k]["start"] . " - " . $event_hours_tt[$weekday_fixed_number][$k]["end"];
                            $event_hours_tt[$weekday_fixed_number][$k]["displayed"] = true;
                        }
                    }
                    $color = "";
                    $text_color = "";
                    $hover_color = "";
                    $hover_text_color = "";
                    $hours_text_color = "";
                    $hours_hover_text_color = "";
                    if (count($events) == 1 && count($events[key($events)]['hours']) == 1) {
                        $color = get_post_meta($events[key($events)]["id"], "timetable_color", true);
                        if ($color == "" && strtoupper($box_bg_color) != "00A27C") {
                            $color = $box_bg_color;
                        }
                        $hover_color = get_post_meta($events[key($events)]["id"], "timetable_hover_color", true);
                        if ($hover_color == "" && strtoupper($box_hover_bg_color) != "1F736A") {
                            $hover_color = $box_hover_bg_color;
                        }
                        $text_color = get_post_meta($events[key($events)]["id"], "timetable_text_color", true);
                        if ($text_color == "" && strtoupper($box_txt_color) != "FFFFFF") {
                            $text_color = $box_txt_color;
                        }
                        $hover_text_color = get_post_meta($events[key($events)]["id"], "timetable_hover_text_color", true);
                        if ($hover_text_color == "" && strtoupper($box_hover_txt_color) != "FFFFFF") {
                            $hover_text_color = $box_hover_txt_color;
                            if ($text_color == "") {
                                $text_color = "FFFFFF";
                            }
                        }
                        $hours_text_color = get_post_meta($events[key($events)]["id"], "timetable_hours_text_color", true);
                        if ($hours_text_color == "" && strtoupper($box_hours_txt_color) != "FFFFFF") {
                            $hours_text_color = $box_hours_txt_color;
                        }
                        $hours_hover_text_color = get_post_meta($events[key($events)]["id"], "timetable_hours_hover_text_color", true);
                        if ($hours_hover_text_color == "" && (strtoupper($box_hours_hover_txt_color) != "FFFFFF" || $hours_text_color != "")) {
                            $hours_hover_text_color = $box_hours_hover_txt_color;
                            if ($hours_text_color == "") {
                                $hours_text_color = "FFFFFF";
                            }
                        }
                    }
                    $global_colors = array("box_bg_color" => $box_bg_color, "box_hover_bg_color" => $box_hover_bg_color, "box_txt_color" => $box_txt_color, "box_hover_txt_color" => $box_hover_txt_color, "box_hours_txt_color" => $box_hours_txt_color, "box_hours_hover_txt_color" => $box_hours_hover_txt_color);
                    $row_content .= '<td' . ($color != "" || $text_color != "" || $text_align != "center" ? ' style="' . ($text_align != "center" ? 'text-align:' . $text_align . ';' : '') . ($color != "" ? 'background: #' . $color . ';' : '') . ($text_color != "" ? 'color: #' . $text_color . ';' : '') . '"' : '') . ($hover_color != "" || $hover_text_color != "" || $hours_hover_text_color != "" ? ' onMouseOver="' . ($hover_color != "" ? 'this.style.background=\'#' . $hover_color . '\';' : '') . ($hover_text_color != "" ? 'this.style.color=\'#' . $hover_text_color . '\';jQuery(this).find(\'.event_header\').css(\'cssText\', \'color: #' . $hover_text_color . ' !important\');' : '') . ($hours_hover_text_color != "" ? 'jQuery(this).find(\'.hours\').css(\'color\',\'#' . $hours_hover_text_color . '\');' : '') . '" onMouseOut="' . ($hover_color != "" ? 'this.style.background=\'#' . $color . '\';' : '') . ($hover_text_color != "" ? 'this.style.color=\'#' . $text_color . '\';jQuery(this).find(\'.event_header\').css(\'cssText\',\'color: #' . $text_color . ' !important\');' : '') . ($hours_hover_text_color != "" ? 'jQuery(this).find(\'.hours\').css(\'color\',\'#' . $hours_text_color . '\');' : '') . '"' : '') . ' class="event' . (count(array_filter(array_values($events[key($events)]['tooltip']))) && count($events) == 1 && count($events[key($events)]['hours']) == 1 ? ' tt_tooltip' : '') . (count($events) == 1 && count($events[key($events)]['hours']) == 1 ? ' tt_single_event' : '') . '"' . ($rowspan > 1 ? ' rowspan="' . $rowspan . '"' : '') . '>';
                    $row_content .= tt_get_row_content($events, $events_page, $time_format, $event_layout, $global_colors, $disable_event_url);
                    $row_content .= '</td>';
                    $row_empty = false;
                } else {
                    $row_content .= '<td></td>';
                }
                $temp_empty_count++;
            }
        }
        if ($temp_empty_count != $j) {
            $row_empty = false;
        }
        if ((int) $hide_empty && !$row_empty || !(int) $hide_empty) {
            $output .= '<tr class="row_' . ($l + 1) . ($l % 2 == 1 ? ' row_gray' : '') . '"' . ($l % 2 == 1 && strtoupper($row1_color) != "F0F0F0" ? ' style="background: ' . ($row1_color != "transparent" ? '#' : '') . $row1_color . ' !important;"' : '') . ($l % 2 == 0 && $row2_color != "" ? ' style="background: ' . ($row2_color != "transparent" ? '#' : '') . $row2_color . ' !important;"' : '') . '>';
            if (!(int) $hide_hours_column) {
                $output .= '<td class="tt_hours_column">
					' . $start . ((int) $show_end_hour ? ' - ' . $end : '') . '
				</td>';
            }
            $output .= $row_content;
            $output .= '</tr>';
            $l++;
        }
    }
    $output .= '</tbody>
			</table>';
    if ((int) $responsive) {
        $output .= '<div class="tt_timetable small">';
        $l = 0;
        foreach ($weekdays as $weekday) {
            //$weekday_fixed_number = ($weekday->menu_order>1 ? $weekday->menu_order-1 : 7);
            $weekday_fixed_number = $weekday->menu_order;
            if (isset($event_hours_tt[$weekday_fixed_number])) {
                $output .= '<h3 class="box_header ' . ($collapse_event_hours_responsive ? 'plus ' : '') . ($l > 0 ? ' page_margin_top' : '') . '">
					' . $weekday->post_title . '
				</h3>
				<ul class="tt_items_list thin page_margin_top timetable_clearfix' . (isset($mode) && $mode == '12h' ? ' mode12' : '') . '">';
                $event_hours_count = count($event_hours_tt[$weekday_fixed_number]);
                for ($i = 0; $i < $event_hours_count; $i++) {
                    if ($time_format != "H.i") {
                        $event_hours_tt[$weekday_fixed_number][$i]["start"] = date($time_format, strtotime($event_hours_tt[$weekday_fixed_number][$i]["start"]));
                        $event_hours_tt[$weekday_fixed_number][$i]["end"] = date($time_format, strtotime($event_hours_tt[$weekday_fixed_number][$i]["end"]));
                    }
                    $classes_url = "";
                    $timetable_custom_url = get_post_meta($event_hours_tt[$weekday_fixed_number][$i]["id"], "timetable_custom_url", true);
                    if (!(int) get_post_meta($event_hours_tt[$weekday_fixed_number][$i]["id"], "timetable_disable_url", true) && !(int) $disable_event_url) {
                        $classes_url = $timetable_custom_url != "" ? $timetable_custom_url : get_permalink($event_hours_tt[$weekday_fixed_number][$i]["id"]);
                    }
                    $output .= '
							<li class="timetable_clearfix">
								<div class="event_container">
									<' . ($classes_url != "" ? 'a' : 'span') . ($classes_url != "" ? ' href="' . $classes_url . '"' : '') . ' title="' . esc_attr($event_hours_tt[$weekday_fixed_number][$i]["title"]) . '"' . ' class="event_header">' . $event_hours_tt[$weekday_fixed_number][$i]["title"] . ' </' . ($classes_url != "" ? 'a' : 'span') . '>';
                    if ($event_description_responsive == "description-1" || $event_description_responsive == "description-1-and-description-2") {
                        $output .= '<span class="event_description_1">' . $event_hours_tt[$weekday_fixed_number][$i]["before_hour_text"] . '</span>';
                    }
                    if ($event_description_responsive == "description-2" || $event_description_responsive == "description-1-and-description-2") {
                        $output .= '<span class="event_description_2">' . $event_hours_tt[$weekday_fixed_number][$i]["after_hour_text"] . '</span>';
                    }
                    $output .= '</div>';
                    $output .= '<div class="value">
									' . $event_hours_tt[$weekday_fixed_number][$i]["start"] . ' - ' . $event_hours_tt[$weekday_fixed_number][$i]["end"] . '
								</div>
							</li>';
                }
                $output .= '</ul>';
                $l++;
            }
        }
        $output .= '</div>';
    }
    return $output;
}