#!/usr/bin/python2.6
#
# @package      hubzero-cli
# @file         hzuseradd
# @author       David Benham <dbenham@purdue.edu>
# @copyright    Copyright (c) 2013 HUBzero Foundation, LLC.
# @license      http://www.gnu.org/licenses/lgpl-3.0.html LGPLv3
#
# Copyright (c) 2013 HUBzero Foundation, LLC.
#
# This file is part of: The HUBzero(R) Platform for Scientific Collaboration
#
# The HUBzero(R) Platform for Scientific Collaboration (HUBzero) is free
# software: you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# HUBzero 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# HUBzero is a registered trademark of HUBzero Foundation, LLC.
#

import argparse
import grp
import hubzero.utilities.user
import hubzero.config.passwords
import hubzero.config.webconfig
import re
import traceback
import os
import hubzero.utilities.misc

hubname = hubzero.config.webconfig.getDefaultSite()
docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")

if os.path.exists(docroot + "/libraries/cms/index.html"):
        hubzero.utilities.misc.JOOMLA_25 = True

# really, python has no int test without having to throw an exception?
def RepresentsInt(s):
	try: 
		int(s)
		return True
	except ValueError:
		return False



def addUser(args):

	# default email if it wasn't provided
	if not args.email:
		defaultedEmail = True
		email = args.username + "@invalid"
	else:
		defaultedEmail = False
		email = args.email

	
	# default hubname if it wasn't provided
	if not args.hubname:
		hubname = hubzero.config.webconfig.getDefaultSite()
	else:
		hubname = args.hubname
		
	
	# username tests
	args.username = args.username.lower()
	p = re.compile("[a-z][a-z0-9]*")
	m = p.match(args.username)
	if not m:
		print "username invalid - must be alphanumeric and must start with letter"
		exit(1)
	
	
	# joomlagid tests
	userTypeLookupDict = {18:"Registered", 23:"Manager", 24:"Administrator", 25:"Super Administrator"}
	
	if RepresentsInt(args.joomlagid):
		if not args.joomlagid in ['18', '23', '24', '25']:
			print "invalid joomlagid (1) " + args.joomlagid
			exit(3)
		else:
			jgidNumber = args.joomlagid
			jgid = userTypeLookupDict[int(args.joomlagid)]
	
	else:
		if not args.joomlagid in ["Registered", "Manager", "Administrator", "Super Administrator"]:
			print "invalid joomlagid (2) " + args.joomlagid
			exit(3)
		else:
			jgid = [key for key,val in userTypeLookupDict.items() if val==args.joomlagid ][0]
			jgidNumber = args.joomlagid
	
		
	# gid tests, user can specify a numeric group id, or the groupid, make sure after this code
	# runs, the gid and gidNumber correspond to the same group.
	try:
		if not args.gid.isdigit():
			if not grp.getgrnam(args.gid):
				print "invalid gid"
				exit(3)
			else:
				gid = args.gid
				gidNumber = grp.getgrnam(args.gid)[2]
		else:
			if not grp.getgrgid(args.gid):
				print "invalid gid"
				exit(3)
			else:
				gid = grp.getgrgid(args.gid)[0]
				gidNumber = args.gid
	except Exception as e:
		traceback.print_exc()
		print "Error: problem with provided gid"
		raise e
		
	
	# email validity testing, if email was defaulted, don't check that.
	if not defaultedEmail:
		p = re.compile("^[a-zA-Z0-9.]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$")
		m = p.match(email)
		if not m:
			print "invalid email"
			exit(4)
	
	# prompt for a password, or create one from scratch
	if not args.promptforpw:
		if args.disabledpassword:
			pw = '*'
		else:
			if args.pw:
				pw = args.pw
			else:
				pw = hubzero.config.passwords.generateAlphaNumPassword(10)
		
	else:
		# To make things easier, just alphanumberic, wierd characters are a pain
		validPW = False
		while not validPW:
			pw = raw_input("Enter a password: ")
	
			p = re.compile("[a-zA-Z0-9]*")
			m = p.match(pw)
	
			if not m:
				print "Password invalid - must be alphanumeric"
			else:
				validPW = True
	
	# reconcile the keys passed in in the -k/--key argument
	if False: #args.key:
		
		keyValuePairs = dict(re.findall(r'(\S+)=(".*?"|\S+)', ' '.join(args.key)))
		
		uid_min = keyValuePairs["UID_MIN"]
		uid_max = keyValuePairs["UID_MAX"]
		
		# check supported args one at a time
		if "UID_MIN" in keyValuePairs:
			uid_min = keyValuePairs["UID_MIN"]
		else:
			uid_min = 1000
		
		if "UID_MAX" in keyValuePairs:
			uid_max = keyValuePairs["UID_MAX"]
		else:
			uid_max = 65528
		
	else: # all defaults
		uid_min = 1000
		uid_max = 65528
		
	# group type logic (0 is system, 1 is regular)
	if args.system:
		grouptype = 0
	else:
		grouptype = 1
		
	rc = hubzero.utilities.user.addhubuser(hubname,
		                              args.username, 
		                              email,
		                              pw,
		                              args.disabledpassword,
	                                  grouptype,
		                              jgidNumber, 
		                              gid, 
		                              gidNumber, 
		                              args.uid,
		                              args.gecos,
		                              args.shell,
		                              args.skipcreatehome,
		                              args.home,
		                              args.skipcreateusergroup,
		                              args.skipcreateldapuser, 
	                                  args.skipcreatecmsuser,
	                                  uid_min,
	                                  uid_max)
	
	
	# only if we execute without errors
	if not rc:
		# if user specified pw, no reason to tell them
		if not args.promptforpw and not args.pw:
			print "Autogenerated password for user is: " + pw


