################################################################################
#      Copyright (C) 2019 drinfernoo                                           #
#                                                                              #
#  This Program is free software; you can redistribute it and/or modify        #
#  it under the terms of the GNU General Public License as published by        #
#  the Free Software Foundation; either version 2, or (at your option)         #
#  any later version.                                                          #
#                                                                              #
#  This Program is distributed in the hope that it will be useful,             #
#  but WITHOUT ANY WARRANTY; without even the implied warranty of              #
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                #
#  GNU General Public License for more details.                                #
#                                                                              #
#  You should have received a copy of the GNU General Public License           #
#  along with XBMC; see the file COPYING.  If not, write to                    #
#  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.       #
#  http://www.gnu.org/copyleft/gpl.html                                        #
################################################################################

import xbmc
import xbmcgui
import xbmcvfs

import glob
import os
import re
try:  # Python 3
    import zipfile
except ImportError:  # Python 2
    from resources.libs import zipfile

from sqlite3 import dbapi2 as database

from datetime import datetime

from resources.libs.common.config import CONFIG
from resources.libs.common import logging
from resources.libs.common import tools
from xml.dom.minidom import parse


def addon_database(addon=None, state=1, array=False):
    dbfile = latest_db('Addons')
    dbfile = os.path.join(CONFIG.DATABASE, dbfile)
    installedtime = str(datetime.now())[:-7]

    if os.path.exists(dbfile):
        try:
            textdb = database.connect(dbfile)
            textexe = textdb.cursor()
        except Exception as e:
            logging.log("DB Connection Error: {0}".format(str(e)), level=xbmc.LOGERROR)
            return False
    else:
        return False

    if state == 2:
        try:
            textexe.execute("DELETE FROM installed WHERE addonID = ?", (addon,))
            textdb.commit()
            textexe.close()
        except:
            logging.log("Error Removing {0} from DB".format(addon))
        return True

    try:
        if not array:
            textexe.execute('INSERT or IGNORE into installed (addonID , enabled, installDate) VALUES (?,?,?)', (addon, state, installedtime,))
            textexe.execute('UPDATE installed SET enabled = ? WHERE addonID = ? ', (state, addon,))
        else:
            for item in addon:
                textexe.execute('INSERT or IGNORE into installed (addonID , enabled, installDate) VALUES (?,?,?)', (item, state, installedtime,))
                textexe.execute('UPDATE installed SET enabled = ? WHERE addonID = ? ', (state, item,))
        textdb.commit()
        textexe.close()
    except:
        logging.log("Erroring enabling addon: {0}".format(addon))


def latest_db(db):
    if db in CONFIG.DB_FILES:
        match = glob.glob(os.path.join(CONFIG.DATABASE, '{0}*.db'.format(db)))
        comp = '{0}(.+?).db'.format(db[1:])
        highest = 0
        for file in match:
            try:
                check = int(re.compile(comp).findall(file)[0])
            except:
                check = 0
            if highest < check:
                highest = check
        return '{0}{1}.db'.format(db, highest)
    else:
        return False
        
        
def force_check_updates(auto=False, over=False):
    import time
    
    if not over:
        logging.log_notify(CONFIG.ADDONTITLE,
                           '[COLOR {0}]Force Checking for Updates[/COLOR]'.format(CONFIG.COLOR2))

    dbfile = latest_db('Addons')
    dbfile = os.path.join(CONFIG.DATABASE, dbfile)
    sqldb = database.connect(dbfile)
    sqlexe = sqldb.cursor()
    
    # force rollback all installed repos
    sqlexe.execute("UPDATE repo SET version = ?, checksum = ?, lastcheck = ?", ('', '', '',))
    sqldb.commit()

    # trigger kodi to check them for updates
    xbmc.executebuiltin('UpdateAddonRepos')

    # wait until they have finished updating
    with tools.busy_dialog():
        installed_repos = sqlexe.execute('SELECT addonID FROM repo')

        start_time = time.time()
        checked_time = 0.1
        for repo in installed_repos.fetchall():
            repo = repo[0]
            logging.log('Force checking {0}...'.format(repo), level=xbmc.LOGDEBUG)
            while checked_time < start_time:
                if time.time() >= start_time + 20:
                    logging.log('{0} timed out during repo force check.'.format(repo), level=xbmc.LOGDEBUG)
                    break
                
                lastcheck = sqlexe.execute('SELECT lastcheck FROM repo WHERE addonID = ?', (repo,))
                
                if lastcheck:
                    checked_time = lastcheck.fetchone()[0]
                    if checked_time:
                        checked_time = time.mktime(time.strptime(checked_time, '%Y-%m-%d %H:%M:%S'))
                    
                xbmc.sleep(1000)
            checked_time = 0
            logging.log('{0} successfully force checked.'.format(repo), level=xbmc.LOGDEBUG)
            logging.log_notify('[COLOR {0}]{1}[/COLOR]'.format(CONFIG.COLOR1, CONFIG.ADDONTITLE),
                               "[COLOR {0}]{1} successfully force checked.[/COLOR]".format(CONFIG.COLOR2, repo))
            
    sqlexe.close()
                    
    if auto:
        xbmc.executebuiltin('UpdateLocalAddons')


