from datetime import datetime
import obspython as obs

source_name = ""
scene_name = ""
switch_scene = False
diff = 0
hours_visible = True
mins_visible = True
secs_visible = True

# The time formatter
def format_time(secs):
    global hours_visible
    global mins_visible
    global secs_visible
    
    mins = secs // 60
    secs = secs % 60
    hours = mins // 60
    mins = mins % 60

    output = ""
    if hours_visible:
        output += "{:02d}".format(hours)
    if mins_visible:
        if hours_visible:
            output += ":"
        output += "{:02d}".format(mins)
    if secs_visible:
        if hours_visible or mins_visible:
            output += ":"
        output += "{:02d}".format(secs)
        
    return output

# The stopwatch
def stopwatch():
    global source_name
    global diff
    global switch_scene
    global scene_name

    now = datetime.now()
    source = obs.obs_get_source_by_name(source_name)
    diff = end_countdown_time-(int(now.strftime("%H"))*3600)-(int(now.strftime("%M"))*60)-int(now.strftime("%S"))
    if diff == 0:
        obs.timer_remove(stopwatch)
        obs.remove_current_callback()
        if switch_scene == True:
            if scene_name != "":
                obs.obs_frontend_set_current_scene(obs.obs_get_source_by_name(scene_name))
    elif diff < 0:
        obs.timer_remove(stopwatch)
        obs.remove_current_callback()
        diff = 0
    try:
        settings = obs.obs_data_create()
        obs.obs_data_set_string(settings, "text", str(format_time(int(diff))))
        obs.obs_source_update(source, settings)
        obs.obs_data_release(settings)
    except UnboundLocalError:
        pass

# Update the scene
def scene_updater():
    global source_name

    source = obs.obs_get_source_by_name(source_name)
    obs.obs_source_release(source)

# Apply the settings
def settings_updater(settings):
    global source_name
    global end_countdown_time
    global diff
    global switch_scene
    global scene_name
    global hours_visible
    global mins_visible
    global secs_visible

    source_name = obs.obs_data_get_string(settings, "source")
    end_countdown_time = (int(obs.obs_data_get_int(settings, "end_countdown_hour"))*3600) + (int(obs.obs_data_get_int(settings, "end_countdown_minute"))*60)
    switch_scene = obs.obs_data_get_bool(settings, "switch_scene")
    scene_name = obs.obs_data_get_string(settings, "end_scene")
    hours_visible = obs.obs_data_get_bool(settings, "hours_visible")
    mins_visible = obs.obs_data_get_bool(settings, "mins_visible")
    secs_visible = obs.obs_data_get_bool(settings, "secs_visible")

# Restart the timer and apply the settings
def restart_timer_pressed(props, prop):
    global settings_global

    obs.timer_remove(stopwatch)
    obs.timer_add(stopwatch, 200)
    settings_updater(settings_global)

# Description of the script
def script_description():
    return "Text source: The text of this source will be the timer\nLive update: If enabled the settings will be applied immediately\nEnd hour: The hour mark in 24-hour on which the timer will end\nEnd minute: The hour mark on which the timer will end\nHours visible: If enabled the hours will be visible\nMins visible: If enabled the minutes will be visible\nSecs visible: If enabled the seconds will be visible\nSwitch to scene: If enabled the scene will be switched to the selected scene\nEnd scene: The scene which will be switched to when the timer ends if 'Switch to scene' is enabled\nUpdate / (Re)start timer Timer: Applies the settings and (re)starts the timer"

# Update the settings
def script_update(settings):
    global settings_global
    settings_global = settings

    if obs.obs_data_get_bool(settings, "live_update"):
        settings_updater(settings)
    obs.timer_remove(scene_updater)
    if source_name != "":
        obs.timer_add(scene_updater, 1000)

# Delete the timers when the script is unloaded
def script_unload():
    obs.timer_remove(stopwatch)
    obs.timer_remove(scene_updater)

# Set the default settings
def script_defaults(settings):
    global settings_global

    obs.obs_data_set_bool(settings, "live_update", True)
    obs.obs_data_set_bool(settings, "switch_scene", False)
    obs.obs_data_set_bool(settings, "hours_visible", True)
    obs.obs_data_set_bool(settings, "mins_visible", True)
    obs.obs_data_set_bool(settings, "secs_visible", True)

    settings_global = settings

# Setup the script settings
def script_properties():
    props = obs.obs_properties_create()

    p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)

    obs.obs_properties_add_bool(props, "live_update", "Live update")
    obs.obs_properties_add_int(props, "end_countdown_hour", "End hour:", 0, 23, 1)
    obs.obs_properties_add_int(props, "end_countdown_minute", "End minute:", 0, 59, 1)

    sources = obs.obs_enum_sources()

    if sources is not None:
        for source in sources:
            name = obs.obs_source_get_name(source)
            source_id = obs.obs_source_get_unversioned_id(source)
            if source_id == "text_gdiplus" or source_id == "text_ft2_source":
                name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
        obs.source_list_release(sources)

    obs.obs_properties_add_bool(props, "hours_visible", "Hours visible")
    obs.obs_properties_add_bool(props, "mins_visible", "Mins visible")
    obs.obs_properties_add_bool(props, "secs_visible", "Secs visible")

    obs.obs_properties_add_bool(props, "switch_scene", "Switch to scene")

    s = obs.obs_properties_add_list(props, "end_scene", "End Scene", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)

    scenes = obs.obs_frontend_get_scenes()
    if scenes is not None:
        for scene in scenes:
            name = obs.obs_source_get_name(scene)
            obs.obs_property_list_add_string(s, name, name)
        obs.source_list_release(scenes)
        
    obs.obs_properties_add_button(props, "restart_button", "Update / (Re)start Timer", restart_timer_pressed)

    return props