<?php

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Includes the files needed for the Calendars
 *
 */
function wpsbc_include_files_calendar()
{

    // Get calendar dir path
    $dir_path = plugin_dir_path(__FILE__);

    // Include other functions files
    if (file_exists($dir_path . 'functions-ajax.php')) {
        include $dir_path . 'functions-ajax.php';
    }

    // Include main Calendar class
    if (file_exists($dir_path . 'class-calendar.php')) {
        include $dir_path . 'class-calendar.php';
    }

    // Include the db layer classes
    if (file_exists($dir_path . 'class-object-db-calendars.php')) {
        include $dir_path . 'class-object-db-calendars.php';
    }

    if (file_exists($dir_path . 'class-object-meta-db-calendars.php')) {
        include $dir_path . 'class-object-meta-db-calendars.php';
    }

    // Include calendar outputters
    if (file_exists($dir_path . 'class-calendar-outputter.php')) {
        include $dir_path . 'class-calendar-outputter.php';
    }

    if (file_exists($dir_path . 'class-calendar-overview-outputter.php')) {
        include $dir_path . 'class-calendar-overview-outputter.php';
    }

}
add_action('wpsbc_include_files', 'wpsbc_include_files_calendar');

/**
 * Register the class that handles database queries for the Calendars
 *
 * @param array $classes
 *
 * @return array
 *
 */
function wpsbc_register_database_classes_calendars($classes)
{

    $classes['calendars'] = 'WPSBC_Object_DB_Calendars';
    $classes['calendarmeta'] = 'WPSBC_Object_Meta_DB_Calendars';

    return $classes;

}
add_filter('wpsbc_register_database_classes', 'wpsbc_register_database_classes_calendars');

/**
 * Returns an array with WPSBC_Calendar objects from the database
 *
 * @param array $args
 * @param bool  $count
 *
 * @return array
 *
 */
function wpsbc_get_calendars($args = array(), $count = false)
{

    $calendars = wp_simple_booking_calendar()->db['calendars']->get_calendars($args, $count);

    /**
     * Add a filter hook just before returning
     *
     * @param array $calendars
     * @param array $args
     * @param bool  $count
     *
     */
    return apply_filters('wpsbc_get_calendars', $calendars, $args, $count);

}

/**
 * Gets a calendar from the database
 *
 * @param mixed int|object      - calendar id or object representing the calendar
 *
 * @return WPSBC_Calendar|false
 *
 */
function wpsbc_get_calendar($calendar)
{

    return wp_simple_booking_calendar()->db['calendars']->get_object($calendar);

}

/**
 * Inserts a new calendar into the database
 *
 * @param array $data
 *
 * @return mixed int|false
 *
 */
function wpsbc_insert_calendar($data)
{

    return wp_simple_booking_calendar()->db['calendars']->insert($data);

}

/**
 * Updates a calendar from the database
 *
 * @param int     $calendar_id
 * @param array $data
 *
 * @return bool
 *
 */
function wpsbc_update_calendar($calendar_id, $data)
{

    return wp_simple_booking_calendar()->db['calendars']->update($calendar_id, $data);

}

/**
 * Deletes a calendar from the database
 *
 * @param int $calendar_id
 *
 * @return bool
 *
 */
function wpsbc_delete_calendar($calendar_id)
{

    return wp_simple_booking_calendar()->db['calendars']->delete($calendar_id);

}

/**
 * Inserts a new meta entry for the calendar
 *
 * @param int    $calendar_id
 * @param string $meta_key
 * @param string $meta_value
 * @param bool   $unique
 *
 * @return mixed int|false
 *
 */
function wpsbc_add_calendar_meta($calendar_id, $meta_key, $meta_value, $unique = false)
{

    return wp_simple_booking_calendar()->db['calendarmeta']->add($calendar_id, $meta_key, $meta_value, $unique);

}

/**
 * Updates a meta entry for the calendar
 *
 * @param int    $calendar_id
 * @param string $meta_key
 * @param string $meta_value
 * @param bool   $prev_value
 *
 * @return bool
 *
 */
function wpsbc_update_calendar_meta($calendar_id, $meta_key, $meta_value, $prev_value = '')
{

    return wp_simple_booking_calendar()->db['calendarmeta']->update($calendar_id, $meta_key, $meta_value, $prev_value);

}

