#!/usr/bin/python3

# -------------------------------------------
# description: Convert a supportconfig to md
# -------------------------------------------
VERSION = '2024-08-27_3'
author = 'Raine Curtis (raine.curtis@suse.com)'

import datetime
import pickle
import os
import sys
import subprocess
import jinja2
import json
import shutil
import unicodedata
import codecs
import tarfile
import xml.etree.ElementTree as ET
from html.parser import HTMLParser
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import random
import matplotlib.colors as mcolors
import pprint


pp = pprint.PrettyPrinter(indent=4)

##sys.setdefaultencoding('utf8')

reset='\033[0m'
bold='\033[01m'
green='\033[00;32m'
green_bold='\033[01;32m'
blue='\033[0;34m'


crm_entries = ['colocation', 'node', 'primitive', 'group', 'clone', 'order', 'property', 'rsc_defaults', 'opt_default', 'ms']

share_path = '/usr/share/supportconfig2report'
ifile_path= ''
TRIM_OUTPUT = False
TRIM_SIZE = 100 
suse_colors= ['#0C322C', '#30BA78', '#192072', '#2453FF', '#90EBCD', '#FE7C3F']
skip_files = ['open-files', 'sysfs']
noprocess_files = ['messages', 'warn']
DEBUG = False

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Found a start tag:", tag)

    def handle_endtag(self, tag):
        print("Found an end tag :", tag)

    def handle_data(self, data):
        print("Found some data  :", data)

def parse_sca_report(src_dir):
    report_name = '{}_report.html'.format(src_dir)
    report_file = open(report_name, 'r')
    report_data = report_file.read()
    report_file.close()
    #print(report_data)
    parser = MyHTMLParser()
    parser.feed(report_data)

def ask_trim():
    global TRIM_SIZE
    q_ask_size = raw_input('The output can be large, do you want to trim output to a limited amount of lines?  [Y|n] ') or 'Y'
    print(q_ask_size)


def open_txt(sfile):
    data = []
    srcfile = open(sfile, 'r', encoding='latin1')
    for line in srcfile.readlines():
        if isinstance(line, str):
            line = line.encode('ascii', 'replace').strip()
            try:
                line = line.decode()
            except:
                line = line
        elif isinstance(line, unicode):
            print(type(line))
            line = line.strip()
        if not line.startswith('====================================='):
            data.append(line)
    srcfile.close()
    return data


def write_md(tfile, data, tgt_dir):
    HEADER_LENGTH = 50
    last_dot_index = tfile.rindex('.')

    tfile_base = tfile[0:last_dot_index]

    tfile_label = tfile_base
    file_extension = ''
    #for np in noprocess_files:
    #    if np in tfile_base: 
    #        #print("NO process: " + tfile_base)
    #        tfile_extension =  ".EXCLUDED_MD"
    #        break
    #    else:
    #        #print("process: " + tfile_base)
    #        tfile_extension =  ".md"
    # Delete the following line if uncomment above
    tfile_extension =  ".md"

    tfile = tgt_dir + '/md/' + tfile_base + tfile_extension
    print('TARGET FILE: {}'.format(tfile))
    tgtfile = open(tfile, 'w')
    previous_literal = False
    header_found = False
    section_size = 0
    code_block = False
    section_type = ''

    tgtfile.write("--- \n")
    tgtfile.write("##################################################################\n")
    tgtfile.write("# YAML Header for document metadata\n")
    tgtfile.write("##################################################################\n")
    tgtfile.write("# Document class can be [article | report]\n")
    tgtfile.write("documentclass: article\n")
    tgtfile.write("title: | \n")
    tgtfile.write("       Support Configuration \n")
    tgtfile.write("       ![](images/suse-logo.png){width=\"400px\" margin-right=\"auto\"  margin-left=\"auto\"}  \n")
    tgtfile.write("author: SUSE Support\n")
    tgtfile.write("subtitle: {} Report \n".format(tfile_label))
    tgtfile.write("abstract: Formatted report of SUSE supportconfig data for " + report_host + " \n")
    tgtfile.write("fontfamily: DejaVu Sans\n")
    tgtfile.write("mainfont: DejaVu Sans\n")
    tgtfile.write("monfont: DejaVu Sans Mono\n")
    tgtfile.write("classoption:\n")
    tgtfile.write(" - landscape\n")
    tgtfile.write(" \n")
    tgtfile.write("##################################################################\n")
    tgtfile.write("# Document in markdown starts below  (dots) ...\n")
    tgtfile.write("##################################################################\n")
    tgtfile.write("...\n")
    tgtfile.write(" \n")
    tgtfile.write("# Executive Summary \n")
    tgtfile.write(" \n")
    exec_sum_data='''The SUSE ``supportconfig`` utility gathered system information on the server. 

## Overview

After a review of the support configuration information gathered, the
system appears to be...

## Next Steps

Additional information is provided in the following sections of this document. 

'''

    tgtfile.write(exec_sum_data)
    tgtfile.write("\n \n")
    # Write section title
    #tgtfile.write("\n# {}\n\n".format(tfile_label))
    for line in data:
        if line.startswith('#==['):
            header_found = True
            section_size = 0
            pre_idx = line.index(' ')
            post_idx = line.rindex(' ')
            section_type = line[(pre_idx + 1):post_idx]
            continue
        elif 'Support Utilities - Supportconfig' in line:
            section_type == '## Utility Information'
            line = '## {} \n\n```\n\n'.format(line)
            tgtfile.write(line)

        elif header_found:
            if previous_literal:
                tgtfile.write('```\n')
            #tgtfile.write('\n \\newpage \n\n')

            ## -- Lines in support config beginning 
            ##    with '#' are the commands.
            if line.startswith('# '):
                after_space = line.index(' ')
                line = line[after_space:].strip()
                title = '{}({}): {}'.format(tfile_label.upper(), section_type, line)
            else:
                line = line.strip()
                title = '{}: {}'.format(tfile_label.upper(), line)
            if len(title) >= HEADER_LENGTH:
                title = '{}...'.format(title[:HEADER_LENGTH])
            #tgtfile.write('\n\\pagebreak \n\n')
            title_line = '# {}'.format(title)
            line = line.strip()
            tgtfile.write('{}\n'.format(title_line))
            #tgtfile.write('-' * len(title_line))
            tgtfile.write('\n\n')
            tgtfile.write('**Command / Description:**')
            tgtfile.write('\n\n')
            tgtfile.write('```bash\n')
            tgtfile.write('{}\n```'.format(line))
            tgtfile.write('\n\n')
            tgtfile.write('**Output:**')
            tgtfile.write('\n\n')
            tgtfile.write('```bash\n')
            header_found = False
            code_block = True
        else:
            previous_literal = True
            if code_block:
                code_block = False
                if line == '':
                    line = '### no output ###'
            if TRIM_OUTPUT:
                section_size += 1
                #print('section size: {}'.format(section_size))
                if section_size <= TRIM_SIZE:
                    tgtfile.write('{}\n'.format(line))
                if section_size == TRIM_SIZE:
                    tgtfile.write('### output trimmed to {} lines ### \n'.format(TRIM_SIZE))
            else:
                tgtfile.write('{}\n'.format(line))
    if previous_literal:
        tgtfile.write('```\n')
    tgtfile.close()
    if tfile.endswith('.md'):
        build_docx(tgt_dir, tfile, tfile_base)
        build_html(tgt_dir, tfile, tfile_base)


