#!/usr/libexec/platform-python

import os
import sys
import json
import subprocess
import io
from shutil import copyfile
from contextlib import redirect_stdout
from datetime import datetime
import copy
import fileinput
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_smbs_file_path = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files/smbs.yml"
g_smbs_default_file_path = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files/smbs-default.yml"
g_smbs_file_dir = "/usr/share/cockpit/ceph-deploy/ceph-ansible-files"
g_ansible_file_path = "/usr/share/ceph-ansible/group_vars/smbs.yml"

g_inventory_file_key = "smbs.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_smbs_file(smbs_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)

    smbs_file = open(path, "r")
    smbs_file_content = smbs_file.read()
    smbs_file.close()

    # populate the active_directory_info data structure
    start_tag = "##### ceph-deploy:active_directory_info:START #####\n"
    end_tag = "##### ceph-deploy:active_directory_info:END #####\n"
    section_to_replace = smbs_file_content[smbs_file_content.find(start_tag)+len(start_tag):smbs_file_content.rfind(end_tag)]
    

    if smbs_dict["smb_active_directory"] == False:
        # we have to remove any content between our active directory object markers in the file
        smbs_file_content = smbs_file_content.replace(start_tag + section_to_replace + end_tag, start_tag + "\n" + end_tag)
    else:
        # we need to put the active_directory_info object in .yml syntax
        new_content = start_tag + "active_directory_info:\n"
        for field in smbs_dict["active_directory_info"].keys():
            if(smbs_dict["active_directory_info"][field] not in ["yes", "no"]):
                new_content += "  {f}: \"{v}\"\n".format(
                    f=field, v=smbs_dict["active_directory_info"][field])
            else:
                new_content += "  {f}: {v}\n".format(
                    f=field, v=smbs_dict["active_directory_info"][field])
        new_content += end_tag
        smbs_file_content = smbs_file_content.replace(start_tag +
            section_to_replace + end_tag, new_content)

    # populate the ctdb_public_addresses data structure
    start_tag = "##### ceph-deploy:ctdb_public_addresses:START #####\n"
    end_tag = "##### ceph-deploy:ctdb_public_addresses:END #####\n"
    section_to_replace = smbs_file_content[smbs_file_content.find(
        start_tag)+len(start_tag):smbs_file_content.rfind(end_tag)]

    new_content = start_tag + "ctdb_public_addresses:\n"
    for addr_obj in smbs_dict["ctdb_public_addresses"]:
        new_content += "  - "
        for field in addr_obj.keys():
            new_content += "{f}: \"{v}\"\n".format(f=field, v=addr_obj[field])
            new_content += "    "
        new_content = new_content[:-4]
    new_content += end_tag
    smbs_file_content = smbs_file_content.replace(
        start_tag + section_to_replace + end_tag, new_content)

    # finally search each line for simple single variables
    smbs_file_lines = smbs_file_content.split("\n")
    special_keys = ["smb_active_directory", "smb_local_users",
                    "ctdb_public_addresses", "active_directory_info"]

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

    smbs_file_content = "\n".join(smbs_file_lines)
    smbs_file = open(path, "w")
    smbs_file.writelines(smbs_file_content)
    smbs_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_smbs_file_path
    global g_smbs_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 "smbs" in params["groups"].keys():
        make_smbs_file(params["groups"]["smbs"], g_smbs_default_file_path,
                       g_smbs_file_path, g_smbs_file_dir, g_ansible_file_path)
        success_msg = {
            "success_msg": "smbs.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 smbs.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()
