#!/usr/bin/python3
SVER = '2.0.15'
##############################################################################
# sagvc - Regular Patterns Change Log Generator
# Copyright (C) 2023 SUSE LLC
#
# Description:  Creates a list of new regular pattern entries for the change
#               log
# Modified:     2023 Aug 25
#
##############################################################################
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; version 2 of the License.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, see <http://www.gnu.org/licenses/>.
#
#  Authors/Contributors:
#     Jason Record <jason.record@suse.com>
#
##############################################################################

import sys
import os
import re
import getopt
import datetime
import signal
import configparser
import patdevel as pd

##############################################################################
# Global Options
##############################################################################

title_string = "Regular Pattern Change Log Generator"

##############################################################################
# Functions
##############################################################################

def usage():
	"Displays usage information"
	display = "  {:33s} {}"
	print("Usage: patgvc [options] [Date]")
	print()
	print("Options:")
	print(display.format("-h, --help", "Display this help"))
	print(display.format('-d <dir>, --dir <dir>', "Set the path to a GitHub repository directory"))
	print(display.format('-a, --all', "Generate change logs from all GitHub repository directories"))
	print(display.format('-l <level>, --log_level <level>', "Set log level, default: Minimal"))
	print(display.format('', "0 Quiet, 1 Minimal, 2 Normal, 3 Verbose, 4 Debug"))
	print()

def signal_handler(sig, frame):
	print("\n\nAborting...\n")
	sys.exit(1)

def get_pattern_info(pattern_file):
	descr = re.compile("Description:", re.IGNORECASE)
	links = re.compile("OTHER_LINKS =", re.IGNORECASE)
	description = ''
	tid_str = ''
	bug_str = ''
	tag_str = ''
	fd = open(pattern_file, "r")
	lines = fd.readlines()
	fd.close()
	for line in lines:
		if descr.search(line):
			description = line.split(':')[-1].strip().strip()
		elif links.search(line):
			link_list = line.strip().strip('\"\'').split('|')
			for link in link_list:
				if link.startswith('META_LINK_TID='):
					tid_str = "TID" + str(link.split('=')[-1])
				elif link.startswith('META_LINK_BUG='):
					tid_str = "bsc#" + str(link.split('=')[-1])
	
	if( len(bug_str) > 0 ):
		tag_str = bug_str
	elif( len(tid_str) > 0 ):
		tag_str = tid_str

	return [description, tid_str, bug_str, tag_str]

def generate_reg_change_log(_git_repo, _given_date):
	pattern_list = _git_repo.get_local_regular_patterns()
	add_dict = {}
	mod_dict = {}
	del_dict = {}
	date_updated = pd.convert_log_date(_given_date)
	count = 0
	if( len(pattern_list) > 0 ):
		data = _git_repo.get_info()
		count_total = 0
		print()
		for this_pattern, this_action in pattern_list.items():
			if this_action == "del":
				del_dict[this_pattern] = {'title': '', 'tid': '', 'bug': '', 'tag': ''}
			elif this_action == "add":
				(title, tid, bug, tag) = get_pattern_info(this_pattern)
				add_dict[this_pattern] = {'title': title, 'tid': tid, 'bug': bug, 'tag': tag}
			elif this_action == "mod":
				(title, tid, bug, tag) = get_pattern_info(this_pattern)
				mod_dict[this_pattern] = {'title': title, 'tid': tid, 'bug': bug, 'tag': tag}
		print("- Changes in version " + str(data['spec_ver_bumped']))
		count = len(add_dict)
		count_total += count
		if( count > 0 ):
			print("  - New patterns (" + str(count) + "):")
			key_index = list(add_dict.keys())
			key_index.sort()
			for key in key_index:
				if( len(add_dict[key]['title']) > 0 ):
					print("    + {}: {} ({})".format(key, add_dict[key]['title'], add_dict[key]['tag']))
				else:
					print("    + {}".format(key))
		count = len(mod_dict)
		count_total += count
		if( count > 0 ):
			print("  - Updated patterns (" + str(count) + "):")
			key_index = list(mod_dict.keys())
			key_index.sort()
			for key in key_index:
				if( len(mod_dict[key]['title']) > 0 ):
					print("    + {}: {} ({})".format(key, mod_dict[key]['title'], mod_dict[key]['tag']))
				else:
					print("    + {}".format(key))
		count = len(del_dict)
		count_total += count
		if( count > 0 ):
			print("  - Deleted patterns (" + str(count) + "):")
			key_index = list(del_dict.keys())
			key_index.sort()
			for key in key_index:
				print("    + {}".format(key))

		print("\nAffected Patterns {}".format(count_total))
	else:
		print("Warning: No regular patterns found for the change log")
	print()