def build_docx(tgt_dir, tfile,  tfile_base):
    #print(os.getcwd())
    os.chdir(tgt_dir)
    #print(os.getcwd())
    docx_path = "{}/docx/{}.docx".format(tgt_dir, tfile_base)
    print("DOCX REPORT FILE: {}".format(docx_path))
    #PANDOC_CMD = "pandoc {} --reference-doc=resources/suse-white-paper-template-landscape.docx  -o {}".format(tfile, docx_path)
    PANDOC_CMD = "pandoc {} --reference-doc=resources/suse-white-paper-template.docx --table-of-contents --number-sections -V toc-title:\"Contents\"  -o {}".format(tfile, docx_path)
    rc = subprocess.call(PANDOC_CMD, shell=True)
    print("Build returned: {} ".format(rc))



def build_html(tgt_dir, tfile,  tfile_base):
    #print(os.getcwd())
    html_dir = '{}/html'.format(tgt_dir)
        
    # -- copy html/images for any updated images
    src = '{}/images'.format(tgt_dir)
    tgt = '{}/html/images'.format(tgt_dir)
    image_files = os.listdir(src)
    image_files.sort()

    for image_file in image_files:
        src = '{}/images/{}'.format(tgt_dir, image_file)
        print('copying {} to {}'.format(src, tgt))
        ret = shutil.copy(src, tgt)
        try:
            ret = shutil.copy(src, tgt)
        except Exception as e:
            print('{} already there'.format(image_file))

    # -- build the html format
    html_path = "{}/html/{}.html".format(tgt_dir, tfile_base)
    os.chdir(html_dir)
    print("CURRENT BUILD DIR: {}".format(os.getcwd()))
    print("HTML REPORT FILE: {}".format(html_path))
    PANDOC_CMD = "pandoc --standalone  --highlight-style=resources/suse.theme --css=resources/suse.css --metadata date=\"$(date \"+%B %d, %Y\")\"   --table-of-contents   --number-sections -V toc-title:\"Contents\" -V mainfont=\"Poppins\" -V monofont=\"DejaVu Sans Mono\" -V colorlinks -V linkcolor=\"RedOrange\"  -V urlcolor=\"NavyBlue\" -V toccolor=\"PineGreen\" -V geometry:\"top=1in, bottom=1in, left=1in, right=1in\"  {} -o {}".format(tfile, html_path)
    rc = subprocess.call(PANDOC_CMD, shell=True)
    #print('PANDOC_CMD: {}'.format(PANDOC_CMD))
    print("Build returned: {} ".format(rc))


def get_hostname(src_dir):
    # hostname in summary xml
    summary_xml = '{}/summary.xml'.format(src_dir)
    #print(summary_xml)
    # BUG: summary from supportconfig contains malformed xml
    # so have to read as text file until hostname line.

    if os.path.isfile(summary_xml):
        print('Opening summary.xml')
        xfile = open(summary_xml, 'r')
        xdata = ET.fromstring(xfile.read())
        print(xdata)
        #for line in xfile.readlines():
        #    print(line)
        #    if '<hostname>' in line:
        #        xroot = ET.fromstring(line)
        #        return xroot.text
        xfile.close()
    else:
        print('Error opening summary.xml')
        exit()

