#! /usr/bin/python3 -s

'''
Project: RPQR
Author: Tomáš Korbař (tomas.korb@seznam.cz)
Copyright 2021 - 2022 Tomáš Korbař
'''

from networkx.readwrite import json_graph
import matplotlib.pyplot as plt
import configparser
import argparse
import networkx
import json
import sys

from rpqr.library.RPQRConfiguration import RPQRConfiguration
from rpqr.query.RPQRQuery import RPQRQuery

""" This is script which allows user to work with rpqr from commandline.
    It allows user to perform queries over rpm repository, cache its structure
    and choose whether the output should be visualized or printed on stdout.
"""

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="RPQR project CLI")
    parser.add_argument("--cfgpath", type=str,
                        help="Path to configuration file", default="/etc/rpqr.conf")
    parser.add_argument("query", type=str,
                        help="Query in RPQR language", default="")
    parser.add_argument("--filterattributes", type=str,
                        help="Specify list of attributes which interest you in the result",
                        default="")
    parser.add_argument("--filterrelations", type=str,
                        help="Specify list of relations which interest you in the result",
                        default="")
    parser.add_argument("--visualize", action="store_true",
                        default=False, help="Visualize result")
    parser.add_argument("--clearcache", action="store_true",
                        default=False, help="Clear cache")

    args = parser.parse_args()
    cfgParser = configparser.ConfigParser()
    cfgParser.read(args.cfgpath)

    pluginDirectories = json.loads(cfgParser["RPQR"]["pluginDirectories"])
    cacheFile = cfgParser["RPQR"]["cache"]
    namexrepository = []
    for sect in cfgParser.sections():
        if sect.startswith("RPQRRepo_"):
            namexrepository.append(
                (sect.replace("RPQRRepo_", ""), cfgParser[sect]["url"]))

    rpqrcfg = RPQRConfiguration(pluginDirectories, namexrepository, cfgParser)
    userQuery = RPQRQuery(rpqrcfg)

    # we will not be performing empty query
    if len(args.query) == 0:
        sys.exit(0)

    result = userQuery.performQuery(args.query)

    if result is None:
        sys.exit(1)

    # we will filter result attributes according to supplied parameters
    if len(args.filterattributes) != 0 or len(args.filterrelations) != 0:
        allAttrs = args.filterattributes.split(";") if len(
            args.filterattributes.split(";")[0]) != 0 else []
        allAttrs += args.filterrelations.split(";") if len(
            args.filterrelations.split(";")[0]) != 0 else []
        checkTuple = rpqrcfg.isAttributeSupported(allAttrs)
        if not checkTuple[0]:
            rpqrcfg.rootLogger.error(
                "attribute %s unsupported (maybe missing plugin?)", checkTuple[1])
            sys.exit(2)
        if len(args.filterattributes.split(";")[0]) != 0:
            for node in result.nodes:
                for key in list(result.nodes[node].keys()):
                    if not key in args.filterattributes.split(";"):
                        del result.nodes[node][key]
        if len(args.filterrelations.split(";")[0]) != 0:
            for node in result.nodes:
                for u, v, edge_key in result.out_edges([node], keys=True):
                    if not edge_key in args.filterrelations.split(";"):
                        result.remove_edge(u, v, key=edge_key)

    # if result should not be visualized then just print it in JSON format to stdout
    if not args.visualize:
        print(json.dumps(json_graph.node_link_data(
            result), indent=4, sort_keys=True))
        sys.exit(0)

    # labeling requires some more processing
    result: networkx.MultiDiGraph
    labelDict = {}
    for nodeId in result.nodes:
        label = ""
        for (attr, value) in result.nodes[nodeId].items():
            label += "%s=%s\n" % (attr, value)
        labelDict[nodeId] = label
    pos = networkx.spring_layout(result)
    networkx.draw_networkx(result, pos=pos, with_labels=True, labels=labelDict)
    edgeLabels = dict([((n1, n2), key) for n1, n2, key in result.edges])
    networkx.draw_networkx_edge_labels(result, pos=pos, edge_labels=edgeLabels)
    plt.show()
