#!/usr/bin/env python

import argparse
import subprocess
import getpass
import jinja2
import re
import os

THIS_DIR    = os.path.dirname(os.path.abspath(__file__))
jinja2env   = jinja2.Environment(loader=jinja2.FileSystemLoader("%s/templates" % THIS_DIR), keep_trailing_newline=True)

SHELLS      = [ '/bin/bash', '/bin/csh', '/bin/zsh' '/bin/sh', '/bin/ksh' ]

def unboundldapcommand( cmd, args ):
    basecmd =   [
                    '/usr/bin/%s' % cmd,
                    '-x',
                ]
    return basecmd + args;

def boundldapcommand( cmd, args ):
    basecmd =   [
                    '/usr/bin/%s' % cmd,
                    '-x',
                    '-D',
                    '"uid=%s,ou=people,dc=itap,dc=com"' % getpass.getuser(),
                ]
    return basecmd + args;

def get_groups():
    p = subprocess.Popen(unboundldapcommand('ldapsearch', [ '-b', 'ou=groups,dc=itap,dc=com', '(objectclass=posixgroup)', 'cn gidnumber']), stdout=subprocess.PIPE)
    (standardout,stderr) = p.communicate()

    groups = []
    cnmatch = re.compile('cn: (\w+)')
    for line in standardout.split():
        cn = cnmatch.match(line)
        if cn:
            groups.append(cn.group(1))

    return groups;

def get_users():
    p = subprocess.Popen(unboundldapcommand('ldapsearch', [ '-b', 'ou=people,dc=itap,dc=com', '(objectclass=posixaccount)', 'uid uidnumber']), stdout=subprocess.PIPE)
    (standardout,stderr) = p.communicate()

    names = {}
    uids  = {}
    namematch   = re.compile('uid: (\w+)')
    uidmatch    = re.compile('uidnumber: (\d+)')

    for line in standardout.split():
        name = namematch.match(line)
        if name:
            names[name.group(1)] = True
        uid  = uidmatch.match(line)
        if uid:
            uids[uid.group(1)] = True

    return { 'names': names, 'uids': uids };


def jinja_groups(j2,attrs):
    "group_add.ldif template defines: cn, username"

    for group in attrs.groups:
        print j2.get_template("group_add.ldif").render(attrs)

    return;

def jinja_user(j2,attrs):
    "user_add.ldif template defines: username, password, first, last, email, site, uid, gid, fullname, shell, manager, company, phone, expiration"

    print j2.get_template("user_add.ldif").render(attrs)

    return;

def adjust_user(base):
    user = base

    existing = get_users()

    if 'username' not in user:
        user['username'] = (user['first'][0] + user['last'])[0:8].lower()

    if 'fullname' not in user:
        user['fullname'] = "%s %s" % [ user['first'], user['last'] ]

    if 'uidnumber' not in user:
        # Someday, someone will screw up my nice uid numbering, then this
        # function will have to get ugly to fill in the empty slots.  Please
        # don't be that person.
        user['uidnumber'] = max(map(int,existing['uids'].keys())) + 1

    return user;

def parse_args(group_list,shell_list):
    parser = argparse.ArgumentParser(description='Create new ITAP user accounts')
    parser.add_argument('-f', '--first', type=str, required=True, help="First Name")
    parser.add_argument('-l', '--last',  type=str, required=True, help="Last Name")
    parser.add_argument('-e', '--email', type=str, required=True, help="unclassified email address")
    parser.add_argument('-p', '--phone', type=str, required=True, help="business contact phone number")
    parser.add_argument('-s', '--site',  type=str, required=True, help="business site")
    parser.add_argument('-m', '--manager',  type=str, required=True, help="manager's name")
    parser.add_argument('-c', '--company',  type=str, required=True, help="employer's name")
    parser.add_argument('--fullname', type=str, help="A specific full name, incase <first> <last> is insufficient")
    parser.add_argument('-u', '--username', type=str, help="username, default is first initial, last name (8 chars)")
    parser.add_argument('-U', '--uidnumber', type=str, help="default is next available uid")
    parser.add_argument('-S', '--shell', type=str, help="login shell, default is bash", choices=shell_list,
                                            default="/bin/bash")
    parser.add_argument('-g', '--groups', type=str, nargs='+', help="one or more additional groups (everyone is in users)",
                                            choices=group_list)

    args = parser.parse_args()

    phonematch=re.match('(\d{3}).*(\d{3}).*(\d{4})',args.phone)
    if phonematch:
        args.phone = "%03d %03d-%04d" % phonematch.group(1,2,3)
    else:
        print "Phone number not in a valid format: NNN AAA-BBBB\n"
        sys.exit(1);

    return adjust_user(vars(args));

def create_user():
    user = parse_args(get_groups(),SHELL_LIST)

    jinja_groups(jinja2env,user)
    jinja_user(jinja2env,user)

if __name__ == '__main__':
    create_user()