/**
 * Returns a meta entry for the calendar
 *
 * @param int    $calendar_id
 * @param string $meta_key
 * @param bool   $single
 *
 * @return mixed
 *
 */
function wpsbc_get_calendar_meta($calendar_id, $meta_key = '', $single = false)
{

    return wp_simple_booking_calendar()->db['calendarmeta']->get($calendar_id, $meta_key, $single);

}

/**
 * Removes a meta entry for the calendar
 *
 * @param int    $calendar_id
 * @param string $meta_key
 * @param string $meta_value
 * @param bool   $delete_all
 *
 * @return bool
 *
 */
function wpsbc_delete_calendar_meta($calendar_id, $meta_key, $meta_value = '', $delete_all = '')
{

    return wp_simple_booking_calendar()->db['calendarmeta']->delete($calendar_id, $meta_key, $meta_value, $delete_all);

}

/**
 * Returns the default arguments for the calendar outputter
 *
 * @return array
 *
 */
function wpsbc_get_calendar_output_default_args()
{

    $args = array(
        'show_title' => 1,
        'months_to_show' => 1,
        'start_weekday' => 1,
        'show_legend' => 1,
        'legend_position' => 'side',
        'show_button_navigation' => 1,
        'show_selector_navigation' => 1,
        'show_week_numbers' => 0,
        'current_year' => current_time('Y'),
        'current_month' => current_time('n'),
        'jump_months' => 0,
        'highlight_today' => 0,
        'history' => 1,
        'show_tooltip' => 1,
        'language' => wpsbc_get_locale(),
        'min_width' => '200',
        'max_width' => '380',
    );

    /**
     * Filter the args before returning
     *
     * @param array $args
     *
     */
    $args = apply_filters('wpsbc_get_calendar_output_default_args', $args);

    return $args;

}

/**
 * Returns the default arguments for the calendar overview outputter
 *
 * @return array
 *
 */
function wpsbc_get_calendar_overview_output_default_args()
{

    $args = array(
        'show_legend' => 1,
        'legend_position' => 'top',
        'show_day_abbreviation' => 0,
        'current_year' => current_time('Y'),
        'current_month' => current_time('n'),
        'history' => 1,
        'show_tooltip' => 1,
        'language' => wpsbc_get_locale(),
    );

    /**
     * Filter the args before returning
     *
     * @param array $args
     *
     */
    $args = apply_filters('wpsbc_get_calendar_overview_output_default_args', $args);

    return $args;

}

/**
 * Generates and returns a random 32 character long string
 *
 * @return string
 *
 */
function wpsbc_generate_ical_hash()
{

    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $chars_length = strlen($chars);
    $ical_hash = '';

    for ($i = 0; $i < 19; $i++) {

        $ical_hash .= $chars[rand(0, $chars_length - 1)];

    }

    return $ical_hash . uniqid();

}

/**
 * Returns an array with all iCal feeds saved in the database
 *
 * @param int $calendar_id
 *
 * @return array
 *
 */
function wpsbc_get_calendar_meta_ical_feeds($calendar_id)
{

    global $wpdb;

    $calendar_id = absint($calendar_id);
    $table_name = wp_simple_booking_calendar()->db['calendarmeta']->table_name;

    $results = $wpdb->get_results("SELECT meta_value FROM {$table_name} WHERE calendar_id = '{$calendar_id}' AND meta_key LIKE '%ical_feed_%'", ARRAY_A);

    if (!is_array($results)) {
        return array();
    }

    foreach ($results as $key => $result) {

        $meta_value = $results[$key]['meta_value'];

        unset($results[$key]);

        $results[$key] = maybe_unserialize($meta_value);

    }

    return $results;

}

/**
 * Returns the last added ical_feed id
 *
 * @param int $calendar_id
 *
 * @return int
 *
 */
function wpsbc_get_ical_feeds_last_id($calendar_id)
{

    $ical_feeds = wpsbc_get_calendar_meta_ical_feeds($calendar_id);
    $last_id = 0;

    foreach ($ical_feeds as $ical_feed) {

        if ($ical_feed['id'] > $last_id) {
            $last_id = $ical_feed['id'];
        }

    }

    return $last_id;

}

/**
 * Gets all ical feed events, from all linked URLs and returns them as
 * WPSBC_Event objects that can be added to the calendar output
 *
 * @param int $calendar_id
 * @param array $existing_events
 *
 * @return array
 *
 */