def purge_db_file(name):
    logging.log('Purging DB {0}.'.format(name))
    if os.path.exists(name):
        try:
            textdb = database.connect(name)
            textexe = textdb.cursor()
        except Exception as e:
            logging.log("DB Connection Error: {0}".format(str(e)), level=xbmc.LOGERROR)
            return False
    else:
        logging.log('{0} not found.'.format(name), level=xbmc.LOGERROR)
        return False
    textexe.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
    for table in textexe.fetchall():
        if table[0] == 'version':
            logging.log('Data from table `{0}` skipped.'.format(table[0]))
        else:
            try:
                textexe.execute("DELETE FROM {0}".format(table[0]))
                textdb.commit()
                logging.log('Data from table `{0}` cleared.'.format(table[0]))
            except Exception as e:
                logging.log("DB Remove Table `{0}` Error: {1}".format(table[0], str(e)), level=xbmc.LOGERROR)
    textexe.close()
    logging.log('{0} DB Purging Complete.'.format(name))
    show = name.replace('\\', '/').split('/')
    logging.log_notify("[COLOR {0}]Purge Database[/COLOR]".format(CONFIG.COLOR1),
                       "[COLOR {0}]{1} Complete[/COLOR]".format(CONFIG.COLOR2, show[len(show)-1]))


def depends_list(plugin):
    addonxml = os.path.join(CONFIG.ADDONS, plugin, 'addon.xml')
    if os.path.exists(addonxml):

        match  = tools.parse_dom(tools.read_from_file(addonxml), 'import', ret='addon')
        items  = []
        for depends in match:
            if not 'xbmc.python' in depends:
                items.append(depends)
        return items
    return []


def purge_db():
    dialog = xbmcgui.Dialog()

    DB = []
    display = []
    for dirpath, dirnames, files in os.walk(CONFIG.HOME):
        import fnmatch

        for f in fnmatch.filter(files, '*.db'):
            if f != 'Thumbs.db':
                found = os.path.join(dirpath, f)
                DB.append(found)
                dir = found.replace('\\', '/').split('/')
                display.append('({0}) {1}'.format(dir[len(dir)-2], dir[len(dir)-1]))
    choice = dialog.multiselect("[COLOR {0}]Select DB File to Purge[/COLOR]".format(CONFIG.COLOR2), display)
    if choice is None or len(choice) == 0:
        logging.log_notify("[COLOR {0}]Purge Database[/COLOR]".format(CONFIG.COLOR1),
                           "[COLOR {0}]Cancelled[/COLOR]".format(CONFIG.COLOR2))
    else:
        for purge in choice:
            purge_db_file(DB[purge])


def kodi_17_fix():
    from resources.libs.common import tools
    from resources.libs import update

    addonlist = glob.glob(os.path.join(CONFIG.ADDONS, '*/'))
    disabledAddons = []
    for folder in sorted(addonlist, key=lambda x: x):
        addonxml = os.path.join(folder, 'addon.xml')
        if os.path.exists(addonxml):
            fold = folder.replace(CONFIG.ADDONS, '')[1:-1]
            aid = tools.parse_dom(tools.read_from_file(addonxml), 'addon', ret='id')
            try:
                if len(aid) > 0:
                    addonid = aid[0]
                else:
                    addonid = fold
            except:
                try:
                    logging.log("{0} was disabled".format(aid[0]))
                    disabledAddons.append(addonid)
                except:
                    logging.log("Unable to enable: {0}".format(folder), level=xbmc.LOGERROR)
    if len(disabledAddons) > 0:
        addon_database(disabledAddons, 1, True)
        logging.log_notify(CONFIG.ADDONTITLE,
                           "[COLOR {0}]Enabling Addons Complete![/COLOR]".format(CONFIG.COLOR2))
    xbmc.executebuiltin("UpdateLocalAddons()")
    xbmc.executebuiltin("ReloadSkin()")


