import datetime
import json
import os
import sys
import re
import glob
import shutil
import errno
import subprocess
from lxml import etree
from urllib.request import urlopen

scheduleUrl = 'http://data.c3voc.de/rC3_21/everything.schedule.xml'

scheduleTree=None

# Download the Events-Schedule and parse all Events out of it. Yield a tupel for each Event
def downloadSchedule(scheduleUrl):
    print("downloading schedule")

    # download the schedule
    response = urlopen(scheduleUrl)

    # read xml-source
    xml = response.read()

    # parse into ElementTree
    parser = etree.XMLParser(huge_tree=True)
    return etree.fromstring(xml, parser)

def getSchedule(scheduleUrl):
    global scheduleTree
    if not scheduleTree:
        scheduleTree=downloadSchedule(scheduleUrl)
    return scheduleTree

def persons(scheduleUrl, personmap={}, taglinemap={}, forEventId=None):
    schedule = getSchedule(scheduleUrl)
    # iterate all days
    for day in schedule.iter('day'):
        # iterate all rooms
        for room in day.iter('room'):
            # iterate events on that day in this room
            for event in room.iter('event'):
                eventid = int(event.get("id"))
                if event != None and not eventid == forEventId:
                    continue
                # aggregate names of the persons holding this talk
                persons_seen = []
                if event.find('persons') is not None:
                    for person in event.find('persons').iter('person'):
                        id = int(person.get("id"))
                        person = re.sub(r'\s+', ' ', person.text).strip()
                        match = re.search(r'\((.*?)\)', person)
                        tagline = ''
                        if not match is None:
                            tagline = match.group(1)
                            person = person.split(" (")[0]
                        if id in taglinemap:
                            tagline = taglinemap[id]
                        if id in personmap:
                            person = personmap[id]
                        if not id in persons_seen:
                            persons_seen.append(id)
                            yield {
                                'id': id,
                                'person': person,
                                'tagline': tagline
                            }

def events(scheduleUrl, titlemap={}):
    schedule = getSchedule(scheduleUrl)
    # iterate all days
    for day in schedule.iter('day'):
        # iterate all rooms
        for room in day.iter('room'):
            # iterate events on that day in this room
            for event in room.iter('event'):
                # aggregate names of the persons holding this talk
                personnames = []
                if event.find('persons') is not None:
                    for person in event.find('persons').iter('person'):
                        personname = re.sub(r'\s+', ' ', person.text).strip()
                        personnames.append(personname)

                id = int(event.get('id'))

                if id in titlemap:
                    title = titlemap[id]
                elif event.find('title') is not None and event.find('title').text is not None:
                    title = re.sub(r'\s+', ' ', event.find('title').text).strip()
                else:
                    title = ''

                if event.find('subtitle') is not None and event.find('subtitle').text is not None:
                    subtitle = re.sub(r'\s+', ' ', event.find('subtitle').text).strip()
                else:
                    subtitle = ''

                if event.find('duration') is not None and ':' in event.find('duration').text:
                    parts = event.find('duration').text.split(':', 1)
                    duration = int(parts[0]) * 60 + int(parts[1])
                else:
                    duration = None

                if event.find('start') is not None and event.find('start').text is not None:
                    start = re.sub(r'\s+', ' ', event.find('start').text).strip()
                else:
                    start = ''

                # yield a tupel with the event-id, event-title and person-names
                yield {
                    'day': day.get('index'),
                    'id': id,
                    'title': title,
                    'subtitle': subtitle,
                    #'persons': personnames,
                    'personnames': ', '.join(personnames),
                    'room': room.attrib['name'],
                    'track': event.find('track').text,
                    'start': event.find('start').text,
                    'datetime': event.find('date').text,
                    'duration': duration,
                    'roomguid': room.attrib['guid'] if 'guid' in room.attrib else '',
                    #'url': event.find('url').text
                }



if __name__ == "__main__":	
    events = list(events(scheduleUrl))

    # FIX: Some events have an incorrectly specified timezone (UTC instead of CET)
    for ev in events:
        if ev['datetime'].endswith("+00:00"):
            ev['datetime'] = ev['datetime'].replace("+00:00", "+01:00")
            print(f"Warning: Assuming CET instead of UTC for event '{ev['title']}': {ev['datetime']}")

    events = sorted(events, key=lambda x: datetime.datetime.fromisoformat(x["datetime"]))

    # Filter already passed events
    # (There is a grace period of 30 mins after start for events longer than that)
    grace = datetime.timedelta(minutes=30)
    def is_upcoming(ev, now=datetime.datetime.now().astimezone()):
        ev_date = datetime.datetime.fromisoformat(ev["datetime"])
        return ev_date + grace > now and ev_date + datetime.timedelta(minutes=ev["duration"]) > now
    events = filter(is_upcoming, events)

    with open("public/fahrplan.json", "w") as f:
        json.dump(list(events), f)


