import locale
import platform
import re
import sys
from datetime import datetime
from time import mktime
from .._compat import PY2, pjoin
from .base import SQLAdapter
from . import adapters


@adapters.register_for('sqlite', 'sqlite:memory')
class SQLite(SQLAdapter):
    dbengine = 'sqlite'
    drivers = ('sqlite2', 'sqlite3')

    def _initialize_(self, do_connect):
        super(SQLite, self)._initialize_(do_connect)
        path_encoding = sys.getfilesystemencoding() \
            or locale.getdefaultlocale()[1] or 'utf8'
        if ':memory' in self.uri.split('://', 1)[0]:
            self.dbpath = ':memory:'
        else:
            self.dbpath = self.uri.split('://', 1)[1]
            if self.dbpath[0] != '/':
                if PY2:
                    self.dbpath = pjoin(
                        self.folder.decode(path_encoding).encode('utf8'),
                        self.dbpath)
                else:
                    self.dbpath = pjoin(self.folder, self.dbpath)
        if 'check_same_thread' not in self.driver_args:
            self.driver_args['check_same_thread'] = False
        if 'detect_types' not in self.driver_args and do_connect:
            self.driver_args['detect_types'] = self.driver.PARSE_DECLTYPES

    def _driver_from_uri(self):
        return None

    def connector(self):
        return self.driver.Connection(self.dbpath, **self.driver_args)

    @staticmethod
    def web2py_extract(lookup, s):
        table = {
            'year': (0, 4), 'month': (5, 7), 'day': (8, 10), 'hour': (11, 13),
            'minute': (14, 16), 'second': (17, 19)}
        try:
            if lookup != 'epoch':
                (i, j) = table[lookup]
                return int(s[i:j])
            else:
                return mktime(
                    datetime.strptime(s, '%Y-%m-%d %H:%M:%S').timetuple())
        except:
            return None

    @staticmethod
    def web2py_regexp(expression, item):
        if item is None:
            return False
        return re.compile(expression).search(item) is not None

    def _register_extract(self):
        self.connection.create_function(
            'web2py_extract', 2, self.web2py_extract)

    def _register_regexp(self):
        self.connection.create_function(
            "REGEXP", 2, self.web2py_regexp)

    def after_connection(self):
        self._register_extract()
        self._register_regexp()
        if self.adapter_args.get('foreign_keys', True):
            self.execute('PRAGMA foreign_keys=ON;')

    def select(self, query, fields, attributes):
        if attributes.get('for_update', False) and 'cache' not in attributes:
            self.execute('BEGIN IMMEDIATE TRANSACTION;')
        return super(SQLite, self).select(query, fields, attributes)

    def delete(self, tablename, query):
        db = self.db
        table = db[tablename]
        deleted = [x[table._id.name] for x in db(query).select(table._id)]
        counter = super(SQLite, self).delete(tablename, query)
        if counter:
            for field in table._referenced_by:
                if field.type == 'reference ' + tablename \
                   and field.ondelete == 'CASCADE':
                    db(field.belongs(deleted)).delete()
        return counter


@adapters.register_for('spatialite', 'spatialite:memory')
class Spatialite(SQLite):
    dbengine = 'spatialite'

    SPATIALLIBS = {
        'Windows': 'mod_spatialite.dll',
        'Linux': 'libspatialite.so',
        'Darwin': 'libspatialite.dylib'
    }

    def after_connections(self):
        self.connection.enable_load_extension(True)
        libspatialite = self.SPATIALLIBS[platform.system()]
        self.execute(r'SELECT load_extension("%s");' % libspatialite)
        super(Spatialite, self).after_connection()


@adapters.register_for('jdbc:sqlite', 'jdbc:sqlite:memory')
class JDBCSQLite(SQLite):
    drivers = ('zxJDBC_sqlite',)

    def connector(self):
        return self.driver.connect(
            self.driver.getConnection('jdbc:sqlite:'+self.dbpath),
            **self.driver_args)

    def after_connection(self):
        self._register_extract()