def toggle_addon(id, value, over=None):
    from resources.libs.common import tools

    from xml.etree import ElementTree

    logging.log("Toggling {0}".format(id))
    addonid = id
    addonxml = os.path.join(CONFIG.ADDONS, id, 'addon.xml')
    if os.path.exists(addonxml):
        root = ElementTree.parse(addonxml).getroot()
        tid = root.get('id')
        tname = root.get('name')
        tservice = root.find('extension').get('point')
        
        try:
            if len(tid) > 0:
                addonid = tid
            if tservice == 'xbmc.service':
                logging.log("We got a live one, stopping script: {0}".format(tid))
                xbmc.executebuiltin('StopScript({0})'.format(os.path.join(CONFIG.ADDONS, addonid)))
                xbmc.executebuiltin('StopScript({0})'.format(addonid))
                xbmc.executebuiltin('StopScript({0})'.format(os.path.join(CONFIG.ADDONS, addonid, tservice[0])))
                xbmc.sleep(500)
        except:
            pass
            
    query = '{{"jsonrpc":"2.0", "method":"Addons.SetAddonEnabled","params":{{"addonid":"{0}","enabled":{1}}}, "id":1}}'.format(addonid, value)
    response = xbmc.executeJSONRPC(query)
    
    if 'error' in response and over is None:
        from resources.libs import update
        
        dialog = xbmcgui.Dialog()
        
        v = 'Enabling' if value == 'true' else 'Disabling'
        dialog.ok(CONFIG.ADDONTITLE,
                      "[COLOR {0}]Error {1} [COLOR {2}]{3}[/COLOR]".format(CONFIG.COLOR2, v, CONFIG.COLOR1, id),
                      "Check to make sure the add-on list is up to date and try again.[/COLOR]")
        update.force_update()


def toggle_dependency(name, dp=None):
    from resources.libs.common import tools

    dep = os.path.join(CONFIG.ADDONS, name, 'addon.xml')
    if os.path.exists(dep):
        match = tools.parse_dom(tools.read_from_file(dep), 'import', ret='addon')
        for depends in match:
            if 'xbmc.python' not in depends:
                dependspath = os.path.join(CONFIG.ADDONS, depends)
                if dp is not None:
                    dp.update("",
                              "Checking Dependency [COLOR yellow]{0}[/COLOR] for [COLOR yellow]{1}[/COLOR]".format(depends, name),
                              "")
                if os.path.exists(dependspath):
                    toggle_addon(name, 'true')
            xbmc.sleep(100)


# NOT CURRENTLY IN USE, BROKEN DUE TO DEAD NaN LINK
# def toggle_adult():
#     from resources.libs import gui
#     from resources.libs.common import tools
#
#     do = gui.DIALOG.yesno(CONFIG.ADDONTITLE,
#                           "[COLOR {0}]Would you like to [COLOR {1}]Enable[/COLOR] or [COLOR {2}]Disable[/COLOR] all Adult add-ons?[/COLOR]".format(CONFIG.COLOR2, CONFIG.COLOR1, CONFIG.COLOR1),
#                           yeslabel="[B][COLOR springgreen]Enable[/COLOR][/B]",
#                           nolabel="[B][COLOR blue]Disable[/COLOR][/B]")
#     state = 'true' if do == 1 else 'false'
#     goto = 'Enabling' if do == 1 else 'Disabling'
#     link = tools.open_url('http://noobsandnerds.com/TI/AddonPortal/adult.php').replace('\n', '').replace('\r', '').replace('\t', '')
#     list = re.compile('i="(.+?)"').findall(link)
#     found = []
#     for item in list:
#         fold = os.path.join(CONFIG.ADDONS, item)
#         if os.path.exists(fold):
#             found.append(item)
#             toggle_addon(item, state, True)
#             logging.log("[Toggle Adult] {0} {1}".format(goto, item))
#     if len(found) > 0:
#         if gui.DIALOG.yesno(CONFIG.ADDONTITLE,
#                             "[COLOR {0}]Would you like to view a list of the add-ons that where {1}?[/COLOR]".format(CONFIG.COLOR2, goto.replace('ing', 'ed')),
#                             yeslabel="[B][COLOR springgreen]View List[/COLOR][/B]",
#                             nolabel="[B][COLOR blue]Cancel[/COLOR][/B]"):
#             editlist = '[CR]'.join(found)
#             gui.show_text_box(CONFIG.ADDONTITLE,
#                               "[COLOR {0}]Here are a list of the add-ons that where {1} for Adult Content:[/COLOR][CR][CR][COLOR {2}]{3}[/COLOR]".format(CONFIG.COLOR1, goto.replace('ing', 'ed'), CONFIG.COLOR2, editlist))
#         else:
#             logging.log_notify("[COLOR {0}]{1}[/COLOR]".format(CONFIG.COLOR1, CONFIG.ADDONTITLE),
#                                "[COLOR {0}[COLOR {1}]{2}[/COLOR] Adult Addons {3}[/COLOR]".format(CONFIG.COLOR2, CONFIG.COLOR1, count, goto.replace('ing', 'ed')))
#         from resources.libs import update
#         update.force_update(True)
#     else:
#         logging.log_notify("[COLOR {0}]{1}[/COLOR]".format(CONFIG.COLOR1, CONFIG.ADDONTITLE),
#                            "[COLOR {0}]No Adult Addons Found[/COLOR]".format(CONFIG.COLOR2))


