# This scipt is for creating and using as many counters as you need.
#
# Written by HighMoon - Malcolm Greene
# v1.0

import obspython as obs
import sys

totalCounters = 1
counters = []

class counterClass:
    hotKeyInc = obs.OBS_INVALID_HOTKEY_ID
    hotKeyDec = obs.OBS_INVALID_HOTKEY_ID
    hotKeyRst = obs.OBS_INVALID_HOTKEY_ID
    stepAmount = 1
    count = 0
    displaySource = ""
    name = "counterName"
    padChar = "0"
    minVal = 0
    maxVal = 99
    
    def __init__(self, cntName):
        self.name = cntName
        
    def saveCounter(self, settings):
        hotKeySaveArray = obs.obs_hotkey_save(self.hotKeyInc)
        obs.obs_data_set_array(settings, self.name+"_inc", hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        hotKeySaveArray = obs.obs_hotkey_save(self.hotKeyDec)
        obs.obs_data_set_array(settings, self.name+"_dec", hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        hotKeySaveArray = obs.obs_hotkey_save(self.hotKeyRst)
        obs.obs_data_set_array(settings, self.name+"_rst", hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        obs.obs_data_set_int(settings,self.name+"_count",self.count)
        obs.obs_data_set_string(settings,self.name+"_source",self.displaySource)
        obs.obs_data_set_string(settings,self.name+"_pad_char", self.padChar)
        obs.obs_data_set_int(settings, self.name+"_min_val", self.minVal)
        obs.obs_data_set_int(settings, self.name+"_max_val", self.maxVal)
        obs.obs_data_set_int(settings, self.name+"_step_val", self.stepAmount)
    
    def loadCounter(self, settings, counterName):
        self.name = counterName
        self.count = obs.obs_data_get_int(settings, counterName+"_count")
        self.displaySource = obs.obs_data_get_string(settings, counterName+"_source")
        self.padChar = obs.obs_data_get_string(settings, counterName+"_pad_char")
        self.minVal = obs.obs_data_get_int(settings, counterName+"_min_val")
        self.maxVal = obs.obs_data_get_int(settings, counterName+"_max_val")
        self.stepAmount = obs.obs_data_get_int(settings, counterName+"_step_val")
        
        def inc_counter(pressed):
            if pressed:
                self.count = self.count + self.stepAmount
                if self.count > self.maxVal:
                    self.count = self.maxVal
                self.updateText()
            
        self.hotKeyInc = obs.obs_hotkey_register_frontend(counterName+"_inc", "Increment Counter "+counterName, inc_counter)
        hotKeySaveArray = obs.obs_data_get_array(settings, counterName+"_inc")
        obs.obs_hotkey_load(self.hotKeyInc, hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        def dec_counter(pressed):
            if pressed:
                self.count = self.count - self.stepAmount
                if self.count < self.minVal:
                    self.count = self.minVal
                self.updateText()
            
        self.hotKeyDec = obs.obs_hotkey_register_frontend(counterName+"_dec", "Decrement Counter "+counterName, dec_counter)
        hotKeySaveArray = obs.obs_data_get_array(settings, counterName+"_dec")
        obs.obs_hotkey_load(self.hotKeyDec, hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        def rst_counter(pressed):
            if pressed:
                self.count = self.minVal
                self.updateText()
            
        self.hotKeyRst = obs.obs_hotkey_register_frontend(counterName+"_rst", "Reset Counter "+counterName, rst_counter)
        hotKeySaveArray = obs.obs_data_get_array(settings, counterName+"_rst")
        obs.obs_hotkey_load(self.hotKeyRst, hotKeySaveArray)
        obs.obs_data_array_release(hotKeySaveArray)
        
        return settings
    
    def updateText(self):
        settings = obs.obs_data_create()
        pad=""
        
        source = obs.obs_get_source_by_name(self.displaySource)
        
        numLen = len(str(self.count))
        maxLen = len(str(self.maxVal)) 
        if len(str(self.minVal)) > maxLen:
            maxLen = len(str(self.minVal))
        pad = self.padChar * (maxLen - numLen)
            
        obs.obs_data_set_string(settings, "text", pad+str(self.count))
        obs.obs_source_update(source, settings)
        obs.obs_data_release(settings)
        obs.obs_source_release(source)    
    
def script_load(settings):
    global totalCounters
    totalCounters = obs.obs_data_get_int(settings,"total_counters")
    for prepCounter in range(totalCounters):
        counter = counterClass("counter_"+str(prepCounter+1))
        counters.append(counter)
        counters[prepCounter].loadCounter(settings, "counter_"+str(prepCounter+1))
        counters[prepCounter].updateText()
    obs.script_log(obs.LOG_INFO, "Counters script loaded")
    
def script_save(settings):
    for counter in counters:
        counter.saveCounter(settings)

def script_update(settings):
    global totalCounters
    oldTotal = totalCounters
    totalCounters = obs.obs_data_get_int(settings,"total_counters")
    
    for cntNum in range(totalCounters):
        if cntNum >= oldTotal:
            counter = counterClass("counter_"+str(cntNum+1))
            counter.displaySource = obs.obs_data_get_string(settings, "counter_"+str(cntNum+1)+"_source")
            counter.padChar = obs.obs_data_get_string(settings, "counter_"+str(cntNum+1)+"_pad_char")
            counter.minVal = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_min_val")
            counter.maxVal = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_max_val")
            counter.stepAmount = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_step_val")
            counters.append(counter)
            counter.updateText()
        else:
            counters[cntNum].displaySource = obs.obs_data_get_string(settings, "counter_"+str(cntNum+1)+"_source")
            counters[cntNum].padChar = obs.obs_data_get_string(settings, "counter_"+str(cntNum+1)+"_pad_char")
            counters[cntNum].minVal = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_min_val")
            counters[cntNum].maxVal = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_max_val")
            counters[cntNum].stepAmount = obs.obs_data_get_int(settings, "counter_"+str(cntNum+1)+"_step_val")
            counters[cntNum].updateText()
    

def script_properties():
    global totalCounters
    
    props = obs.obs_properties_create()
    obs.obs_properties_add_int(props, "total_counters", "Total Number of Counters", 1, 2147483647, 1)
    
    for makeCounter in range(totalCounters):
    
        p = obs.obs_properties_add_list(props, "counter_"+str(makeCounter+1)+"_source", "Text Source to display counter_"+str(makeCounter+1) , obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
        
        sources = obs.obs_enum_sources()
        if sources is not None:
            for source in sources:
                source_id = obs.obs_source_get_id(source)
                if source_id == "text_gdiplus" or source_id == "text_ft2_source" or source_id == "text_gdiplus_v3":
                    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_text(props, "counter_"+str(makeCounter+1)+"_pad_char", "Pad Character",  obs.OBS_TEXT_DEFAULT)
        obs.obs_properties_add_float(props, "counter_"+str(makeCounter+1)+"_min_val", "Counter Minimum Value", -2147483647, 2147483647, 1)
        obs.obs_properties_add_float(props, "counter_"+str(makeCounter+1)+"_max_val", "Counter Maximum Value", -2147483647, 2147483647, 1)
        obs.obs_properties_add_float(props, "counter_"+str(makeCounter+1)+"_step_val", "Counter Step Value", -2147483647, 2147483647, 1)
    
    return props
        
def script_description():
    return "Counter system that can handle many counters. \n Press the script refresh button after changing counter count. \n You can also hit refresh after changing other options force an update."