def get_server_info(src_dir):
    server = {}
    summary_xml = '{}/summary.xml'.format(src_dir)
    sum_data = ''
    sum_line = 1
    if os.path.isfile(summary_xml):
        print('found summary.xml')
        sum_file = open(summary_xml)
        for line in sum_file.readlines():
            #print(line)
            if sum_line == 2:
                sum_data += '<doc>\n'
                sum_data += line
            else:
                sum_data += line
            sum_line += 1
    else:
        print('The file: \n{}\n cannot be found. \n{}Is the tarball the same name as the directory extracted?{}'.format(summary_xml, bold, reset))
        print('Rename the tarball to be the name as the directory extracted.')
        exit(1)
    sum_data += '</doc>'
    of = open('server.xml', 'w')
    of.write(sum_data)
    of.close()
    #print(sum_data)
    xdoc = ET.fromstring(sum_data)
    server['Script Run Date'] = xdoc.find('summary/rundate').text
    server['Script Run Time'] = xdoc.find('summary/runtime').text
    server['Hostname'] = xdoc.find('summary/hostname').text
    server['Arch'] = xdoc.find('summary/arch').text
    server['Kernel'] = xdoc.find('summary/kernel').text
    server['SLE Type'] = xdoc.find('summary/sle_type').text
    server['SLE Version'] = xdoc.find('summary/sle_version').text
    server['SLE Patchlevel'] = xdoc.find('summary/sle_patchlevel').text
    products = xdoc.findall('products/product')
    installed_products = ''
    for product in products:
        #print(product.tag)
        for item in product:
            #print(item.tag)
            if item.tag == 'summary':
                if installed_products == '':
                    installed_products = item.text
                else:
                    installed_products += ', {}'.format(item.text)
    server['Products'] = installed_products
    return server


def write_profile(server_data, tgt_dir, pfile):
    pfile_base = 'server_report'
    profile_path = '{}/md/{}.md'.format(tgt_dir,pfile_base)
    
    runhour = int(server_data['Script Run Time'][:2])
    runminute = int(server_data['Script Run Time'][-2:])
    runyear = int('20{}'.format(server_data['Script Run Date'][:2]))
    runmonth = int('{}'.format(server_data['Script Run Date'][2:4]))
    runday = int('{}'.format(server_data['Script Run Date'][-2:]))
    rundate = datetime.datetime(runyear, runmonth, runday, runhour, runminute)
    script_ran_on =  rundate.strftime('%B %d, %Y %H:%M')

    pfile = open(profile_path, 'w')
    pfile.write("--- \n")
    pfile.write("##################################################################\n")
    pfile.write("# YAML Header for document metadata\n")
    pfile.write("##################################################################\n")
    pfile.write("# Document class can be [article | report]\n")
    pfile.write("documentclass: article\n")
    pfile.write("title: | \n")
    pfile.write("       Support Configuration Report\n")
    pfile.write("       ![](images/suse-logo.png){width=\"400px\" margin-right=\"auto\"  margin-left=\"auto\"}  \n")
    pfile.write("author: SUSE Support\n")
    pfile.write("subtitle: Server Report \n")
    pfile.write("abstract: Formatted report of SUSE supportconfig data for" + server_data['Hostname'] + " \n")
    pfile.write("classoption:\n")
    pfile.write(" - landscape\n")
    pfile.write(" \n")
    pfile.write("##################################################################\n")
    pfile.write("# Document in markdown starts below  (dots) ...\n")
    pfile.write("##################################################################\n")
    pfile.write("...\n")
    pfile.write(" \n")
    pfile.write("# Executive Summary \n")
    pfile.write(" \n")
    exec_sum_data='''The SUSE ``supportconfig`` utility gathered system information on the server. 

## Overview

After a review of the support configuration information gathered, the
system appears to be...

## Next Steps

Additional information is provided in the following sections of this document. 

'''

    pfile.write(exec_sum_data)
    pfile.write("\n \n")
    pfile.write('This Support Configuration gathered on: **{}**\n\n'.format(script_ran_on))

    pfile.write('# System Profile \n\n')
    pfile.write('The basic system environment is: \n\n')

    pfile.write('|  |  |\n')
    pfile.write('| --------- | --------- |\n')

    for key, value in server_data.items():
        if 'Script Run Date' in key:
            continue
        elif 'Script Run Time' in key:
            continue
        pfile.write('| **{}** | {}  | \n'.format(key, value))
    pfile.write('\n')
    pfile.close()


def prep_env(dir_path):
    if not os.path.isdir(dir_path):
        os.makedirs(dir_path)
        print('DIRECTORY: {} created'.format(dir_path)) 
        # REMOVE os.makedirs(pages_path)
        # REMOVE print('PAGES DIRECTORY: {} created'.format(pages_path)) 
    else: 
        print('DIRECTORY: {} already exists'.format(dir_path))
    if os.path.isfile(ifile_path):
        os.remove(ifile_path)