function wpsbc_get_ical_feeds_as_events($calendar_id, $existing_events)
{

    if (wpsbc_get_calendar_meta($calendar_id, 'disable_icalendar_links', true) == true) {
        return array();
    }

    $ical_events = $temporary_ical_events = array();

    // Get the default legend item
    $bookable_legend_ids = array();

    $legend_items = wpsbc_get_legend_items(array('calendar_id' => $calendar_id));
    foreach ($legend_items as $legend_item) {
        if ($legend_item->get('is_bookable') && $legend_item->get('is_default')) {
            $bookable_legend_ids[] = $legend_item->get('id');
        }
    }

    // Loop for building temporary events
    $events = wpsbc_get_ical_feeds_as_array($calendar_id);

    foreach ($events as $event) {

        if (in_array($event['legend_item_id'], $bookable_legend_ids)) {
            continue;
        }

        $temporary_ical_events[$event['date_year'] . $event['date_month'] . $event['date_day']] = true;

    }

    foreach ($existing_events as $event) {
        if (in_array($event->get('legend_item_id'), $bookable_legend_ids) || $event->get('legend_item_id') == 0) {
            continue;
        }

        $temporary_ical_events[$event->get('date_year') . str_pad($event->get('date_month'), 2, '0', STR_PAD_LEFT) . str_pad($event->get('date_day'), 2, '0', STR_PAD_LEFT)] = true;
    }

    // Loop for building the correct events array
    foreach ($events as $event) {

        $event_date = DateTime::createFromFormat('Y-m-d', $event['date_year'] . '-' . $event['date_month'] . '-' . $event['date_day']);

        $split_end = $split_start = false;

        // Check if there are any past events for the current date
        $previous_day = clone $event_date;
        $previous_day->modify('-1 day');
        if (!array_key_exists($previous_day->format('Y') . $previous_day->format('m') . $previous_day->format('d'), $temporary_ical_events)) {
            $split_start = true;
        }

        // Check if there are any future events for the current date
        $next_day = clone $event_date;
        $next_day->modify('+1 day');
        if (!array_key_exists($next_day->format('Y') . $next_day->format('m') . $next_day->format('d'), $temporary_ical_events)) {
            $split_end = true;
        }

        // Get the correct legend item for our event
        if ($split_start && !$split_end && $event['split_days']) {
            $legend_item_id = $event['legend_item_id_split_start'];
        } elseif (!$split_start && $split_end && $event['split_days']) {
            
            $legend_item_id = $event['legend_item_id_split_end'];
            // Add another day to the split end day
            $event_data = array(
                'id' => null,
                'calendar_id' => $calendar_id,
                'legend_item_id' => $event['legend_item_id'],
                'date_year' => $event_date->format('Y'),
                'date_month' => $event_date->format('m'),
                'date_day' => $event_date->format('d'),
                'description' => $event['description'],
                'tooltip' => $event['tooltip'],
                'meta' => (isset($event['meta']) && $event['meta'] == 'ical-changeover' && $event['split_days'] ? 'ical-changeover' : ''),
            );
            $ical_events[] = wpsbc_get_event((object) $event_data);
            $event_date->modify('+1 day');

        } elseif ($split_start && $split_end && $event['split_days']) {

            $legend_item_id = $event['legend_item_id_split_end'];

            // Add another day to the split end day
            $event_data = array(
                'id' => null,
                'calendar_id' => $calendar_id,
                'legend_item_id' => $event['legend_item_id_split_start'],
                'date_year' => $event_date->format('Y'),
                'date_month' => $event_date->format('m'),
                'date_day' => $event_date->format('d'),
                'description' => $event['description'],
                'tooltip' => $event['tooltip'],
            );
            $ical_events[] = wpsbc_get_event((object) $event_data);
            $event_date->modify('+1 day');

        } else {
            $legend_item_id = $event['legend_item_id'];
        }

        $event_data = array(
            'id' => null,
            'calendar_id' => $calendar_id,
            'legend_item_id' => $legend_item_id,
            'date_year' => $event_date->format('Y'),
            'date_month' => $event_date->format('m'),
            'date_day' => $event_date->format('d'),
            'description' => $event['description'],
            'tooltip' => $event['tooltip'],
            'meta' => (isset($event['meta']) && $event['meta'] == 'ical-changeover' && $legend_item_id == $event['legend_item_id'] && $event['split_days'] ? 'ical-changeover' : ''),
        );

        $ical_events[] = wpsbc_get_event((object) $event_data);

    }

    return $ical_events;

}

