__filename__ = "webapp_calendar.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.5.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Calendar"
import os
from datetime import datetime
from datetime import date
from utils import remove_html
from utils import get_display_name
from utils import get_config_param
from utils import get_nickname_from_actor
from utils import get_domain_from_actor
from utils import locate_post
from utils import load_json
from utils import week_day_of_month_start
from utils import get_alt_path
from utils import remove_domain_port
from utils import acct_dir
from utils import local_actor_url
from utils import replace_users_with_at
from utils import language_right_to_left
from utils import date_from_string_format
from happening import get_todays_events
from happening import get_calendar_events
from happening import get_todays_events_icalendar
from happening import get_month_events_icalendar
from webapp_utils import get_banner_file
from webapp_utils import set_custom_background
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import html_hide_from_screen_reader
from webapp_utils import html_keyboard_navigation
from maps import html_open_street_map
def html_calendar_delete_confirm(translate: {}, base_dir: str,
                                 path: str, http_prefix: str,
                                 domain_full: str, post_id: str,
                                 post_time: str,
                                 year: int, month_number: int,
                                 day_number: int, calling_domain: str) -> str:
    """Shows a screen asking to confirm the deletion of a calendar event
    """
    nickname = get_nickname_from_actor(path)
    if not nickname:
        return None
    actor = local_actor_url(http_prefix, nickname, domain_full)
    domain, _ = get_domain_from_actor(actor)
    if not domain:
        return None
    message_id = actor + '/statuses/' + post_id
    post_filename = locate_post(base_dir, nickname, domain, message_id)
    if not post_filename:
        return None
    post_json_object = load_json(post_filename)
    if not post_json_object:
        return None
    delete_post_str = None
    css_filename = base_dir + '/epicyon-profile.css'
    if os.path.isfile(base_dir + '/epicyon.css'):
        css_filename = base_dir + '/epicyon.css'
    instance_title = \
        get_config_param(base_dir, 'instanceTitle')
    delete_post_str = \
        html_header_with_external_style(css_filename, instance_title, None)
    delete_post_str += \
        '
\n' + post_time + ' ' + str(year) + '/' + \
        str(month_number) + \
        '/' + str(day_number) + ' \n \n'
    delete_post_str += ''
    delete_post_str += '  ' + \
        translate['Delete this event'] + '
'
    post_actor = get_alt_path(actor, domain_full, calling_domain)
    delete_post_str += \
        '  \n'
    delete_post_str += ' \n'
    delete_post_str += html_footer()
    return delete_post_str
def _html_calendar_day(person_cache: {}, translate: {},
                       base_dir: str, path: str,
                       year: int, month_number: int, day_number: int,
                       nickname: str, domain: str, day_events: [],
                       month_name: str, actor: str,
                       theme: str, access_keys: {},
                       system_language: str) -> str:
    """Show a day within the calendar
    """
    account_dir = acct_dir(base_dir, nickname, domain)
    calendar_file = account_dir + '/.newCalendar'
    if os.path.isfile(calendar_file):
        try:
            os.remove(calendar_file)
        except OSError:
            print('EX: _html_calendar_day unable to delete ' + calendar_file)
    css_filename = base_dir + '/epicyon-calendar.css'
    if os.path.isfile(base_dir + '/calendar.css'):
        css_filename = base_dir + '/calendar.css'
    cal_actor = actor
    if '/users/' in actor:
        cal_actor = '/users/' + actor.split('/users/')[1]
    instance_title = get_config_param(base_dir, 'instanceTitle')
    calendar_str = \
        html_header_with_external_style(css_filename, instance_title, None)
    calendar_link = cal_actor + \
        '/calendar?year=' + str(year) + '?month=' + str(month_number)
    # show banner
    banner_file, _ = \
        get_banner_file(base_dir, nickname, domain, theme)
    calendar_str += \
        '\n\n'
    # day header
    calendar_str += \
        '  \n\n\n'
    datetime_str = str(year) + '-' + str(month_number) + '-' + str(day_number)
    calendar_str += \
        '   ' + str(year) + ' \n'
    calendar_str += '
