#!/usr/libexec/platform-python

import os
import sys
import json
import subprocess
import io
from shutil import copyfile
from contextlib import redirect_stdout
import fileinput
from datetime import datetime
import copy
import re

g_param_file_path = "/usr/share/cockpit/ceph-deploy/params/core_params.json"
g_param_file_dir = "/usr/share/cockpit/ceph-deploy/params"
g_osds_file_path = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files/osds.yml"
g_osds_default_file_path = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files/osds-default.yml"
g_osds_file_dir = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files"
g_ansible_file_path = "/usr/share/ceph-ansible/group_vars/osds.yml" 
g_inventory_file_key = "osds.yml"

def print_to_string(item):
	with io.StringIO() as buf, redirect_stdout(buf):
		print(item)
		output = buf.getvalue().rstrip("\n")
		return output

def get_parameters(path):
	if os.path.exists(path) and os.path.isfile(path):
		#file exists on disk, load contents and return json object.
		f = open(path,"r")
		param_file_content = print_to_string(f.read())
		f.close()
		try:
			parsed_json = json.loads(param_file_content)
		except ValueError as err:
			# failed to get json from command line arguments
			error_string = print_to_string(err)
			error_msg = { "error_msg":"JSON Parse Error ({p}): ".format(p=g_param_file_path) + error_string }
			print(json.dumps(error_msg,indent=4))
			update_inventory_state(g_inventory_file_key,g_ansible_file_path,True)
			sys.exit(1)
		return parsed_json
	else:
		error_msg = { "error_msg":"File not found ({p}): ".format(p=path) }
		print(json.dumps(error_msg,indent=4))
		update_inventory_state(g_inventory_file_key,g_ansible_file_path,True)
		sys.exit(1)

def make_osds_file(osds_dict,default_path,path,dir,ansible_path):
	if not os.path.exists(dir):
		os.makedirs(dir)
	if os.path.exists(path) and os.path.isfile(path):
		os.remove(path)
	
	try:
		copyfile(default_path,path)
	except OSError as err:
		# print json formatted error
		error_string = print_to_string(err)
		error_msg = { "error_msg":error_string}
		print(json.dumps(error_msg,indent=4))
		update_inventory_state(g_inventory_file_key,g_ansible_file_path,True)
		sys.exit(1)

	osds_file = open(path,"r")
	osds_file_content = osds_file.readlines()
	osds_file.close()

	for option in osds_dict.keys():
		for i in range(len(osds_file_content)):
			regex = re.search("^.*{o}:\s+.*$".format(o=option),osds_file_content[i])
			if regex != None:
				comment = ""
				if isinstance(osds_dict[option], str):
					comment = "#" if (len(osds_dict[option]) == 0) else ""
					osds_file_content[i] = "{c}{o}: {ov}\n".format(c=comment,o=option,ov=osds_dict[option])
				elif osds_dict[option] == None:
					osds_dict[option] = False
					osds_file_content[i] = "{c}{o}: {ov}\n".format(c=comment,o=option,ov=json.dumps(osds_dict[option]))

	osds_file = open(path,"w")
	osds_file.writelines(osds_file_content)
	osds_file.close()

	# overwrite the hosts file in the ceph-ansible directory
	try:
		copyfile(path,ansible_path)
	except OSError as err:
		# print json formatted error
		error_string = print_to_string(err)
		error_msg = { "error_msg":error_string}
		print(json.dumps(error_msg,indent=4))
		update_inventory_state(g_inventory_file_key,g_ansible_file_path,True)
		sys.exit(1)

def update_inventory_state(key,path,failed):
    inv_state_file_path = "/usr/share/cockpit/ceph-deploy/state/inventory_state.json"
    inv_state_file_dir = "/usr/share/cockpit/ceph-deploy/state"

    date = datetime.today()
    time = datetime.now()
    timestamp =  date.strftime("%Y-%m-%d") + time.strftime("-%H-%M")

    state_dict = {}

    new_state = {
        "path":path,
        "failed": failed,
        "timestamp": timestamp
    }

    # check to see if file needs to be created.
    if not os.path.exists(inv_state_file_path):
        # file doesn't exist
        if not os.path.exists(inv_state_file_dir):
            # file directory doesn't exist, make required directories
            os.makedirs(inv_state_file_dir)
        #create new inv state file with default parameters
        state_file = open(inv_state_file_path,"w")
        state_file.write(json.dumps(state_dict,indent=4))
        state_file.close()

    else:
        #file exists on disk, load contents and return json object.
        state_file = open(inv_state_file_path,"r")
        state_file_content = print_to_string(state_file.read())
        state_file.close()
        state_dict = json.loads(state_file_content)
    
    state_dict[key] = copy.deepcopy(new_state)
    state_file = open(inv_state_file_path,"w")
    state_file.write(json.dumps(state_dict,indent=4))
    state_file.close()

def main():
	global g_param_file_path
	global g_param_file_dir
	global g_osds_file_path
	global g_osds_default_file_path
	global g_ansible_file_path
	global g_inventory_file_key
	params = get_parameters(g_param_file_path)
	if "groups" in params.keys() and "osds" in params["groups"].keys():
		make_osds_file(params["groups"]["osds"],g_osds_default_file_path,g_osds_file_path,g_osds_file_dir,g_ansible_file_path)
		success_msg = { "success_msg":"osds.yml file created successfully","path":g_ansible_file_path}
		print(json.dumps(success_msg,indent=4))
		update_inventory_state(g_inventory_file_key,g_ansible_file_path,False)
		sys.exit(0)
	else:
		error_msg = { "error_msg":"unable to make osds.yml"}
		print(json.dumps(error_msg,indent=4))
		update_inventory_state(g_inventory_file_key,g_ansible_file_path,True)
		sys.exit(1)
		
if __name__ == "__main__":
	main()