# -*- coding: utf-8 -*-

import decimal
import re

from ._globals import LOGGER


# verify presence of modules
from collections import OrderedDict

try:
    from ..security import uuid as web2py_uuid
except (ImportError, SystemError):
    import uuid as uuidm
    def web2py_uuid(): return str(uuidm.uuid4())

try:
    from ..libs import portalocker
    have_portalocker = True
except ImportError:
    portalocker = None
    have_portalocker = False

try:
    from weppy import serializers
    have_serializers = True
    #simplejson = None
    simplejson = serializers.json_parser
except ImportError:
    serializers = None
    have_serializers = False
    import json as simplejson


# list of drivers will be built on the fly
# and lists only what is available
DRIVERS = []

try:
    from new import classobj
    from google.appengine.ext import db as gae
    from google.appengine.ext import ndb
    from google.appengine.api import namespace_manager, rdbms
    from google.appengine.api.datastore_types import Key  ### for belongs on ID
    from google.appengine.ext.db.polymodel import PolyModel
    from google.appengine.ext.ndb.polymodel import PolyModel as NDBPolyModel
    DRIVERS.append('google')
except ImportError:
    classobj = None
    gae = None
    ndb = None
    namespace_manager = rdbms = None
    Key = None
    PolyModel = NDBPolyModel = None

if not 'google' in DRIVERS:

    try:
        from pysqlite2 import dbapi2 as sqlite2
        DRIVERS.append('sqlite2')
    except ImportError:
        LOGGER.debug('no SQLite drivers pysqlite2.dbapi2')

    try:
        from sqlite3 import dbapi2 as sqlite3
        DRIVERS.append('sqlite3')
    except ImportError:
        LOGGER.debug('no SQLite drivers sqlite3')

    try:
        import pymysql
        DRIVERS.append('pymysql')
    except ImportError:
        LOGGER.debug('no MySQL driver pymysql')

    try:
        import MySQLdb
        DRIVERS.append('MySQLdb')
    except ImportError:
        LOGGER.debug('no MySQL driver MySQLDB')

    try:
        import mysql.connector as mysqlconnector
        DRIVERS.append("mysqlconnector")
    except ImportError:
        LOGGER.debug("no driver mysql.connector")

    try:
        import psycopg2
        from psycopg2.extensions import adapt as psycopg2_adapt
        DRIVERS.append('psycopg2')
    except ImportError:
        psycopg2_adapt = None
        LOGGER.debug('no PostgreSQL driver psycopg2')

    try:
        import pg8000.dbapi as pg8000
        DRIVERS.append('pg8000')
    except ImportError:
        LOGGER.debug('no PostgreSQL driver pg8000')

    try:
        import cx_Oracle
        DRIVERS.append('cx_Oracle')
    except ImportError:
        cx_Oracle = None
        LOGGER.debug('no Oracle driver cx_Oracle')

    try:
        import pyodbc
        DRIVERS.append('pyodbc')
        #DRIVERS.append('DB2(pyodbc)')
        #DRIVERS.append('Teradata(pyodbc)')
        #DRIVERS.append('Ingres(pyodbc)')
    except ImportError:
        pyodbc = None
        LOGGER.debug('no MSSQL/DB2/Teradata/Ingres driver pyodbc')

    try:
        import Sybase
        DRIVERS.append('Sybase')
    except ImportError:
        LOGGER.debug('no Sybase driver')

    try:
        import kinterbasdb
        DRIVERS.append('kinterbasdb')
        #DRIVERS.append('Firebird(kinterbasdb)')
    except ImportError:
        LOGGER.debug('no Firebird/Interbase driver kinterbasdb')

    try:
        import fdb
        DRIVERS.append('fdb')
    except ImportError:
        LOGGER.debug('no Firebird driver fdb')

    try:
        import firebirdsql
        DRIVERS.append('firebirdsql')
    except ImportError:
        LOGGER.debug('no Firebird driver firebirdsql')

    try:
        import informixdb
        DRIVERS.append('informixdb')
        LOGGER.warning('Informix support is experimental')
    except ImportError:
        LOGGER.debug('no Informix driver informixdb')

    try:
        import sapdb
        DRIVERS.append('sapdb')
        LOGGER.warning('SAPDB support is experimental')
    except ImportError:
        LOGGER.debug('no SAP driver sapdb')

    try:
        import cubriddb
        DRIVERS.append('cubriddb')
        LOGGER.warning('Cubrid support is experimental')
    except ImportError:
        LOGGER.debug('no Cubrid driver cubriddb')

    try:
        from com.ziclix.python.sql import zxJDBC
        import java.sql
        # Try sqlite jdbc driver from http://www.zentus.com/sqlitejdbc/
        from org.sqlite import JDBC # required by java.sql; ensure we have it
        zxJDBC_sqlite = java.sql.DriverManager
        DRIVERS.append('zxJDBC')
        #DRIVERS.append('SQLite(zxJDBC)')
        LOGGER.warning('zxJDBC support is experimental')
        is_jdbc = True
    except ImportError:
        LOGGER.debug('no SQLite/PostgreSQL driver zxJDBC')
        is_jdbc = False

    try:
        import couchdb
        DRIVERS.append('couchdb')
    except ImportError:
        couchdb = None
        LOGGER.debug('no Couchdb driver couchdb')

    try:
        import pymongo
        DRIVERS.append('pymongo')
    except:
        LOGGER.debug('no MongoDB driver pymongo')

    try:
        import imaplib
        DRIVERS.append('imaplib')
    except:
        LOGGER.debug('no IMAP driver imaplib')

    GAEDecimalProperty = None
    NDBDecimalProperty = None
else:
    is_jdbc = False

    class GAEDecimalProperty(gae.Property):
        """
        GAE decimal implementation
        """
        data_type = decimal.Decimal

        def __init__(self, precision, scale, **kwargs):
            super(GAEDecimalProperty, self).__init__(self, **kwargs)
            d = '1.'
            for x in range(scale):
                d += '0'
            self.round = decimal.Decimal(d)

        def get_value_for_datastore(self, model_instance):
            value = super(GAEDecimalProperty, self)\
                .get_value_for_datastore(model_instance)
            if value is None or value == '':
                return None
            else:
                return str(value)

        def make_value_from_datastore(self, value):
            if value is None or value == '':
                return None
            else:
                return decimal.Decimal(value).quantize(self.round)

        def validate(self, value):
            value = super(GAEDecimalProperty, self).validate(value)
            if value is None or isinstance(value, decimal.Decimal):
                return value
            elif isinstance(value, basestring):
                return decimal.Decimal(value)
            raise gae.BadValueError("Property %s must be a Decimal or string."\
                                        % self.name)

    #TODO Needs more testing
    class NDBDecimalProperty(ndb.StringProperty):
        """
        NDB decimal implementation
        """
        data_type = decimal.Decimal

        def __init__(self, precision, scale, **kwargs):
            d = '1.'
            for x in range(scale):
                d += '0'
            self.round = decimal.Decimal(d)

        def _to_base_type(self, value):
            if value is None or value == '':
                return None
            else:
                return str(value)

        def _from_base_type(self, value):
            if value is None or value == '':
                return None
            else:
                return decimal.Decimal(value).quantize(self.round)

        def _validate(self, value):
            if value is None or isinstance(value, decimal.Decimal):
                return value
            elif isinstance(value, basestring):
                return decimal.Decimal(value)
            raise TypeError("Property %s must be a Decimal or string."\
                                        % self._name)

    psycopg2_adapt = None
    cx_Oracle = None
    pyodbc = None
    couchdb = None


def get_driver(name):
    return globals().get(name)
