# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is designed to work with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms, as
# designated in a particular file or component or in included license
# documentation.  The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have either included with
# the program or referenced in the documentation.
# 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, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

""" This module implements a manager for loading the correct DB API 2.0 
compliant driver from a db_mgmt_Connection object and  interface for the
underlying drivers. This module itself complies with DB API 2.0.
"""

import grt
from workbench.utils import replace_string_parameters, parameters_from_dsn, dsn_parameters_to_connection_parameters

def get_connection_parameters(conn, do_not_transform=False):
    provided_params = dict(conn.parameterValues)

    # Start filling the all_params dict with the predefined values from the driver data:
    all_params = dict( (param.name, param.defaultValue) for param in conn.driver.parameters )
    all_params.update(provided_params)
    if all_params.get('dsn', ''):  # If dsn is provided, get parameter values from there
        try:
            all_params.update(dsn_parameters_to_connection_parameters(parameters_from_dsn(all_params['dsn'])))
        except Exception:
            pass
    if do_not_transform:
        return all_params
    
    conn_params = { 'hostName'  : '127.0.0.1',
                    'port'      : '1433',
                    'schema'    : '',
                    'userName'  : '',
                    'driver'    : '',
                    'dsn'       : '',
                    'password'  : '',
                    'extras'    : '',
                  }
    conn_params.update(all_params)
    return conn_params


def get_odbc_connection_string(conn, password):
    conn_params = get_connection_parameters(conn)
    if password is not None:
        conn_params['password'] = password  # TODO: Check password handling policy: When should we take this or the one in the parameters?
    connection_string_template = conn.driver.connectionStringTemplate or 'DRIVER={%driver%};SERVER=%hostName%;PORT=%port%;DATABASE={%schema%};UID=%userName%;PWD={%password%}'
    connection_string = replace_string_parameters(connection_string_template, conn_params)
    return connection_string


def is_odbc_connection(conn):
    return conn.driver.driverLibraryName == "pyodbc"


def connect(conn, password=''):
    """ Establish a connection to a database and return a Python DB API 2.0 connection object.
    
    :param conn:      An instance of :class:`db_mgmt_Connection` that contains the needed parameters
                      to set the connection up. You must ensure that this object has a :attr:`driver`
                      attribute with a :attr:`driverLibraryName` attribute that specifies a python module
                      name that will be imported and its :meth:`connect` method called to actually perform
                      the connection.

    :type conn: db_mgmt_Connection

    :param password:  A password to authenticate the user specified in :attr:`conn` with (optional).

    :type password: string

    :returns: A Python DB API 2.0 connection object that can be used to communicate to the target RDBMS.
    """

    connection_string = get_odbc_connection_string(conn, password)
    import re
    connection_string_fixed = re.sub("(.*PWD=)([^;]*)(.*)", r"\1XXXX\3", connection_string)
    connection_string_fixed = re.sub("(.*PASSWORD=)([^;]*)(.*)", r"\1XXXX\3", connection_string_fixed)
    grt.send_info('Opening ODBC connection to %s...' % connection_string_fixed)

    library = __import__(conn.driver.driverLibraryName, globals(), locals())
    connection = library.connect(connection_string, password=password)

    return connection 
    

    