def addUserToGroup(userName, groupName):
	hubzero.utilities.group.addusertogroup_ldap(userName, groupName)


# ####################
# main

# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("username", help="username, alpha username")
parser.add_argument("--groups", help="add specified user to group", default="")
parser.add_argument("--email", help="email address", default="")
parser.add_argument("--hubname", help="hubname, if not provided, will default to default hub", default="")
parser.add_argument("--joomlagid", help="Joomla specific GIDs, (18=Registered, 23=Manager, 24=Administrator, 25=Super Administrator)", default="18")
parser.add_argument("--gid", help="Linux gidNumber or gid, default is 100 (users)", default="100")
parser.add_argument("--home", help="set user home directory", default="")
parser.add_argument("--uid", help="numerical value of the user's id", default=-1)
parser.add_argument("--shell", help="specify users shell", default='/bin/bash')
parser.add_argument("--skipcreateldapuser", help="skip adding user to ldap database", action="store_true", default=False)
parser.add_argument("--skipcreatecmsuser", help="skip adding user to cms database", action="store_true", default=False)
parser.add_argument("--skipcreateusergroup", help="create group made just for this new user", action="store_true", default=False)
parser.add_argument("--skipcreatehome", help="create user home directory", action="store_true", default=False)
parser.add_argument("--gecos", help="gecos field, see man page for /etc/passwd for more info", default="<none>")
parser.add_argument("--system", help="add system level user", action="store_true", default=False)

group = parser.add_mutually_exclusive_group()
group.add_argument("--pw", help="password, hashed or not, doesn't matter")
group.add_argument("--promptforpw", help="Prompt for password for user, otherwise generate random password", action="store_true", default=False)
group.add_argument("--disabled-password", dest="disabledpassword", help="disable user password", action="store_true", default=False)

args = parser.parse_args()

addUser(args)	

# were groups specified?
if args.groups:
	# see if there is more than one group in a comma delimited list
	if "," in args.groups:
		for groupName in args.groups.split(","):
			addUserToGroup(groupName)
	else:
		addUserToGroup(args.groups)