def build_project(dir_path, report_host):
    # -- copy images
    src = '{}/images'.format(share_path)
    tgt = '{}/images'.format(dir_path)
    print('copying {}'.format(src))
    try:
        ret = shutil.copytree(src, tgt)
    except Exception as e:
        print('{} already there'.format(src))

    # -- copy resources
    src = '{}/resources'.format(share_path)
    tgt = '{}/resources'.format(dir_path)
    print('copying {}'.format(src))
    try:
        ret = shutil.copytree(src, tgt)
    except Exception as e:
        print('{} already there'.format(src))

    # -- copy py
    src = '{}/py'.format(share_path)
    tgt = '{}/py'.format(dir_path)
    print('copying {}'.format(src))
    try:
        ret = shutil.copytree(src, tgt)
    except Exception as e:
        print('{} already there'.format(src))

    # -- create md dir
    tgt = '{}/md'.format(dir_path)
    print('Creating{}'.format(tgt))
    try:
        ret = os.mkdir(tgt)
    except Exception as e:
        print('{} already there'.format(tgt))

    # -- create docx dir
    tgt = '{}/docx'.format(dir_path)
    print('Creating{}'.format(tgt))
    try:
        ret = os.mkdir(tgt)
    except Exception as e:
        print('{} already there'.format(tgt))

    # -- HTML OUTPUT ---
    # -- create html dir
    tgt = '{}/html'.format(dir_path)
    print('Creating{}'.format(tgt))
    try:
        ret = os.mkdir(tgt)
    except Exception as e:
        print('{} already there'.format(tgt))

    # -- create html/images dir
    tgt = '{}/html/images'.format(dir_path)
    print('Creating{}'.format(tgt))
    try:
        ret = os.mkdir(tgt)

    except Exception as e:
        print('{} already there'.format(tgt))

    # -- copy html/resources
    src = '{}/resources'.format(tgt_dir)
    tgt = '{}/html/resources'.format(tgt_dir)
    print('# copying {} to {}'.format(src, tgt))
    try:
        ret = shutil.copytree(src, tgt)
    except Exception as e:
        print('{} already there'.format(src))

    _write_index_html(dir_path)

def _write_nav_html(tgt_dir):
    html_dir = '{}/html'.format(tgt_dir)
    print(html_dir)

    html_files = os.listdir(html_dir)
    html_files.sort()

    # Create nav page
    nav_html = '{}/nav.html'.format(html_dir)
    navfile = open(nav_html, 'w')
    nav_header = '''
<html>
<style>
body{ background-color: #0C322C; } 
p { 
  color: #ffffff; 
  font-family: "Helvetica";
} 
a:link { 
  color: #90EBCD; 
  font-family: "Helvetica";
  font-weight: "bold";
  text-decoration: none;
} 
a:visited{ 
  color: #90EBCD; 
  font-family: "Helvetica";
  font-weight: "bold";
  text-decoration: none;
} 
a:hover{ 
  color: #FE7C3F; 
  font-family: "Helvetica";
  font-weight: "bold";
  text-decoration: none;
} 
</style>
    <body>
    <p><b>SUSE Support Configuration Reports</b></p>
    <p><a href="server_report.html" target="content">Server Report</a></p>
    <p><a href="../docx" target="content">Document Files</a></p>
    <p><a href="../md" target="content">Markdown Files</a></p>
    <hr>
'''

    nav_footer = '''
    </body>
</html>
'''
 
    navfile.write(nav_header)  
    for hfile in html_files:
        file_parts = hfile.split('.')
        navfile.write('<p><a href=\"{}\" target=\"content\">{}</a></p>\n'.format(hfile, file_parts[0]))
    navfile.write(nav_footer)  
    navfile.close()




def _write_index_html(dir_path):
    index_html = '{}/index.html'.format(dir_path)
    idxfile = open(index_html, 'w')
    idx_contents = '''
<HTML>
    <HEAD>
        <title>SUSE Supportconfig Reports</title>
    </HEAD>
<STYLE>
#navDiv {
    display: inline-block;
    height: 100%;
    vertical-align: top;
    width: 10%;
    border: 0;
}

#contents, #content {
    height: 100%;
    width: 100%;
}

#contentDiv {
    display: inline-block;
    height: 100%;
    vertical-align: top;
    width: 89.5%;
    border: 0;
}
body { margin: 0}
</STYLE>
</HEAD>
<BODY >
<!-- Generated from supportconfig2md utility -->
<DIV id="navDiv">
    <IFRAME frameBorder="0" name="nav"  id="contents" src="html/nav.html">
    </IFRAME>
</DIV>
<DIV id="contentDiv">
    <IFRAME frameBorder="0" name="content" id="content" src="html/server_report.html">
    </IFRAME>
</DIV>
</BODY>
</HTML>
    '''
    idxfile.write(idx_contents)
    idxfile.close()
    


