#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License. See accompanying LICENSE file.
#

import os
import re
import sys
import errno
import shlex
import logging
import subprocess
import platform
import fileinput
import getpass
import shutil
from xml.etree import ElementTree as ET
import update_property
from os.path import basename
from subprocess import Popen,PIPE
from datetime import date
from datetime import datetime
globalDict = {}

os_name = platform.system()
os_name = os_name.upper()

def check_output(query):
	if os_name == "LINUX":
		p = subprocess.Popen(shlex.split(query), stdout=subprocess.PIPE)
	elif os_name == "WINDOWS":	
		p = subprocess.Popen(query, stdout=subprocess.PIPE, shell=True)
	output = p.communicate ()[0]
	return output

def log(msg,type):
	if type == 'info':
		logging.info(" %s",msg)
	if type == 'debug':
		logging.debug(" %s",msg)
	if type == 'warning':
		logging.warning(" %s",msg)
	if type == 'exception':
		logging.exception(" %s",msg)
	if type == 'error':
		logging.error(" %s",msg)

def import_properties_from_xml(xml_path, properties_from_xml=None):
	print('getting values from file : ' + str(xml_path))
	if os.path.isfile(xml_path):
		xml = ET.parse(xml_path)
		root = xml.getroot()
		if properties_from_xml is None:
			properties_from_xml = dict()
		for child in root.findall('property'):
			name = child.find("name").text.strip()
			value = child.find("value").text.strip() if child.find("value").text is not None  else ""
			properties_from_xml[name] = value
	else:
		print('XML file not found at path : ' + str(xml_path))
	return properties_from_xml


def main():
	global globalDict
	FORMAT = '%(asctime)-15s %(message)s'
	logging.basicConfig(format=FORMAT, level=logging.DEBUG)

	CFG_FILE=os.path.join(os.getcwd(),'conf','ranger-ugsync-site.xml')
	if os.path.isfile(CFG_FILE):
		pass
	else:
		log("[E] Required file not found: ["+CFG_FILE+"]","error")
		sys.exit(1)

	if os.environ['JAVA_HOME'] == "":
		log("[E] ---------- JAVA_HOME environment property not defined, aborting installation. ----------", "error")
		sys.exit(1)
	JAVA_BIN=os.path.join(os.environ['JAVA_HOME'],'bin','java')
	if os_name == "WINDOWS" :
		JAVA_BIN = JAVA_BIN+'.exe'
	if os.path.isfile(JAVA_BIN):
		pass
	else:
		while os.path.isfile(JAVA_BIN) == False:
			log("Enter java executable path: :","info")
			JAVA_BIN=raw_input()
	log("[I] Using Java:" + str(JAVA_BIN),"info")

	globalDict=import_properties_from_xml(CFG_FILE,globalDict)
	SYNC_LDAP_BIND_KEYSTOREPATH=globalDict['ranger.usersync.credstore.filename']
	log("[I] SYNC_LDAP_BIND_KEYSTOREPATH:" + str(SYNC_LDAP_BIND_KEYSTOREPATH),"info")
	SYNC_POLICY_MGR_ALIAS="ranger.usersync.policymgr.password"
	SYNC_POLICY_MGR_PASSWORD = ''
	SYNC_POLICY_MGR_USERNAME = ''
	unix_user = "ranger"
	unix_group = "ranger"

	while SYNC_POLICY_MGR_USERNAME == "":
		print "Enter policymgr user name:"
		SYNC_POLICY_MGR_USERNAME=raw_input()

	while SYNC_POLICY_MGR_PASSWORD == "":
		SYNC_POLICY_MGR_PASSWORD=getpass.getpass("Enter policymgr user password:")

	if SYNC_LDAP_BIND_KEYSTOREPATH != "" or SYNC_POLICY_MGR_ALIAS != "" or SYNC_POLICY_MGR_USERNAME != "" or SYNC_POLICY_MGR_PASSWORD != "":
		log("[I] Storing policymgr usersync password in credential store:","info")
		cmd="%s -cp lib/* org.apache.ranger.credentialapi.buildks create %s -value %s  -provider jceks://file%s" %(JAVA_BIN,SYNC_POLICY_MGR_ALIAS,SYNC_POLICY_MGR_PASSWORD,SYNC_LDAP_BIND_KEYSTOREPATH)
		ret=subprocess.call(shlex.split(cmd))
		if ret == 0:
			cmd="chown %s:%s %s" %(unix_user,unix_group,SYNC_LDAP_BIND_KEYSTOREPATH)
			ret=subprocess.call(shlex.split(cmd))
			if ret == 0:
				if os.path.isfile(CFG_FILE):
					update_property.write_properties_to_xml(CFG_FILE,"ranger.usersync.policymgr.username",SYNC_POLICY_MGR_USERNAME)
					update_property.write_properties_to_xml(CFG_FILE,"ranger.usersync.policymgr.keystore",SYNC_LDAP_BIND_KEYSTOREPATH)
					update_property.write_properties_to_xml(CFG_FILE,"ranger.usersync.policymgr.alias",SYNC_POLICY_MGR_ALIAS)
				else:
					log("[E] Required file not found: ["+CFG_FILE+"]","error")
			else:
				log("[E] unable to execute command ["+cmd+"]","error")
		else:
			log("[E] unable to execute command ["+cmd+"]","error")
	else:
		log("[E] Input Error","error")

main()