def create_temp(plugin):
    from resources.libs.common import tools

    temp = os.path.join(CONFIG.PLUGIN, 'resources', 'tempaddon.xml')
    r = tools.read_from_file(temp)
    plugdir = os.path.join(CONFIG.ADDONS, plugin)
    if not os.path.exists(plugdir):
        os.makedirs(plugdir)

    tools.write_to_file(os.path.join(plugdir, 'addon.xml'), r.replace('testid', plugin).replace('testversion', '0.0.1'))
    logging.log("{0}: wrote addon.xml".format(plugin))


def fix_metas():
    from resources.libs.common import tools

    idlist = []
    for item in idlist:
        fold = os.path.join(CONFIG.ADDOND, item)
        if os.path.exists(fold):
            storage = os.path.join(fold, '.storage')
            if os.path.exists(storage):
                tools.clean_house(storage)
                tools.remove_folder(storage)


# def hide_password():
#     from resources.libs.common import tools
#     from resources.libs.common import logging
#
#     dialog = xbmcgui.Dialog()
#
#     if dialog.yesno(CONFIG.ADDONTITLE,
#                         "[COLOR {0}]Would you like to [COLOR {1}]hide[/COLOR] all passwords when typing in the add-on settings menus?[/COLOR]".format(CONFIG.COLOR2),
#                         yeslabel="[B][COLOR springgreen]Hide Passwords[/COLOR][/B]",
#                         nolabel="[B][COLOR blue]No Cancel[/COLOR][/B]"):
#         count = 0
#         for folder in glob.glob(os.path.join(CONFIG.ADDONS, '*/')):
#             sett = os.path.join(folder, 'resources', 'settings.xml')
#             if os.path.exists(sett):
#                 f = tools.read_from_file(sett)
#                 match = tools.parse_dom(f, 'addon', ret='id')
#                 for line in match:
#                     if 'pass' in line:
#                         if 'option="hidden"' not in line:
#                             try:
#                                 change = line.replace('/', 'option="hidden" /')
#                                 f.replace(line, change)
#                                 count += 1
#                                 logging.log("[Hide Passwords] found in {0} on {1}".format(sett.replace(CONFIG.HOME, ''), line))
#                             except:
#                                 pass
#                 tools.write_to_file(sett, f)
#         logging.log_notify("[COLOR {0}]Hide Passwords[/COLOR]".format(CONFIG.COLOR1),
#                            "[COLOR {0}]{1} items changed[/COLOR]".format(CONFIG.COLOR2, count))
#         logging.log("[Hide Passwords] {0} items changed".format(count))
#     else:
#         logging.log("[Hide Passwords] Cancelled")
#
#
# def unhide_password():
#     from resources.libs.common import tools
#     from resources.libs.common import logging
#
#     dialog = xbmcgui.Dialog()
#
#     if dialog.yesno(CONFIG.ADDONTITLE,
#                         "[COLOR {0}]Would you like to [COLOR {1}]unhide[/COLOR] all passwords when typing in the add-on settings menus?[/COLOR]".format(CONFIG.COLOR2, CONFIG.COLOR1),
#                         yeslabel="[B][COLOR springgreen]Unhide Passwords[/COLOR][/B]",
#                         nolabel="[B][COLOR blue]No Cancel[/COLOR][/B]"):
#         count = 0
#         for folder in glob.glob(os.path.join(CONFIG.ADDONS, '*/')):
#             sett = os.path.join(folder, 'resources', 'settings.xml')
#             if os.path.exists(sett):
#                 f = tools.read_from_file(sett)
#                 match = tools.parse_dom(f, 'addon', ret='id')
#                 for line in match:
#                     if 'pass' in line:
#                         if 'option="hidden"' in line:
#                             try:
#                                 change = line.replace('option="hidden"', '')
#                                 f.replace(line, change)
#                                 count += 1
#                                 logging.log("[Unhide Passwords] found in {0} on {1}".format(sett.replace(CONFIG.HOME, ''), line))
#                             except:
#                                 pass
#                 tools.write_to_file(sett, f)
#         logging.log_notify("[COLOR {0}]Unhide Passwords[/COLOR]".format(CONFIG.COLOR1),
#                            "[COLOR {0}]{1} items changed[/COLOR]".format(CONFIG.COLOR2, count))
#         logging.log("[Unhide Passwords] {0} items changed".format(count))
#     else:
#         logging.log("[Unhide Passwords] Cancelled")