def write_index_md(dir_path, report_host):
    index_md_file = '{}/0000-index.md'.format(dir_path)
    ifile = open(index_md_file, 'w')
    ifile.write("--- \n")
    ifile.write("##################################################################\n")
    ifile.write("# YAML Header for document metadata\n")
    ifile.write("##################################################################\n")
    ifile.write("# Document class can be [article | report]\n")
    ifile.write("documentclass: article\n")
    ifile.write("title:  |\n")
    ifile.write("        Support Configuration Report \ \n")
    ifile.write("        \ \n")
    ifile.write("        ![](images/suse-logo.png){width=\"100px\" margin-right=\"auto\"  margin-left=\"auto\"} \ \n")
    ifile.write("author: {}, SUSE Support\n".format(author))
    ifile.write("subtitle: for "  +  report_host +  "\n")
    ifile.write("abstract: Formatted report of SUSE supportconfig data.\n")
    ifile.write("classoption:\n")
    ifile.write(" - landscape\n")
    ifile.write(" \n")
    ifile.write("##################################################################\n")
    ifile.write("# Document in markdown starts below  (dots) ...\n")
    ifile.write("##################################################################\n")
    ifile.write("...\n")
    ifile.write(" \n")
    ifile.write("# Executive Summary \n")
    ifile.write(" \n")
    exec_sum_data='''The SUSE ``supportconfig`` utility gathered system information on the server. 

## Overview

After a review of the support configuration information gathered, the
system appears to be...

## Next Steps

Additional information is provided in the following sections of this document. 

A **technical summary**
is provided in the next section. It is recommended that technical members
of the team review that section.

The **remaining sections** show the information gathered from the system and
may be referred to as needed. Each sub-section shows how the information
was gathered.'''

    ifile.write(exec_sum_data)
    ifile.write("\n \n")
    ifile.close()

def process_files(working_dir, scc_dir, report_host, server_data):
    print('WORKING DIRECTORY: {}'.format(scc_dir))
    support_config_files = os.listdir(scc_dir)
    support_config_files.sort()
    i = 10
    skip_flag = False
    kernel = []
    netinfo = {}
    cpuinfo = {}
    hainfo = {}
    for tfile in support_config_files:
        if tfile.endswith('.txt'): 
            for skip in skip_files:
                if skip in tfile:
                    skip_flag = True
            if skip_flag:
                skip_flag = False
                continue
            sfile = os.path.join(scc_dir,tfile)
            if os.path.isfile(sfile):
                print('SOURCE FILE processing: {}'.format(sfile))
                data = open_txt(sfile)
                if 'basic-health-check' in tfile:
                    make_basic_partitions_chart(data, tgt_dir)
                    make_basic_inodes_chart(data, tgt_dir)
                    make_basic_memory_chart(data, tgt_dir)
                    kernel = get_kernelinfo(data)
                elif 'network' in tfile:
                    netinfo = get_netinfo(data)
                elif 'basic-environment' in tfile:
                    platform = get_platform(data)
                elif 'hardware' in tfile:
                    cpuinfo = get_cpuinfo(data)
                elif 'ha' in tfile:
                    hainfo = ha_report.get_hainfo(data)
                if 'public_cloud' in sfile:
                    tfile = 'public_cloud_{}'.format(tfile)
                #tfile = '{:04d}-{}'.format(i, tfile)
                #tfile = '{}'.format(tfile)
                write_md(tfile, data, tgt_dir)
                i += 1

    # Write ha report
    pp.pprint(hainfo)
    if hainfo:
        if DEBUG: print("DEBUG: writing ha_report")
        file_base = 'ha_report'
        ha_path = '{}/md/{}.md'.format(tgt_dir,file_base)
        ha_report.write_ha_report(tgt_dir, ha_path, file_base, hainfo, report_host)
        build_docx(tgt_dir, ha_path, file_base)
        build_html(tgt_dir, ha_path, file_base)

    # Write server profile
    pfile_base = 'server_report'
    profile_path = '{}/md/{}.md'.format(tgt_dir,pfile_base)
    write_profile(server_data, tgt_dir, profile_path)
    write_kernelinfo(kernel, tgt_dir, profile_path)
    write_platform(platform, profile_path)
    write_cpuinfo(cpuinfo, profile_path)
    write_memoryinfo(profile_path)
    write_netinfo(netinfo, tgt_dir, profile_path)
    write_storageinfo(profile_path)
    build_docx(tgt_dir, profile_path, pfile_base)
    build_html(tgt_dir, profile_path, pfile_base)

    # Write nav html
    _write_nav_html(tgt_dir)



def write_memoryinfo(mem_path):
    print(mem_path)
    mfile = open(mem_path, 'a')
    mfile.write('\n\n')
    mfile.write('# Memory \n \n')
    mfile.write('The percentages of memory utilization is: \n\n')
    mfile.write(" ![](images/memory-stats.png){height=\"6in\" margin-right=\"auto\"  margin-left=\"auto\"} \n \n")
    mfile.write('\n\n')
    mfile.close()

def write_storageinfo(storage_path):
    print(storage_path)
    sfile = open(storage_path, 'a')
    sfile.write('\n\n')
    sfile.write('# Storage  \n \n')
    sfile.write('The percentage of filesystem utilization by mountpoint is: \n\n')
    sfile.write(" ![](images/partition-percents.png){height=\"6in\" margin-right=\"auto\"  margin-left=\"auto\"} \n \n")

    sfile.write('The percentage of filesystem inode utilization by mountpoint is: \n\n')
    sfile.write(" ![](images/partition-inodes.png){height=\"6in\" margin-right=\"auto\"  margin-left=\"auto\"} \n \n")
    #sfile.write(" ![](images/partition-percents.png){width=\"100px\" margin-right=\"auto\"  margin-left=\"auto\"}  \n")

    sfile.write('\n\n')
    sfile.close()