/**
 * Gets all ical feed events, from all linked URLs and returns them as
 * an array of dates
 *
 * @param int $calendar_id
 *
 * @return array
 *
 */
function wpsbc_get_ical_feeds_as_array($calendar_id)
{

    $ical_feeds = wpsbc_get_calendar_meta_ical_feeds($calendar_id);

    $events = array();

    // Include the iCal Reader
    include_once WPSBC_PLUGIN_DIR . 'includes/libs/iCalReader/class-ical-reader.php';

    // Initial loop to temporarily store iCal events
    foreach ($ical_feeds as $ical_feed) {

        if (empty($ical_feed['file_contents'])) {
            continue;
        }

        if (empty($ical_feed['url'])) {
            continue;
        }

        if(isset($ical_feed['disabled']) && $ical_feed['disabled'] == true){
            continue;
        }

        // Extract the file in an array format
        $ical_reader = new WPSBC_ICal_Reader();
        $ical_arr = $ical_reader->init_contents($ical_feed['file_contents']);

        if (empty($ical_arr['VEVENT']) || !is_array($ical_arr['VEVENT'])) {
            continue;
        }

        foreach ($ical_arr['VEVENT'] as $ical_event) {

            $ical_event = apply_filters('wpsbc_ical_import_from_url_event', $ical_event);

            if (!isset($ical_event['DTEND'])) {
                continue;
            }

            // Remove timezones from strings
            $dtstart = wpsbc_remove_timezone_from_date_string($ical_event['DTSTART']);
            $dtend = wpsbc_remove_timezone_from_date_string($ical_event['DTEND']);

            // Check for invalid dates
            if (!is_numeric($dtstart) || !is_numeric($dtend)) {
                continue;
            }

            $begin = new DateTime($dtstart);
            $end = new DateTime($dtend);

            $begin->setTime(0, 0, 0);
            $end->setTime(23, 59, 59);

            // Check if it's an hourly event
            $interval = $begin->diff($end);
            if ($interval->days == 0) {
                $end->modify('+1 day');
            }

            $end->modify('-1 day');

            /**
             * Allow adding an offset to iCalendar feeds.
             */
            $start_offset = apply_filters('wpsbc_ical_import_from_url_offset_start', false, $ical_event, $begin, $end);
            $end_offset = apply_filters('wpsbc_ical_import_from_url_offset_end', false, $ical_event, $begin, $end);

            if ($start_offset !== false) {
                $begin->modify($start_offset);
            }

            if ($end_offset !== false) {
                $end->modify($end_offset);
            }

            for ($i = clone $begin; $i <= $end; $i->modify('+1 day')) {

                $skip = apply_filters('wpsbc_skip_ical_event', false, $ical_event, $ical_feed);

                if($skip){
                    continue;
                }

                $event_data = array(
                    'legend_item_id' => $ical_feed['legend_item_id'],
                    'split_days' => isset($ical_feed['split_days']) ? $ical_feed['split_days'] : 0,
                    'legend_item_id_split_start' => isset($ical_feed['legend_item_id_split_start']) ? $ical_feed['legend_item_id_split_start'] : false,
                    'legend_item_id_split_end' => isset($ical_feed['legend_item_id_split_end']) ? $ical_feed['legend_item_id_split_end'] : false,
                    'date_year' => $i->format('Y'),
                    'date_month' => $i->format('m'),
                    'date_day' => $i->format('d'),
                    'description' => $ical_feed['name'] . ' - ' . (!empty($ical_event['SUMMARY']) ? wp_kses_post($ical_event['SUMMARY']) : ''),
                    'tooltip' => (!empty($ical_event['SUMMARY']) ? wp_kses_post($ical_event['SUMMARY']) : ''),
                );

                if ($i == $begin || $i == $end) {
                    $event_data['meta'] = 'ical-changeover';
                }

                $events[] = $event_data;

            }

        }

    }

    return $events;

}

/**
 * Remove Timezone from Date strings.
 *
 * @param string $date
 *
 * @return string
 *
 */
function wpsbc_remove_timezone_from_date_string($date)
{
    return explode('T', $date)[0];
}