def fix_update():
    if os.path.exists(os.path.join(CONFIG.USERDATA, 'autoexec.py')):
        temp = os.path.join(CONFIG.USERDATA, 'autoexec_temp.py')
        if os.path.exists(temp):
            xbmcvfs.delete(temp)
        xbmcvfs.rename(os.path.join(CONFIG.USERDATA, 'autoexec.py'), temp)
    xbmcvfs.copy(os.path.join(CONFIG.PLUGIN, 'resources', 'libs', 'autoexec.py'),
                 os.path.join(CONFIG.USERDATA, 'autoexec.py'))
    dbfile = os.path.join(CONFIG.DATABASE, latest_db('Addons'))
    try:
        os.remove(dbfile)
    except:
        logging.log("Unable to remove {0}, Purging DB".format(dbfile))
        purge_db_file(dbfile)

    from resources.libs.common import tools
    tools.kill_kodi(over=True)


def grab_addons(path):
    zfile = zipfile.ZipFile(path, allowZip64=True)
    addonlist = []
    for item in zfile.infolist():
        if str(item.filename).find('addon.xml') == -1:
            continue
        info = str(item.filename).split('/')
        if not info[-2] in addonlist:
            addonlist.append(info[-2])
    return addonlist

    
def find_binary_addons(addon='all'):
    from xml.etree import ElementTree
    
    dialog = xbmcgui.Dialog()
    logging.log('Checking {} for platform-dependence...'.format(addon), level=xbmc.LOGDEBUG)
    
    if addon == 'all':
        addonfolders = glob.iglob(os.path.join(CONFIG.ADDONS, '*/'))
        addonids = []
        addonnames = []
        
        for folder in addonfolders:
            foldername = os.path.split(folder[:-1])[1]
            
            if foldername in CONFIG.EXCLUDES:
                continue
            elif foldername in CONFIG.DEFAULTPLUGINS:
                continue
            elif foldername == 'packages':
                continue    
            
            xml = os.path.join(folder, 'addon.xml')
            
            if os.path.exists(xml):
                root = ElementTree.parse(xml).getroot()
                addonid = root.get('id')
                addonname = root.get('name')
                extension = root.find('extension')
                
                try:
                    ext_attrs = extension.keys()
                except:
                    continue
                
                for attr in ext_attrs:
                    if attr.startswith('library_'):
                        try:
                            addonnames.append(addonname)
                            addonids.append(addonid)
                        except:
                            pass
        
        dialog.ok(CONFIG.ADDONTITLE, "[COLOR {0}]Found [COLOR {1}]{2}[/COLOR] platform-specific addons installed:[/COLOR]".format(CONFIG.COLOR2, CONFIG.COLOR1, len(addonnames)), "[COLOR {0}]{1}[/COLOR]".format(CONFIG.COLOR1, addonnames))
        
        return addonids, addonnames
    else:
        if addon in CONFIG.EXCLUDES:
            return None, None
        elif addon in CONFIG.DEFAULTPLUGINS:
            return None, None
        
        xml = os.path.join(CONFIG.ADDONS, addon, 'addon.xml')
        
        if os.path.exists(xml):
            logging.log('Checking {0}'.format(xml), level=xbmc.LOGINFO)
            root = parse(xml)
            tag = root.documentElement
            addonid = tag.getAttribute('id')
            addonname = tag.getAttribute('name')
            extension = tag.getAttribute('extension')
            
            try:
                ext_attrs = extension.keys()
            except:
                return None, None
            
            for attr in ext_attrs:
                if attr.startswith('library_'):
                    return addonid, addonname
                        
        return None, None
        
#########################################################
#         PARTE DE ESTE CÓDIGO FUE TOMADO DE CHIKIRY    #
#                A QUIEN DAMOS LAS GRACIAS              #
#########################################################