def write_netinfo(server_data, tgt_dir, net_path):
    print(net_path)
    nfile = open(net_path, 'a')
    nfile.write('\n\n')
    nfile.write('#  Network \n \n')
    nfile.write('Network interface and IP addresses are: \n\n')

    nfile.write('|  |  |\n')
    nfile.write('| --------- | --------- |\n')

    for key, value in server_data.items():
        nfile.write(' | **{}** | {} | \n'.format(value, key))
    nfile.write('\n\n')
    nfile.close()


def write_cpuinfo(server_data, cpu_path):
    print(cpu_path)
    cfile = open(cpu_path, 'a')
    cfile.write('# CPU Architecture \n\n')
    cfile.write('The following CPU information is: \n\n')

    cfile.write('|  |  |\n')
    cfile.write('| --------- | --------- |\n')

    for key, value in server_data.items():
        cfile.write(' |**{}** | {} |\n'.format(key, value))
    cfile.write('\n\n')
    cfile.close()

def write_kernelinfo(server_data, tgt_dir, tfile):
    kernel_path = tfile
    print(kernel_path)
    kfile = open(kernel_path, 'a')
    kfile.write('\n\n')
    kfile.write('# Linux Kernel \n\n')
    kfile.write('The following shows the support status of kernel modules: \n')
    kfile.write('```bash\n')

    for value  in server_data:
        kfile.write('    {}\n'.format(value))

    kfile.write('```\n\n')
    kfile.close()

def write_platform(server_data, platform_path):
    print(platform_path)
    pfile = open(platform_path, 'a')
    pfile.write('# System Platform\n\n')
    pfile.write('Server platform information: \n\n')

    pfile.write('|  |  |\n')
    pfile.write('| --------- | --------- |\n')

    for key, value in server_data.items():
        pfile.write('|**{}** | {} | \n'.format(key, value))
    pfile.write('\n\n')
    pfile.close()


def get_netinfo(server_data):
    net_data = {}
    needed = False
    for item in server_data:
        if '/sbin/ip addr' in item:
            needed = True
            continue
        if needed:
            if item.startswith('#==[ '):
                needed = False
                break
            else:
                if 'inet' in item:
                    parts = item.split()
                    key = '{}: {}'.format(parts[-1], parts[1])
                    value = 'ipv4'
                    net_data[key] = value
                if 'inet6' in item:
                    parts = item.split()
                    key = '{}: {}'.format(parts[-1], parts[1])
                    value = 'ipv6'
                    net_data[key] = value
    return net_data


def get_kernelinfo(server_data):
    kernel_data = []
    needed = False
    for item in server_data:
        if '/proc/sys/kernel/tainted' in item:
            needed = True
            continue
        if needed:
            if item.startswith('#==[ '):
                needed = False
                break
            else:
                kernel_data.append(item)
    return kernel_data

def get_cpuinfo(server_data):
    cpu_data = {}
    needed = False
    for item in server_data:
        if '/usr/bin/lscpu' in item:
            needed = True
            continue
        if needed:
            if item != '':
                #print(item)
                if 'CPU(s)' in item or 'Thread(s)' in item or 'Core(s) per socket' in item or 'Socket(s)' in item or 'Model name' in item:
                    key, value = item.split(':')
                    cpu_data[key.strip()] = value.strip()
            else:
                needed = False
                break
    return cpu_data

def get_platform(server_data):
    platform_data = {}
    needed = False
    for item in server_data:
        if 'Virtualization' in item:
            needed = True
            continue
        if needed:
            if item != '':
                #print(item)
                key, value = item.split(':')
                platform_data[key.strip()] = value.strip()
            else:
                needed = False
                break
    return platform_data

def make_basic_memory_chart(data, tgt_dir):
    memory_stats = {} 
    needed = False
    for item in data:
        if '/usr/bin/free -k' in item:
            needed = True
            continue
        if needed:
            if item.startswith('total'):
                continue
            if item != '':
                if 'Mem:' in item:
                    print(item)
                    parts = item.split()
                    #                total        used        free      shared  buff/cache   available
                    # Mem:    23830417456  5452351212 18131177712   146839488   469804016 18378066244
                    percent_used = 10 * int(parts[2])/int(parts[1])
                    percent_avail = 10 * int(parts[6])/int(parts[1])
                    mem_used, mem_used_unit = convert_number(parts[2], 'KB')
                    mem_avail, mem_avail_unit = convert_number(parts[6], 'KB')
                    mem_total, mem_total_unit = convert_number(parts[1], 'KB')
                    mem_title = 'Memory {} {} total'.format(mem_total, mem_total_unit)
                    print(mem_used, mem_avail)
                    memory_stats['used {} {}'.format(mem_used, mem_used_unit)] = percent_used
                    memory_stats['free {} {}'.format(mem_avail, mem_avail_unit)] = percent_avail
                    break
            else:
                needed = False
                break
    make_piechart(memory_stats, tgt_dir, 'memory-stats.png', 10, 10, mem_title)

