import es
import os
import time
import pickle
import keyvalues
import gamethread
import langlib
import playerlib
import popuplib
import keymenulib

import psyco
psyco.full()

#plugin information
info = es.AddonInfo()
info.name = "Setting EventScripts python library"
info.version = "oy2c"
info.author = "Hunter"
info.url = "http://www.eventscripts.com/pages/Setting/"
info.description = "Provides user based setting handling for Source games"

#global variables:
## gSettings holds all the settings by their names for backwards compatibility
gSettings = {}

# Get this library handle for registering events dynamically:
selfmodule = __import__('settinglib')
# Get the data path for reading/writing KeyValues
selfdatapath = "%s/%s" % (es.server_var["eventscripts_addondir"], 'setting/data')
selfdatatest = "%s/__init__.pkl" % selfdatapath
# Get the language strings
selflangpath = "%s/%s" % (es.server_var["eventscripts_addondir"], '_libs/python/settinglib')
selflangtext = langlib.Strings(selflangpath + "/strings.ini")
# Create default data folder
if not os.path.isdir(selfdatapath):
    os.mkdir(selfdatapath)
    
## Setting_setting class is the setting base class
class Setting_base(object):
    def __init__(self, pType):
        self.popup = {}                 #contains the popup object's per userid
        self.keyvalues = None           #contains the keyvalues object
        self.backmenuvar = 0            #backmenu that displays on 0. Cancel
        self.languages = selflangtext   #langlib object
        #init progress
        if not self.filename:
            if self.filetype == 'keyvalues':
                self.filename = selfdatapath+'/'+self.name+'.txt'
            elif self.filetype == 'dict':
                self.filename = selfdatapath+'/'+self.name+'.pkl'
        self.keyvalues = self.createKey(self.name)
        if os.path.exists(self.filename):
            self.load()
            try:
                if self.keyvalues["config"]["name"] == self.name:
                    doinit = False
                else:
                    doinit = True
            except:
                doinit = True
        else:
            doinit = True
        if doinit:
            self.keyvalues["config"] = self.createKey("config")
            self.keyvalues["config"]["name"] = self.name
            self.keyvalues["config"]["descr"] = self.descr
            self.keyvalues["config"]["resend"] = True
            self.keyvalues["config"]["sound"] = None
            self.keyvalues["config"]["type"] = str(pType)
            self.keyvalues["options"] = self.createKey("options")
            self.keyvalues["users"] = self.createKey("users")
            self.keyvalues["variables"] = self.createKey("variables")
            self.keyvalues["variables"]["global"] = self.createKey("global")
            self.save()
    def delete(self):
        #delete this setting, calls global delete function
        delete(self.name)
    def clear(self, timestamp=None):
        if timestamp:
            timediff = int(time.time()) - int(timestamp)
            for steamid in self.keyvalues["users"]:
                if int(str(self.keyvalues["users"][str(steamid)]["time"])) < int(timediff):
                    del self.keyvalues["users"][str(steamid)]
        else:
            for steamid in self.keyvalues["users"]:
                del self.keyvalues["users"][str(steamid)]
        for option in self.keyvalues["options"]:
            state = self.keyvalues["options"][str(option)]["state"]
            self.keyvalues["options"][str(option)]["globstate"] = bool(state)
        for steamid in self.keyvalues["variables"]:
            for variable in self.keyvalues["variables"][str(steamid)]:
                del self.keyvalues["variables"][str(steamid)][str(variable)]
    def save(self):
        if self.filetype == 'keyvalues':
            self.keyvalues.save(self.filename)
        elif self.filetype == 'dict':
            pickle_file = open(self.filename, 'wb')
            pickle.dump(self.keyvalues, pickle_file)
            pickle_file.flush()
            pickle_file.close()
    def saveToFile(self, filename, overwriteFilename=False):
        #this method is only for advanced users!
        if self.filetype == 'keyvalues':
            self.keyvalues.save(filename)
        elif self.filetype == 'dict':
            pickle_file = open(filename, 'wb')
            pickle.dump(self.keyvalues, pickle_file)
            pickle_file.flush()
            pickle_file.close()
        if overwriteFilename == True:
            self.filename = filename
    def load(self):
        if self.filetype == 'keyvalues':
            self.keyvalues.load(self.filename)
        elif self.filetype == 'dict':
            pickle_file = open(self.filename, 'rb')
            pickle_file.seek(0)
            self.keyvalues = pickle.load(pickle_file)
            pickle_file.close()
    def loadFromFile(self, filename, overwriteFilename=False):
        #this method is only for advanced users!
        if self.filetype == 'keyvalues':
            self.keyvalues.load(filename)
        elif self.filetype == 'dict':
            pickle_file = open(filename, 'rb')
            pickle_file.seek(0)
            self.keyvalues = pickle.load(pickle_file)
            pickle_file.close()
        if overwriteFilename == True:
            self.filename = filename
    def createKey(self, name):
        if self.filetype == 'keyvalues':
            return keyvalues.KeyValues(name=str(name))
        elif self.filetype == 'dict':
            return {}
        else:
            return None
    def send(self, pUsers, prio=False, locked=False):
        raise NotImplemented #type specific
    def sendglobal(self, pUsers, prio=False, locked=False):
        raise NotImplemented #type specific
    def information(self, listlevel):
        if listlevel >= 1:
            es.dbgmsg(0, " ")
        es.dbgmsg(0, self.name)
        if listlevel >= 1:
            es.dbgmsg(0, "  Description:  "+str(self.keyvalues["config"]["descr"]))
            es.dbgmsg(0, "  Re-Send:      "+str(self.keyvalues["config"]["resend"]))
            es.dbgmsg(0, "  Soundfile:    "+str(self.keyvalues["config"]["sound"]))
        if listlevel >= 2:
            es.dbgmsg(0, "  Players:      "+str(len(self.keyvalues["users"].keys())))
            es.dbgmsg(0, "  Options:      "+str(len(self.keyvalues["options"].keys())))
            for option in self.keyvalues["options"]:
                es.dbgmsg(0,"    ["+str(option)+"]["+str(self.keyvalues["options"][str(option)]["keyname"])+"]:  "+self.keyvalues["options"][str(option)]["display"])
    def isValidOption(self, option):      #checks for valid options numbers
        if type(option) == int:
            if (option < 1): return False
            if (option > len(self.keyvalues["options"].keys())): return False
            return option
        else:
            for thisoption in self.keyvalues["options"]:
                if option == str(self.keyvalues["options"][str(thisoption)]["keyname"]):
                    return thisoption
            return False
    def initUser(self, userid):
        if es.exists('userid',userid):
            steamid = playerlib.uniqueid(userid, True)
            self.keyvalues["users"][steamid] = self.createKey(steamid)
            self.keyvalues["users"][steamid]["time"] = int(time.time())
            self.keyvalues["users"][steamid]["data"] = self.createKey("data")
            for option in self.keyvalues["options"]:
                self.keyvalues["users"][steamid]["data"][str(option)] = self.createKey(str(option))
                self.keyvalues["users"][steamid]["data"][str(option)]["state"] = self.keyvalues["options"][str(option)]["state"]
    def updateTime(self, userid):
        if es.exists('userid',userid):
            steamid = playerlib.uniqueid(userid, True)
            if steamid in self.keyvalues["users"]:
                self.keyvalues["users"][steamid]["time"] = int(time.time())
            else:
                self.initUser(userid)
    def menuUserSubmit(self, userid, value):
        raise NotImplemented #type specific
    def menuUserGlobalSubmit(self, userid, value):
        raise NotImplemented #type specific
    def settitle(self, text):             #set the description of the setting (old method name)
        self.setdescription(text)
    def setdescription(self, text):       #set the description of the setting
        self.descr = text
        self.keyvalues["config"]["descr"] = text
        self.save()
    def resend(self, resend):
        if resend:
            self.keyvalues["config"]["resend"] = True
        else:
            self.keyvalues["config"]["resend"] = False
        self.save()
    def setoption(self):    #edit/add an option
        raise NotImplemented #type specific
    def addoption(self):            #add an option to the end of the list
        raise NotImplemented #type specific
    def deloption(self):          #delete an option
        raise NotImplemented #type specific
    def setdefault(self):
        raise NotImplemented #type specific
    def get(self):
        raise NotImplemented #type specific
    def set(self):
        raise NotImplemented #type specific
    def clearoption(self):
        optionlist = []
        for option in self.keyvalues["options"]:
            optionlist.append(int(option))
        while optionlist:
            option = optionlist.pop()
            if option and self.isValidOption(option):
                self.deloption(option)
    def addsound(self, sound):            #add a sound file
        self.keyvalues["config"]["sound"] = sound
        self.save()
    def delsound(self):                   #delete a sound file
        self.keyvalues["config"]["sound"] = None
        self.save()
    def setvar(self, variable, value, userid=None):
        if userid:
            if es.exists('userid',userid):
                steamid = playerlib.uniqueid(userid, True)
                if not steamid in self.keyvalues["users"]:
                    self.initUser(int(userid))
            else:
                raise IndexError("Settinglib: Cannot find userid '%s', it does not exists"%userid)
        else:
            steamid = "global"
        self.keyvalues["variables"][str(steamid)][str(variable)] = value
        self.save()
    def getvar(self, variable, userid=None):
        if userid:
            if es.exists('userid',userid):
                steamid = playerlib.uniqueid(userid, True)
                if not steamid in self.keyvalues["users"]:
                    self.initUser(int(userid))
            else:
                raise IndexError("Settinglib: Cannot find userid '%s', it does not exists"%userid)
        else:
            steamid = "global"
        return self.keyvalues["variables"][str(steamid)][str(variable)]
    def backmenu(self, backmenu):
        if popuplib.exists(backmenu):
            for page in self.popup:
                self.popup[page].submenu(10, backmenu)
            self.backmenuvar = backmenu
            es.dbgmsg(1, "Settinglib: Set backmenu of '"+str(self.name)+"' to popup '"+str(self.backmenuvar)+"'")
            return True
        elif keymenulib.exists(backmenu):
            keymenu = keymenulib.find(backmenu)
            for page in self.popup:
                self.popup[page].submenu(10, keymenu.popup.name)
            self.backmenuvar = keymenu.popup.name
            es.dbgmsg(1, "Settinglib: Set backmenu of '"+str(self.name)+"' to popup '"+str(self.backmenuvar)+"'")
            return True
        else:
            es.dbgmsg(0, "setting: Could not set backmenu of '"+str(self.name)+"' to '"+str(backmenu)+"'")
            return False

