# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Arne Svenson
#
# 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 3 of the License, 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 this program.  If not, see <http://www.gnu.org/licenses/>.

# from __future__ import unicode_literals

import os
import xbmc
import xbmcvfs
import threading
from types import DictionaryType

try:
    from sqlite3 import dbapi2 as database
except:
    from pysqlite2 import dbapi2 as database

from koditidal import addon, debug


METACACHE_DIR = xbmc.translatePath(addon.getAddonInfo('profile').decode('utf-8'))
METACACHE_FILE = 'metaCache.db'  # SQlite DB for cach data
CACHE_ALBUMS = True
CACHE_PLAYLISTS = True


class MetaCache(object):

    dbcon = None
    currentThreadId = None

    def __init__(self):
        self.currentThreadId = threading.currentThread()

    def connect(self):
        self.path = os.path.join(METACACHE_DIR, METACACHE_FILE)
        try:
            self.dbcon = database.connect(self.path)
            dbcur = self.dbcon.cursor()
            dbcur.execute("CREATE TABLE IF NOT EXISTS meta (""type TEXT, ""id TEXT, ""data TEXT, ""created DATE, ""UNIQUE(type, id)"");")
            self.dbcon.commit()
        except Exception, e:
            debug.logException(e)

    def close(self):
        if self.dbcon:
            try:
                self.dbcon.close()
                self.dbcon = None
            except:
                pass

    def fetch(self, item_type, item_id, default=None):
        item = default
        try:
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            dbcur.execute("SELECT * FROM meta WHERE (type = '%s' and id = '%s')" % (item_type, item_id))
            match = dbcur.fetchone()
            if match:
                item = eval(match[2])
        except Exception, e:
            debug.logException(e, txt='Error in fetch(%s,%s)' % (item_type, item_id))
        return item

    def fetchAllData(self, item_type):
        items = []
        try:
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            dbcur.execute("SELECT * FROM meta WHERE type = '%s'" % item_type)
            matchall = dbcur.fetchall()
            for match in matchall:
                items.append(eval(match[2]))
        except Exception, e:
            debug.logException(e, txt='Error in fetchAllData(%s)' % item_type)
        return items

    def fetchAllIds(self, item_type):
        items = []
        try:
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            dbcur.execute("SELECT id FROM meta WHERE type = '%s'" % item_type)
            matchall = dbcur.fetchall()
            for match in matchall:
                items.append(match[0])
        except Exception, e:
            debug.logException(e, txt='Error in fetchAllIds(%s)' % item_type)
        return items

    def insert(self, item_type, item_id, data, overwrite=False):
        ok = False
        try:
            if item_type == 'favorites':
                debug.log('MetaCache: Inserting %s Favorite %s' % (len(data), item_id))
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            i = repr(data)
            try: 
                if overwrite:
                    dbcur.execute("INSERT OR REPLACE INTO meta Values (?, ?, ?, DATE('now'))", (item_type, item_id, i))
                else:
                    dbcur.execute("INSERT INTO meta Values (?, ?, ?, DATE('now'))", (item_type, item_id, i))
                ok = True
            except database.IntegrityError:
                ok = False
            except:
                debug.log('Failed: INSERT INTO meta Values type="%s", id="%s", data="%s"' % (item_type, item_id, i), level=xbmc.LOGERROR)
                ok = False
            self.dbcon.commit()
        except Exception, e:
            debug.logException(e, txt='Error in insert(%s,%s)' % (item_type, item_id))
        return ok

    def getAlbumJson(self, album_id, checkMasterAlbum=False):
        json_obj = self.fetch('album', '%s' % album_id)
        #if isinstance(json_obj, DictionaryType):
        #    json_obj.update({'_cached': True, '_mqa': False if not checkMasterAlbum else self.isMasterAlbum(album_id)})
        return json_obj

    def insertAlbumJson(self, json_obj):
        if CACHE_ALBUMS and json_obj.get('id') and json_obj.get('releaseDate'):
            self.insert('album', '%s' % json_obj.get('id'), json_obj, overwrite=True)
            if json_obj.get('numberOfVideos', 0) > 0:
                self.insert('album_with_videos', '%s' % json_obj.get('id'), json_obj, overwrite=True)
            #if json_obj.get('_mqa', False):
            #    self.insertMasterAlbumId(json_obj.get('id'))
            json_obj.update({'_cached': True})

    #def insertMasterAlbumId(self, album_id):
    #    success = self.insert('master_album', '%s' % album_id, '%s' % album_id, overwrite=False)
    #    # debug.log('Inserting Master Album ID %s: %s' % (album_id, success))
    #    return success

    #def deleteMasterAlbumId(self, album_id):
    #    success = True
    #    if self.isMasterAlbum(album_id):
    #        success = self.delete('master_album', '%s' % album_id)
    #        # debug.log('Deleting Master Album ID %s: %s' % (album_id, success))
    #    return success

    #def isMasterAlbum(self, album_id):
    #    master_album_id = self.fetch('master_album', '%s' % album_id)
    #    isMaster = True if master_album_id and '%s' % master_album_id == '%s' % album_id else False 
    #    # debug.log('Checking Master Album ID %s: %s' % (album_id, isMaster))
    #    return isMaster

    def deleteOldMasterAlbums(self):
        allIds = self.fetchAllIds('master_album')
        deletedMasterAlbums = 0
        deletedAlbums = 0
        for nextId in allIds:
            if self.delete('master_album', '%s' % nextId):
                deletedMasterAlbums += 1
            if self.delete('album', '%s' % nextId):
                deletedAlbums += 1
        debug.log('Deleted %s old Master Albums from Cache.' % deletedMasterAlbums)
        debug.log('Deleted %s Albums from Cache.' % deletedAlbums)

    def insertUserPlaylist(self, playlist_id, title='Unknown', items=[], overwrite=True):
        if CACHE_PLAYLISTS:
            if not title:
                title = playlist_id
            if items == None:
                if overwrite:
                    debug.log('MetaCache: Resetting UserPlaylist "%s"' % title)
            else:
                if overwrite:
                    debug.log('MetaCache: Updating UserPlaylist "%s" with %s items' % (title, len(items)))
                else:
                    debug.log('MetaCache: Inserting UserPlaylist "%s" with %s items' % (title, len(items)))
            if items == None:
                upd_playlist = { 'id': playlist_id,
                                 'title': title }
            else:
                upd_playlist = { 'id': playlist_id,
                                 'title': title,
                                 'items': items }
            self.insert('userpl', playlist_id, data=upd_playlist, overwrite=overwrite)

    def delete(self, item_type, item_id):
        ok = False
        try:
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            dbcur.execute("DELETE FROM meta WHERE (type = '%s' and id = '%s')" % (item_type, item_id))
            self.dbcon.commit()
            ok = True
        except:
            pass
        return ok

    def deleteAll(self, item_type):
        ok = False
        try:
            if not self.dbcon:
                self.connect()
            dbcur = self.dbcon.cursor()
            dbcur.execute("DELETE FROM meta WHERE (type = '%s')" % item_type)
            self.dbcon.commit()
            ok = True
        except:
            pass
        return ok

    def deleteDatabase(self):
        try:
            filename = os.path.join(METACACHE_DIR, METACACHE_FILE)
            if xbmcvfs.exists(filename):
                xbmcvfs.delete(filename)
                debug.log('Deleted Database file %s' % METACACHE_FILE)
        except:
            return False
        return True

# End of File