#!/usr/bin/python3

#	cve-manager : CVE management tool
#	Copyright (C) 2017-2022 Alexey Appolonov
#
#	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, either version 3 of the License, or
#	(at your option) any later version.
#
#	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/>.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

from os                   import cpu_count
from cve_manager.parallel import Parallel
from cpe_map.defines      import M_COMPLETE, M_BIN_COMPLETE
from cpe_map.init         import Init
from cpe_map.common       import BlankArgParser, NewArgParser, CompatibleGroups
from cpe_map.control      import TerminateIfAbsent, TerminateOrSkip
from cpe_map.name_conv    import NAME_GROUP, NAME_FORMATTED, \
	NAME_FORMATTED_SPLITTED_WO_MARK

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Forming a set of arguments

argparser = BlankArgParser()
argparser.add_argument(
	'--bin',
	action='store_true',
	help='Perform matching of binary package names'
	)
argparser = NewArgParser(base=argparser, ptype='p')

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Find complete names matches, send results to a given pipe

def GetMatches(our_names, their_names, send_pipe, _):

	matches = {}

	for _our_name, our_name in our_names.items():
		their_name = their_names.get(_our_name)
		if their_name:
			if CompatibleGroups(our_name[NAME_GROUP], their_name[NAME_GROUP]):
				matches[_our_name] = _our_name
			continue
		elif our_name[NAME_FORMATTED_SPLITTED_WO_MARK]:
			continue
		matches_for_this_package = []
		for _their_name, their_name in their_names.items():
			if CompatibleGroups(our_name[NAME_GROUP], their_name[NAME_GROUP]) \
					and our_name[NAME_FORMATTED] == their_name[NAME_FORMATTED]:
				matches_for_this_package.append(_their_name)
		if matches_for_this_package:
			matches[_our_name] = '  '.join(matches_for_this_package)

	send_pipe.send(matches)

	return

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if __name__ == '__main__':

	# Parsing the args and getting the helper objects
	args = argparser.parse_args()
	type_of_matching = M_BIN_COMPLETE if args.bin else M_COMPLETE
	conf, speaker, mediator = Init(type_of_matching, args)

	# Getting package names
	mx_of_our_names = mediator.QueryPackages(args.packages, args.names,
		cpu_count())
	TerminateIfAbsent(mx_of_our_names)

	# For every type of selected data source (nvd, fstec)
	for data_source in args.data_sources:

		# Getting product names
		their_names = mediator.QueryProducts(data_source)
		if TerminateOrSkip(their_names):
			continue

		# Running multiple processes of matching
		speaker.Op(data_source, mx_of_our_names, their_names)
		matches, ok = Parallel(GetMatches, mx_of_our_names, their_names)
		if not ok:
			speaker.Status(err='Some process has terminated with an error')
			exit(1)
		speaker.Status(matches=matches)

		# Updating the table with the results
		if not mediator.SendMatches(data_source, matches):
			exit(1)

	exit(0)
