#!/usr/bin/python
# -*- coding: utf-8 -*-

import re
import os
import grp
try:
    import MySQLdb
except ImportError:
    MySQLdb = None
from clcommon.cpapi.cpapiexceptions import NoPackage

from clcommon.cpapi.cpapiexceptions import NotSupported, NoDBAccessData

__cpname__ = 'ISPManager'


def detect():
    return os.path.isfile('/usr/local/ispmgr/bin/ispmgr') or os.path.isfile('/usr/local/mgr5/sbin/mgrctl')


ISP_DB_CONF = '/usr/local/ispmgr/etc/ispmgr.conf'

SECTION_PATTERN = r'(\S+) "([^"]+)" {([^}]+)}'
KEYWORDS_PATTERN = r'(\S+)\s+(\S+)'


def conf_pars(sectype, secname=None, seckeys=None, path=ISP_DB_CONF):
    """
    /usr/local/ispmgr/etc/ispmgr.conf parser
    :param sectype: Type sector for example: Service or DbServer or Account
    :param secname: Name sector. May be different
    :param seckeys: Name key for retrieving and filtering
    :param path: path to config file default /usr/local/ispmgr/etc/ispmgr.conf
    :return: list
    """
    seckeys_filter = dict()
    seckeys_extracted = None
    if seckeys:
        seckeys_extracted = list()
        for key_val in seckeys:
            key_val_splited = key_val.split()
            if len(key_val_splited) == 2:
                seckeys_filter.update(dict([key_val_splited]))
                seckeys_extracted.append(key_val_splited[0])
            elif len(key_val_splited) == 1:
                seckeys_extracted.append(key_val_splited[0])
    conf_stream = open(path)
    result_list = list()
    for stype, sname, sbody in re.findall(SECTION_PATTERN, conf_stream.read()):
        blst = re.findall(KEYWORDS_PATTERN, sbody)
        if stype == sectype and secname in (None, secname):
            result = dict([(k, v)
                           for k, v in blst
                           if seckeys_extracted is None or k in seckeys_extracted])

            if set(seckeys_filter.items()).issubset(set(result.items())):
                result_list.append(result)

    conf_stream.close()
    return result_list


def db_access(_conf_path=ISP_DB_CONF):
    access = dict()
    access_list = conf_pars(sectype='DbServer', seckeys=('Hostname', 'Password', 'Type mysql', 'User'), path=_conf_path)
    for access_from_conf in access_list:
        try:
            access['pass'] = access_from_conf['Password']
            access['login'] = access_from_conf['User']
            access['host'] = access_from_conf['Hostname']
            access['db'] = 'mysql'
            return access
        except KeyError:
            pass
    raise NoDBAccessData('Can not find database access data for localhost in config file %s' % (_conf_path,))


def _dbname_dblogin_pairs(access):
    if not MySQLdb:
        raise NoPackage('Can not connect to database; MySQL-python package not installed.')
    dbhost = access.get('host', 'localhost')
    dblogin = access['login']
    dbpass = access['pass']
    db = MySQLdb.connect(host=dbhost, user=dblogin, passwd=dbpass, db='mysql')
    cursor = db.cursor()
    sql = r"SELECT db.Db, db.User FROM db  GROUP BY db.User, db.Db"
    cursor.execute(sql)
    data = cursor.fetchall()
    db.close()
    return data


def cpusers():
    raise NotSupported('Getting all users registered in the Control Panel is not currently supported. '
                       'Is under development.')


def _dbname_cplogin_pairs_iter(cplogin_lst=None, _conf_path=ISP_DB_CONF):
    """
    Extract (database name <=> control panel login) pairs from ISPmanager config file
    :param cplogin_lst:
    :param _conf_path:
    :return:
    """
    conf_stream = open(_conf_path)
    grpid_login_dict = dict([(grp_tuple[2], grp_tuple[0]) for grp_tuple in grp.getgrall()])
    for line_numb, line in enumerate(conf_stream):
        if line.startswith('DbAssign '):
            line_splited = line.split()
            if len(line_splited) >= 3:
                dbname, user_uid = line_splited[2:]
                try:
                    cplogin = grpid_login_dict.get(int(user_uid))
                    if cplogin is None:
                        print('WARNING: can not find group name with id %s; line %d in file %s'
                              % (user_uid, line_numb, _conf_path))
                except ValueError:  # if can not convert user_uid to int
                    print('WARNING: can not pars line %d in file %s' % (line_numb, _conf_path))
                    cplogin = None
                if cplogin and (cplogin_lst is not None or cplogin in cplogin_lst):
                    yield dbname, cplogin
    conf_stream.close()