def generate_all_reg_change_logs(msg, config, given_date):
	repo_dir = pd.config_entry(config.get("Common", "sca_repo_dir"), '/')
	repo_list = pd.config_entry(config.get("GitHub", "patdev_repos")).split(',')
	pd.check_git_repos(config, msg)
	current_log_level = msg.get_level()
	for repo in repo_list:
		if current_log_level > msg.LOG_MIN:
			pd.separator_line('-')
		path = repo_dir + repo
		git_repo = pd.GitHubRepository(msg, path)
		patterns = len(git_repo.get_local_regular_patterns())
		if( msg.get_level() >= msg.LOG_NORMAL ):
			msg.min("Repository location", path)
			generate_reg_change_log(git_repo, given_date)
		else:
			if patterns > 0:
				pd.separator_line('-')
				msg.min("Repository location", path)
				generate_reg_change_log(git_repo, given_date)


##############################################################################
# Main
##############################################################################

def main(argv):
	"main entry point"
	global SVER
	parse_patterns = []
	given_dir = ''
	force_all = False
	
	if( os.path.exists(pd.config_file) ):
		config.read(pd.config_file)
		config_log_level = pd.config_entry(config.get("Common", "log_level"))
		config_logging = msg.validate_level(config_log_level)
		if( config_logging >= msg.LOG_QUIET ):
			msg.set_level(config_logging)
		else:
			msg.min("Warning: Invalid log level in config file, using instance default")
	else:
		pd.title(title_string, SVER)
		print("Error: Config file not found - {}".format(pd.config_file))
		print()
		sys.exit(1)

	try:
		(optlist, args) = getopt.gnu_getopt(argv[1:], "hd:al:", ["help", "dir=", "all", "log_level="])
	except getopt.GetoptError as exc:
		pd.title(title_string, SVER)
		print("Error:", exc, file=sys.stderr)
		sys.exit(2)
	for opt, arg in optlist:
		if opt in {"-h", "--help"}:
			pd.title(title_string, SVER)
			usage()
			sys.exit(0)
		elif opt in {"-d", "--dir"}:
			given_dir = arg
			if not os.path.isdir(given_dir):
				pd.title(title_string, SVER)
				print("Error: Directory not found - {}".format(given_dir))
				usage()
				sys.exit(1)
		elif opt in {"-a", "--all"}:
			force_all = True
		elif opt in {"-l", "--log_level"}:
			user_logging = msg.validate_level(arg)
			if( user_logging >= msg.LOG_QUIET ):
				msg.set_level(user_logging)
			else:
				print("Warning: Invalid log level, using instance default")

	if( msg.get_level() > msg.LOG_QUIET ):
		pd.title(title_string, SVER)

	msg.normal("Log Level", msg.get_level_str())

	if len(args) > 0: # A path to a proposed GitHub repository was given on the command line
		given_date = '-'.join(args)
	else:
		given_date = ''

	if force_all:
		msg.debug("  <conf> Force using GitHub directories", "Config File")
		generate_all_reg_change_logs(msg, config, given_date)
	else:
		if( len(given_dir) > 0 ):
			path = os.path.abspath(given_dir)
			msg.debug("  <arg> GitHub directory given", path)
			if pd.github_path_valid(msg, path):
				pd.separator_line('-')
				msg.min("Repository location", path)
				git_repo = pd.GitHubRepository(msg, path)
				generate_reg_change_log(git_repo, given_date)
			else:
				msg.min("Invalid GitHub repository", path)
				sys.exit(4)

		else: # No repository path given on the command line
			path = os.getcwd()
			if pd.github_path_valid(msg, path):
				msg.debug("  <cwd> GitHub directory given", path)
				pd.separator_line('-')
				msg.min("Repository location", path)
				git_repo = pd.GitHubRepository(msg, path)
				generate_reg_change_log(git_repo, given_date)
			else:
				msg.debug("  <conf> GitHub directories", "Config File")
				generate_all_reg_change_logs(msg, config, given_date)

# Entry point
if __name__ == "__main__":
	signal.signal(signal.SIGINT, signal_handler)
	config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
	msg = pd.DisplayMessages()
	main(sys.argv)