\n \n'
    calendar_str += '\n'
    # day events list
    calendar_str += '\n'
    if day_events:
        for event_post in day_events:
            event_time = None
            event_time_markup = None
            event_end_time = None
            start_time_str = ''
            end_time_str = ''
            event_description = None
            event_language = system_language
            event_place = None
            post_id = None
            sender_name = ''
            sender_actor = None
            event_is_public = False
            # get the time place and description
            for evnt in event_post:
                event_language = system_language
                if evnt.get('language'):
                    event_language = evnt['language']
                if evnt['type'] == 'Event':
                    if evnt.get('post_id'):
                        post_id = evnt['post_id']
                    if evnt.get('startTime'):
                        start_time_str = evnt['startTime']
                        event_date = \
                            date_from_string_format(start_time_str,
                                                    ["%Y-%m-%dT%H:%M:%S%z"])
                        event_time = event_date.strftime("%H:%M").strip()
                    if evnt.get('endTime'):
                        end_time_str = evnt['endTime']
                        event_end_date = \
                            date_from_string_format(end_time_str,
                                                    ["%Y-%m-%dT%H:%M:%S%z"])
                        event_end_time = \
                            event_end_date.strftime("%H:%M").strip()
                    if 'public' in evnt:
                        if evnt['public'] is True:
                            event_is_public = True
                    if evnt.get('sender'):
                        # get display name from sending actor
                        if evnt.get('sender'):
                            sender_actor = evnt['sender']
                            disp_name = \
                                get_display_name(base_dir, sender_actor,
                                                 person_cache)
                            if disp_name:
                                sender_name = \
                                    '' + \
                                    disp_name + ' : '
                    if evnt.get('name'):
                        event_description = evnt['name'].strip()
                elif evnt['type'] == 'Place':
                    if evnt.get('name'):
                        event_place = remove_html(evnt['name'])
                        if '://' in event_place:
                            bounding_box_degrees = 0.001
                            event_map = \
                                html_open_street_map(event_place,
                                                     bounding_box_degrees,
                                                     translate,
                                                     '320', '320')
                            if event_map:
                                event_place = event_map
            # prepend a link to the sender of the calendar item
            if sender_name and event_description:
                # if the sender is also mentioned within the event
                # description then this is a reminder
                sender_actor2 = replace_users_with_at(sender_actor)
                if sender_actor not in event_description and \
                   sender_actor2 not in event_description:
                    event_description = sender_name + event_description
                else:
                    event_description = \
                        translate['Reminder'] + ': ' + event_description
            delete_button_str = ''
            if post_id:
                delete_button_str = \
                    '\n ' + \
                    event_time + ' '
                if event_time and event_end_time and \
                   start_time_str != end_time_str:
                    event_time_int_str = event_time.replace(':', '')
                    event_end_time_int_str = event_end_time.replace(':', '')
                    if event_time_int_str.isdigit() and \
                       event_end_time_int_str.isdigit():
                        if int(event_end_time_int_str) > \
                           int(event_time_int_str):
                            event_time_markup = \
                                '' + \
                                event_time_markup + '  - ' + \
                                '' + \
                                event_end_time + ' '
            if event_time and event_description and event_place:
                calendar_str += \
                    '' + \
                    '' + \
                    event_time_markup + \
                    ' ' + \
                    '' + \
                    event_place + '  ' + delete_button_str + ' \n'
            elif event_time and event_description and not event_place:
                calendar_str += \
                    '' + \
                    '' + \
                    event_time_markup + \
                    ' ' + \
                    event_description + ' ' + delete_button_str + ' \n'
            elif not event_time and event_description and not event_place:
                calendar_str += \
                    '' + \
                    '' + \
                    ' ' + \
                    event_description + ' ' + delete_button_str + ' \n'
            elif not event_time and event_description and event_place:
                calendar_str += \
                    '' + \
                    '' + \
                    event_place + '  \n'
            elif event_time and not event_description and event_place:
                calendar_str += \
                    '' + \
                    '' + \
                    event_time_markup + \
                    ' ' + \
                    '' + \
                    event_place + '  ' + \
                    delete_button_str + ' \n'
    calendar_str += ' \n'
    calendar_str += '
\n \n'
    # icalendar download link
    calendar_str += \
        '    ' + \
        ' \n'
    calendar_str += html_footer()
    return calendar_str