def convert_number(data_number, data_unit):
    print(str(data_number))
    data_number = float(data_number) / 1000
    data_unit = 'MB'
    data_number = float(data_number) / 1000
    data_unit = 'GB'
    data_number = float(data_number) / 1000
    data_unit = 'TB'
    data_number = "{:.2f}".format(data_number)
    return (data_number, data_unit)


def make_basic_inodes_chart(data, tgt_dir):
    inode_percents = {} 
    needed = False
    for item in data:
        if '/bin/df -i' in item:
            needed = True
            continue
        if needed:
            if item.startswith('Filesystem'):
                continue
            if item != '':
                parts = item.split()
                partition_name = '{} ({}/{})'.format(parts[5], parts[2], parts[1])
                if '%' in parts[4]:
                    partition_size = int(parts[4][:-1])
                elif '-' in parts[4]:
                    partition_size = 0
                else:
                    partition_size = int(parts[4])

                inode_percents[partition_name] = partition_size
            else:
                needed = False
    #make_doughnutchart(inode_percents, tgt_dir, 'partition-inodes.png', 20, 20)
    #make_barchart(inode_percents, tgt_dir, 'partition-inodes.png', 20, 20)
    make_barchart(inode_percents, tgt_dir, 'partition-inodes.png', 20, 20, 'iNodes by Partitions', 'Percentage Used', 'Partitions')

def make_basic_partitions_chart(data, tgt_dir):
    partition_percents = {} 
    needed = False
    for item in data:
        if '/bin/df -h' in item:
            needed = True
            continue
        if needed:
            if item.startswith('Filesystem'):
                continue
            if item != '':
                parts = item.split()
                partition_name = '{} ({}/{})'.format(parts[5], parts[2], parts[1])
                if '%' in parts[4]:
                    partition_size = int(parts[4][:-1])
                elif '-' in parts[4]:
                    partition_size = 0
                else:
                    partition_size = int(parts[4])
                partition_percents[partition_name] = partition_size
            else:
                needed = False
    ####make_doughnutchart(partition_percents, tgt_dir, 'partition-percents.png', 19, 19)
    make_barchart(partition_percents, tgt_dir, 'partition-percents.png', 19, 19, 'Used Space of Partitions', 'Percentage Used', 'Partitions')

def make_barchart(data, tgt_dir, graph_file='graph.png', height=9, width=6, title='Chart', xaxis='x axis', yaxis='y axis'):
    graph_file = '{}/images/{}'.format(tgt_dir, graph_file)
    labels = []
    sizes = []
    for key, value in data.items():
        labels.append(key)
        sizes.append(value)
    ### Set bar colors
    total_colors_needed = len(labels)
    plt_colors = []
    x=0
    y=0
    while y < total_colors_needed:
        print(suse_colors[x])
        plt_colors.append(suse_colors[x])
        if x == len(suse_colors) - 1:
            x= 0
        else:
            x = x + 1
        y = y + 1
    #pp.pprint(plt_colors)
    #print(len(labels))
    #print(len(plt_colors))

    fig = plt.figure()
    fig.set_size_inches(height, width)

    plt.barh(labels, sizes, color=plt_colors)
    for index, value in enumerate(sizes):
        plt.text(value, index, str(value) + '%')
    plt.ylabel(yaxis, fontsize=14, color=suse_colors[1])
    plt.xlabel(xaxis, fontsize=14, color=suse_colors[2])
    plt.title(title, fontsize=16, color=suse_colors[5])
    fig.tight_layout()
    plt.legend(loc='center')
    plt.savefig(graph_file)
    #pp.pprint(data)
    #plt.show()
    plt.close('all')
    print('Saved in {}'.format(graph_file))
    

def make_doughnutchart(data_dict, tgt_dir, pie_file='foo.png', height=9, width=6):
    pie_file = '{}/images/{}'.format(tgt_dir, pie_file)
    labels = []
    sizes = []
    for key, value in data_dict.items():
        labels.append(key)
        sizes.append(value)

    #print(labels)
    #print(sizes)
    #print(pie_file)
    #print(height)
    #print(width)

    fig = plt.figure()
    fig.set_size_inches(height, width)                                                
    patches, texts, autotexts  = plt.pie(sizes, 
            labels=labels,
            #textprops={'size': 'smaller'}, 
            #shadow = True, 
            autopct='%1.1f%%')

    #draw a circle at the center of pie to make it look like a donut
    centre_circle = plt.Circle((0,0),0.75,color='white', fc='white',linewidth=4.25)
    fig = plt.gcf()
    fig.gca().add_artist(centre_circle)
    
    
    # Set aspect ratio to be equal so that pie is drawn as a circle.
    plt.axis('equal')
    plt.legend(loc='center')
    plt.savefig(pie_file)
    plt.close('all')