# Import the used sub-classes
import settinglib.list
import settinglib.toggle

#setting commands begin here
#usage from other Python scripts for example:
#  import es
#  import setting
#  a = setting.create("insertnamehere", "My Setting", "list")
def create(pSettingid, pDescription, pType="list", pFilename=None, pFiletype='dict'):
    #check for pickle problems
    if pFiletype == 'dict':
        try:
            pickle_file = open(selfdatatest, 'wb')
            pickle.dump(range(1, 10), pickle_file)
            pickle_file.flush()
            pickle_file.close()
            pickle_file = open(selfdatatest, 'rb')
            pickle_file.seek(0)
            pickle_test = pickle.load(pickle_file)
            pickle_file.close()
            os.remove(selfdatatest)
            if len(pickle_test) != len(range(1, 10)):
                pFiletype = 'keyvalues'
        except:
            pFiletype = 'keyvalues'
    #create new setting
    if pType == 'list':
        gSettings[pSettingid] = list.Setting_list(pSettingid, pDescription, pFilename, pFiletype)
    elif pType == 'toggle':
        gSettings[pSettingid] = toggle.Setting_toggle(pSettingid, pDescription, pFilename, pFiletype)
    else:
        return None
    return gSettings[pSettingid]
    
def free(pSettingid):
    #free a setting
    if (pSettingid in gSettings):
        if os.path.exists(gSettings[pSettingid].filename):
            os.remove(gSettings[pSettingid].filename)
        del gSettings[pSettingid]
    else:
        raise ValueError("Settinglib: Cannot free setting %s, it does not exists"%pSettingid)