def html_calendar(person_cache: {}, translate: {},
                  base_dir: str, path: str,
                  http_prefix: str, domain_full: str,
                  text_mode_banner: str, access_keys: {},
                  icalendar: bool, system_language: str,
                  default_timeline: str, theme: str) -> str:
    """Show the calendar for a person
    """
    domain = remove_domain_port(domain_full)
    text_match = ''
    default_year = 1970
    default_month = 0
    month_number = default_month
    day_number = None
    year = default_year
    actor = http_prefix + '://' + domain_full + path.replace('/calendar', '')
    only_show_reminders = False
    if '?' in actor:
        first = True
        for part in actor.split('?'):
            if not first:
                if '=' in part:
                    if part.split('=')[0] == 'year':
                        num_str = part.split('=')[1]
                        if len(num_str) <= 5:
                            if num_str.isdigit():
                                year = int(num_str)
                    elif part.split('=')[0] == 'month':
                        num_str = part.split('=')[1]
                        if len(num_str) <= 3:
                            if num_str.isdigit():
                                month_number = int(num_str)
                    elif part.split('=')[0] == 'day':
                        num_str = part.split('=')[1]
                        if len(num_str) <= 3:
                            if num_str.isdigit():
                                day_number = int(num_str)
                    elif part.split('=')[0] == 'ical':
                        bool_str = part.split('=')[1]
                        if bool_str.lower().startswith('t'):
                            icalendar = True
                    elif part.split('=')[0] == 'onlyShowReminders':
                        bool_str = part.split('=')[1]
                        if bool_str.lower().startswith('t'):
                            only_show_reminders = True
            first = False
        actor = actor.split('?')[0]
    curr_date = datetime.now()
    if year == default_year and month_number == default_month:
        year = curr_date.year
        month_number = curr_date.month
    nickname = get_nickname_from_actor(actor)
    if not nickname:
        return ''
    set_custom_background(base_dir, 'calendar-background',
                          'calendar-background')
    months = (
        'January', 'February', 'March', 'April', 'May', 'June',
        'July', 'August', 'September', 'October', 'November', 'December'
    )
    month_name = translate[months[month_number - 1]]
    if day_number:
        if icalendar:
            return get_todays_events_icalendar(base_dir,
                                               nickname, domain,
                                               year, month_number,
                                               day_number,
                                               person_cache,
                                               text_match,
                                               system_language)
        day_events = None
        events = \
            get_todays_events(base_dir, nickname, domain,
                              year, month_number, day_number,
                              text_match, system_language)
        if events:
            if events.get(str(day_number)):
                day_events = events[str(day_number)]
        return _html_calendar_day(person_cache,
                                  translate, base_dir, path,
                                  year, month_number, day_number,
                                  nickname, domain, day_events,
                                  month_name, actor,
                                  theme, access_keys,
                                  system_language)
    if icalendar:
        return get_month_events_icalendar(base_dir, nickname, domain,
                                          year, month_number, person_cache,
                                          text_match)
    events = \
        get_calendar_events(base_dir, nickname, domain, year, month_number,
                            text_match, only_show_reminders)
    prev_year = year
    prev_month_number = month_number - 1
    if prev_month_number < 1:
        prev_month_number = 12
        prev_year = year - 1
    next_year = year
    next_month_number = month_number + 1
    if next_month_number > 12:
        next_month_number = 1
        next_year = year + 1
    print('Calendar year=' + str(year) + ' month=' + str(month_number) +
          ' ' + str(week_day_of_month_start(month_number, year)))
    if month_number < 12:
        days_in_month = \
            (date(year, month_number + 1, 1) -
             date(year, month_number, 1)).days
    else:
        days_in_month = \
            (date(year + 1, 1, 1) - date(year, month_number, 1)).days
    # print('days_in_month ' + str(month_number) + ': ' + str(days_in_month))
    css_filename = base_dir + '/epicyon-calendar.css'
    if os.path.isfile(base_dir + '/calendar.css'):
        css_filename = base_dir + '/calendar.css'
    cal_actor = actor
    if '/users/' in actor:
        cal_actor = '/users/' + actor.split('/users/')[1]
    instance_title = \
        get_config_param(base_dir, 'instanceTitle')
    header_str = \
        html_header_with_external_style(css_filename, instance_title, None)
    # show banner
    banner_file, _ = \
        get_banner_file(base_dir, nickname, domain, theme)
    calendar_str = \
        '\n'
    # the main graphical calendar as a table
    calendar_str += '\n\n\n'
    # previous month
    calendar_str += \
        '  '
    calendar_str += \
        '   \n'
    # header
    calendar_str += \
        '  '
    calendar_str += \
        '   \n'
    # next month
    calendar_str += \
        '  '
    calendar_str += \
        '   \n'
    # calendar table
    calendar_str += '
