"""A class to manage fetching and caching of images by URL"""

# Copyright 2012-2014 Anthony Beville

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sqlite3 as lite
import os
import datetime
import shutil
import tempfile
import urllib
#import urllib2

try:
    from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest
    from PyQt4.QtCore import QUrl, pyqtSignal, QObject, QByteArray
    from PyQt4 import QtGui
except ImportError:
    # No Qt, so define a few dummy QObjects to help us compile
    class QObject():

        def __init__(self, *args):
            pass

    class QByteArray():
        pass

    class pyqtSignal():

        def __init__(self, *args):
            pass

        def emit(a, b, c):
            pass

from settings import ComicTaggerSettings


class ImageFetcherException(Exception):
    pass


class ImageFetcher(QObject):

    fetchComplete = pyqtSignal(QByteArray, int)

    def __init__(self):
        QObject.__init__(self)

        self.settings_folder = ComicTaggerSettings.getSettingsFolder()
        self.db_file = os.path.join(self.settings_folder, "image_url_cache.db")
        self.cache_folder = os.path.join(self.settings_folder, "image_cache")

        if not os.path.exists(self.db_file):
            self.create_image_db()

    def clearCache(self):
        os.unlink(self.db_file)
        if os.path.isdir(self.cache_folder):
            shutil.rmtree(self.cache_folder)

    def fetch(self, url, user_data=None, blocking=False):
        """
        If called with blocking=True, this will block until the image is
        fetched.
        If called with blocking=False, this will run the fetch in the
        background, and emit a signal when done
        """

        self.user_data = user_data
        self.fetched_url = url

        # first look in the DB
        image_data = self.get_image_from_cache(url)

        if blocking:
            if image_data is None:
                try:
                    image_data = urllib.urlopen(url).read()
                except Exception as e:
                    print(e)
                    raise ImageFetcherException("Network Error!")

            # save the image to the cache
            self.add_image_to_cache(self.fetched_url, image_data)
            return image_data

        else:

            # if we found it, just emit the signal asap
            if image_data is not None:
                self.fetchComplete.emit(QByteArray(image_data), self.user_data)
                return

            # didn't find it.  look online
            self.nam = QNetworkAccessManager()
            self.nam.finished.connect(self.finishRequest)
            self.nam.get(QNetworkRequest(QUrl(url)))

            # we'll get called back when done...

    def finishRequest(self, reply):

        # read in the image data
        image_data = reply.readAll()

        # save the image to the cache
        self.add_image_to_cache(self.fetched_url, image_data)

        self.fetchComplete.emit(QByteArray(image_data), self.user_data)

    def create_image_db(self):

        # this will wipe out any existing version
        open(self.db_file, 'w').close()

        # wipe any existing image cache folder too
        if os.path.isdir(self.cache_folder):
            shutil.rmtree(self.cache_folder)
        os.makedirs(self.cache_folder)

        con = lite.connect(self.db_file)

        # create tables
        with con:

            cur = con.cursor()

            cur.execute("CREATE TABLE Images(" +
                        "url TEXT," +
                        "filename TEXT," +
                        "timestamp TEXT," +
                        "PRIMARY KEY (url))"
                        )

    def add_image_to_cache(self, url, image_data):

        con = lite.connect(self.db_file)

        with con:

            cur = con.cursor()

            timestamp = datetime.datetime.now()

            tmp_fd, filename = tempfile.mkstemp(
                dir=self.cache_folder, prefix="img")
            f = os.fdopen(tmp_fd, 'w+b')
            f.write(image_data)
            f.close()

            cur.execute("INSERT or REPLACE INTO Images VALUES(?, ?, ?)",
                        (url,
                         filename,
                         timestamp)
                        )

    def get_image_from_cache(self, url):

        con = lite.connect(self.db_file)
        with con:
            cur = con.cursor()

            cur.execute("SELECT filename FROM Images WHERE url=?", [url])
            row = cur.fetchone()

            if row is None:
                return None
            else:
                filename = row[0]
                image_data = None

                try:
                    with open(filename, 'rb') as f:
                        image_data = f.read()
                        f.close()
                except IOError as e:
                    pass

                return image_data
