import ldap
import flask
import flask_wtf

from webapp import app, context, config, validation
from webapp.auth import login_required

bp = flask.Blueprint('vcard', __name__)

def str_to_ldap(s):
    return s.encode('utf-8')

perm_errors = {
    'add': 'You cannot add this attribute!',
    'mod': 'You cannot change this attribute!',
    'del': 'You cannot delete this attribute!',
}

templates = {
    'add': 'ops/add.html',
    'mod': 'ops/mod.html',
    'del': 'ops/del.html',
}

def attr_op(op, attrName, uid = None, success_redirect='/vcard',
        fatal_redirect='/vcard'):
    try:
        attr, old_value = None, None
        if uid:
            attr = context.get_profile()[uid]
            attrName = attr.name
            old_value = str(attr)
        form = DelForm() if op == 'del' else app.forms[attrName](value=old_value)
        form.attr_data = attr
        if attrName not in config.can[op]:
            flask.flash(perm_errors[op], 'danger')
            return flask.redirect(fatal_redirect)
        if form.validate_on_submit():
            if op in ['add', 'mod']:
                new_value = form.value.data
            admin = attrName in config.admin_required
            conn = context.get_admin_connection() if admin else context.get_connection()
            dn = context.get_dn()

            # Most fields should be modified by remove/add.
            if op == 'mod' and attrName not in ['commonname']:
                op = 'modreadd'

            if op in ['del', 'modreadd']:
                conn.modify_s(dn, [(ldap.MOD_DELETE, attrName, str_to_ldap(old_value))])
            if op in ['add', 'modreadd']:
                conn.modify_s(dn, [(ldap.MOD_ADD, attrName, str_to_ldap(new_value))])

            if op in ['mod']:
                conn.modify_s(dn, [(ldap.MOD_REPLACE, attrName, str_to_ldap(new_value))])

            context.refresh_profile()
            return flask.redirect(success_redirect)
        if form.is_submitted():
            for field, errors in form.errors.items():
                for error in errors:
                    flask.flash("Error in the {} field - {}".format(
                        getattr(form, field).label.text,
                        error
                    ), 'danger')
            return flask.redirect(success_redirect)
        status = 400 if form.is_submitted() else 200
        return flask.make_response(flask.render_template(templates[op], fatal_redirect=fatal_redirect,
            attr_op=op, form=form, attr_name=attrName, uid=uid), status)
    except ldap.LDAPError as e:
        print('LDAP error:', e)
        flask.flash('Could not modify profile', 'danger')
    return flask.redirect(fatal_redirect)

class DelForm(flask_wtf.FlaskForm):
    pass

@bp.route('/vcard', methods=['GET'])
@login_required
def vcard():
    data = {}
    for v in context.get_profile().values():
        data.setdefault(v.name, []).append(v)
    return flask.render_template('vcard.html', can_add=config.can['add'],
            can_modify=config.can['mod'], can_delete=config.can['del'], profile=data)

@bp.route('/vcard/add/<attrName>', methods=['GET', 'POST'])
@login_required
def add_attr(attrName):
    return attr_op('add', attrName)

@bp.route('/vcard/delete/<uid>', methods=['GET', 'POST'])
@login_required
def del_attr(uid):
    return attr_op('del', None, uid)

@bp.route('/vcard/modify/<uid>', methods=['GET', 'POST'])
@login_required
def mod_attr(uid):
    return attr_op('mod', None, uid)