\n \n\n'
    calendar_str += '\n'
    calendar_str += '\n'
    days = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
    for day in days:
        calendar_str += '  \n'
    calendar_str += ' \n'
    calendar_str += ' \n'
    calendar_str += '\n'
    # beginning of the links used for accessibility
    nav_links = {}
    timeline_link_str = html_hide_from_screen_reader('🏠') + ' ' + \
        translate['Switch to timeline view']
    nav_links[timeline_link_str] = cal_actor + '/' + default_timeline
    day_of_month = 0
    dow = week_day_of_month_start(month_number, year)
    for week_of_month in range(1, 7):
        if day_of_month == days_in_month:
            continue
        calendar_str += '  \n'
        for day_number in range(1, 8):
            if (week_of_month > 1 and day_of_month < days_in_month) or \
               (week_of_month == 1 and day_number >= dow):
                day_of_month += 1
                is_today = False
                if year == curr_date.year:
                    if curr_date.month == month_number:
                        if day_of_month == curr_date.day:
                            is_today = True
                if events.get(str(day_of_month)):
                    url = cal_actor + '/calendar?year=' + \
                        str(year) + '?month=' + \
                        str(month_number) + '?day=' + str(day_of_month)
                    day_description = month_name + ' ' + str(day_of_month)
                    datetime_str = \
                        str(year) + '-' + str(month_number) + '-' + \
                        str(day_of_month)
                    day_link = '' + \
                        '' + \
                        str(day_of_month) + '  '
                    # accessibility menu links
                    menu_option_str = \
                        html_hide_from_screen_reader('📅') + ' ' + \
                        '' + \
                        day_description + ' '
                    nav_links[menu_option_str] = url
                    # there are events for this day
                    if not is_today:
                        calendar_str += \
                            '    ' + \
                            day_link + ' \n'
                    else:
                        calendar_str += \
                            '    ' + \
                            day_link + ' \n'
                else:
                    # No events today
                    if not is_today:
                        calendar_str += \
                            '    ' + \
                            str(day_of_month) + ' \n'
                    else:
                        calendar_str += \
                            '    ' + str(day_of_month) + ' \n'
            else:
                calendar_str += '     \n'
    calendar_str += ' \n'
    calendar_str += '
\n \n'
    # end of the links used for accessibility
    next_month_str = \
        html_hide_from_screen_reader('→') + ' ' + translate['Next month']
    nav_links[next_month_str] = \
        cal_actor + '/calendar?year=' + str(next_year) + \
        '?month=' + str(next_month_number)
    prev_month_str = \
        html_hide_from_screen_reader('←') + ' ' + translate['Previous month']
    nav_links[prev_month_str] = \
        cal_actor + '/calendar?year=' + str(prev_year) + \
        '?month=' + str(prev_month_number)
    nav_access_keys = {
    }
    screen_reader_cal = \
        html_keyboard_navigation(text_mode_banner, nav_links, nav_access_keys,
                                 month_name, None, None, False)
    if not only_show_reminders:
        show_reminders_link = \
            '' + \
            translate['Only show reminders'] + ' '
    else:
        show_reminders_link = \
            '' + \
            translate['Show all events'] + ' '
    new_event_str = \
        '\n\n' + \
        '➕ ' + \
        translate['Add to the calendar'] + ' 
\n' + \
        show_reminders_link + '
\n \n'
    calendar_icon_str = \
        '    ' + \
        ' \n'
    cal_str = \
        header_str + screen_reader_cal + calendar_str + \
        new_event_str + calendar_icon_str + html_footer()
    return cal_str