def delete(pSettingid):
    #delete a setting
    if (pSettingid in gSettings):
        del gSettings[pSettingid]
    else:
        raise ValueError("Settinglib: Cannot delete setting %s, it does not exists"%pSettingid)

def exists(pSettingid):
    #does named setting exist
    return (pSettingid in gSettings)

def find(pSettingid):
    #return class instance of named popup
    if (pSettingid in gSettings):
        return gSettings[pSettingid]
    return None

def send(pSettingid, pUserid, prio=False):
    #send a named setting to user/users
    if pSettingid in gSettings:
        gSettings[pSettingid].send(pUserid,prio)
    else:
        raise ValueError("Settinglib: Cannot send setting %s, it does not exists"%pSettingid)

def sendGlobal(pSettingid, pUserid, prio=False):
    #send a named setting to user/users
    if pSettingid in gSettings:
        gSettings[pSettingid].sendGlobal(pUserid,prio)
    else:
        raise ValueError("Settinglib: Cannot send setting %s, it does not exists"%pSettingid)

###################
#Helper functions #
###################

def _submit(userid, value, popupid):
    es.dbgmsg(1, "Settinglib: _submit("+str(userid)+", "+str(value)+", "+str(popupid)+")")
    page = popuplib.find(popupid)
    if page.settingid in gSettings:
        gSettings[page.settingid].menuUserSubmit(userid, value)
    else:
        raise ValueError("Settinglib: Invalid setting %s submitted from popup"%page.settingid)

def _submitGlobal(userid, value, popupid):
    es.dbgmsg(1, "Settinglib: _submitGlobal("+str(userid)+", "+str(value)+", "+str(popupid)+")")
    page = popuplib.find(popupid)
    if page.settingid in gSettings:
        gSettings[page.settingid].menuUserGlobalSubmit(userid, value)
    else:
        raise ValueError("Settinglib: Invalid setting %s submitted from popup"%page.settingid)
        

def _saveTicker():
    gamethread.delayed(300, _saveTicker, ())
    for setting in gSettings:
        gSettings[setting].save()
        
def _saveAll():
    for setting in gSettings:
        gSettings[setting].save()
                    
######################
#EventScripts events #
######################

def es_map_start(event_var):
    gamethread.delayed(300, _saveTicker, ())    

def player_activate(event_var):
    userid = int(event_var['userid'])
    steamid = playerlib.uniqueid(userid, True)
    for setting in gSettings:
        if not steamid in gSettings[setting].keyvalues["users"]:
            gSettings[setting].initUser(userid)
        gSettings[setting].updateTime(userid)

# Register for custom events
es.addons.registerForEvent(selfmodule, 'es_map_start', es_map_start)
es.addons.registerForEvent(selfmodule, 'player_activate', player_activate)