def make_piechart(data_dict, tgt_dir, pie_file='foo.png', height=9, width=6, title=""):
    labels = []
    sizes = []
    for key, value in data_dict.items():
        labels.append(key)
        sizes.append(value)

    #pie_file = '{}/pages/tech_summary/{}'.format(tgt_dir, pie_file)
    pie_file = '{}/images/{}'.format(tgt_dir, pie_file)
    #print(labels)
    #print(sizes)
    #print(pie_file)
    #print(height)
    #print(width)
    # -- legend conf
    fig = plt.figure()
    fig.set_size_inches(height, width)                                             
    patches, texts, autotexts  = plt.pie(sizes, 
            labels=labels, 
            colors=[suse_colors[1], suse_colors[4]],
            #textprops={'size': 'smaller'}, 
            #shadow = True, 
            autopct='%1.1f%%')
    plt.legend()
    plt.title(title, fontsize=16, color=suse_colors[0])
    fig.tight_layout()
    plt.savefig(pie_file)
    plt.close('all')

    ###plt.legend(bbox_to_anchor=(0,1,1,0), loc='upper left' )
    ##plt.setp(autotexts, size='x-small')
    ##plt.axis('equal')
    ##plt.savefig(pie_file)
    ##### #print(ret)

##def make_piechart(data_dict, pie_file='foo.png', lables=[], sizes=[] ):
##    labels = []
##    sizes = []
##    for key, value in data_dict.items():
##        lables.append(key)
##        sizes.append(value)
##    # Data to plot
##    #labels = ['SLES', 'SLES4SAP', 'RHEL', 'Ubuntu']
##    #sizes = [215, 130, 245, 210]
##    #colors = ['green', 'yellowgreen', 'red', 'orange']
##    #explode = (0.1, 0, 0, 0)  # explode 1st slice
##    # Plot
##    #plt.pie(sizes, labels=labels, shadow=True, startangle=40)
##    #plt.pie(sizes, labels=labels, 
##    #plt.pie(sizes, explode=explode, labels=labels, colors=colors,
##    ##plt.pie(sizes, labels=labels, 
##    ##autopct='%4.1f%%', shadow=True, startangle=140)
##    plt.pie(sizes, labels=labels)
##    plt.axis('equal')
##    #plt.show()
##    plt.savefig('foo.png')


def extract_tarball(tarball):
    cwd = os.getcwd()
    try:
        print('Extracting supportconfig tarball: {}{}{} \nPlease wait...'.format(bold, tarball, reset))
        tf = tarfile.open(tarball)
        tf.extractall()
        tf.close()
    except:
        print('error extracting supportconfig tarball')

def show_utility_info():
  print('{}SUSE Supportconfig to Markdown Utility{}'.format(green_bold, reset))
  print('by {}Raine Curtis (raine.curtis@suse.com){}'.format(green, reset))
  print('ver.{} {}{}'.format(blue, VERSION, reset))

def usage():
  print('usage:{} {} {}<supportconfig> <trim_size>'.format(bold, sys.argv[0], reset))
  print('{}<supportconfig>{}: path to the supportconfig archive (.tbz)'.format(blue, reset))
  print('{}<trim_size>{}: trim the output of each command to this number of lines'.format(blue, reset))
  print('Default trim size is {}100{} lines. \nSet to {}0{} for no trimming of output, but can take a long time to process.'.format(bold, reset, bold, reset))
  #print('Extract the tarball before running: {}\n\ntar xjvf <file>.tbz{}\n'.format(bold, reset))
  print('\n')


# ######################################################
# =======================  main start ================== 
# ######################################################
show_utility_info()
if len(sys.argv) < 2:
    usage()
    exit()

if len(sys.argv) == 3:
    TRIM_SIZE = int(sys.argv[2])
if TRIM_SIZE !=0:
    TRIM_OUTPUT = True

# -- setup environment
cwd = os.getcwd()

# -- import additional modules path
mod_dir = '{}/py'.format(share_path)
sys.path.append(mod_dir)
#print('sys.path: {}'.format(sys.path))
import ha_report

# -- extract tarball
tarball = sys.argv[1]
extract_tarball(tarball)

# -- process support config files
extracted_dir, extension = tarball.split('.')
src_dir = '{}/{}'.format(cwd, extracted_dir)
tgt_dir = '{}/reports/{}'.format(cwd, extracted_dir)
ifile_path = '{}/00-index.md'.format(tgt_dir)

# -- DEBUG
print(src_dir)
print(tgt_dir)
print(ifile_path)

# -- prep report directory
prep_env(tgt_dir)

# -- get basic server information
server_data = get_server_info(src_dir)
report_host = server_data.get('Hostname')

## -- build sphinx project
build_project(tgt_dir, report_host)

## -- process file in current directory
process_files(cwd, src_dir, report_host, server_data)

# TODO: Cleanup 
#write_profile(server_data, tgt_dir)

##cloud_dir = '{}/public_cloud'.format(cwd)
##process_files(cloud_dir)

## -- notify of next steps
print('-' * 60)
#print('{}NEXT STEPS:{}'.format(bold, reset))
#print('You may now add your analysis to the \n{}{}/docx/server_report.docx{} file\n'.format(bold, tgt_dir, reset))
print('Triming of output is set to:{} {} {}\nTrim size is set to: {}{}{}'.format(blue, TRIM_OUTPUT, reset, blue, TRIM_SIZE, reset))
print('-' * 60)
print('Default trim size is {}100{} lines. \nSet to 0 for no trimming of output.'.format(bold, reset))
print('-' * 60)


