import logging
import datetime
from xml.etree import ElementTree
from collections import OrderedDict

import os
from parallels.common.utils import migrator_utils
from parallels.common.utils.windows_utils import path_join as windows_path_join
from parallels.common.connections.source_server import SourceServer
from parallels.common.connections.target_servers import TargetServer
from parallels.plesks_migrator.server import PleskSourceServer
from parallels.target_panel_plesk.connections.target_connections import PleskTargetConnections
from parallels.target_panel_plesk.connections.target_server import PleskTargetServer
from parallels.common.utils.yaml_utils import read_yaml, write_yaml
from parallels.common.registry import Registry
from parallels.common.utils.config_utils import ConfigSection
from parallels.common.utils import windows_utils
logger = logging.getLogger(__name__)

# Analysis estimations
UNKNOWN = frozenset([0])
CRITICAL = frozenset([1])
OK = frozenset([2])
ANY = frozenset([0, 1, 2])


def get_unix_strategies():
	# TODO: extend this after collecting enough experimental data
	return OrderedDict([
		##############################################
		# order: (CPU, RAM, HDD, NET)
		##############################################
		# without ANY
		##############################################

		##############################################
		# with 1 ANY
		##############################################

		##############################################
		# with 2 ANY
		##############################################
		((UNKNOWN, CRITICAL, ANY, ANY), {'compression': True, 'msg': 'CPU = UNKNOWN, RAM = CRITICAL: use compression'}),
		((UNKNOWN, OK, ANY, ANY), {'compression': True, 'msg': 'CPU = UNKNOWN, RAM = OK: use compression'}),
		##############################################
		# with 3 ANY
		##############################################
		((CRITICAL, ANY, ANY, ANY), {'compression': False, 'msg': 'CPU = CRITICAL: skip compression'}),
		((ANY, ANY, CRITICAL, ANY), {'compression': False, 'msg': 'HDD = CRITICAL: skip compression'}),
		((ANY, ANY, ANY, CRITICAL), {'compression': True, 'msg': 'NET = CRITICAL: use compression'}),
		((ANY, ANY, ANY, OK), {'compression': True, 'msg': 'NET = OK: use compression'}),
		##############################################
		# with 4 ANY: Default strategy
		##############################################
		((ANY, ANY, ANY, ANY), {'compression': True, 'msg': 'Default strategy: use compression'}),
	])


def get_windows_strategies():
	return OrderedDict([
		##############################################
		# order: (CPU, RAM, HDD, NET)
		##############################################
		# without ANY
		##############################################

		##############################################
		# with 1 ANY
		##############################################

		##############################################
		# with 2 ANY
		##############################################

		##############################################
		# with 3 ANY
		##############################################
		((ANY, ANY, ANY, CRITICAL), {'compression': True, 'msg': 'NET = CRITICAL: use compression'}),
		##############################################
		# with 4 ANY: Default strategy
		##############################################
		((ANY, ANY, ANY, ANY), {'compression': False, 'msg': 'Default strategy: skip compression'}),
	])


class HostingAnalyser():
	"""Hosting Analyser"""

	def __init__(self, migrator_server):
		self.remote_xml_report_filename = 'summary.xml'
		self.remote_agent_report_folder_name = 'hosting_analysis_report'  # hosting analyser agent foldername with report
		self.remote_win_plesk_python_bin = "Additional\\Python\\python.exe"  # Use Plesk python package in Windows
		self.local_dst_plesk_server_report_filename = 'destination-plesk.xml'
		self.agent_filename = 'hosting_analyser_agent.py'
		self.network_analysis_report_filename = '_rsync_network_report'
		self.network_analysis_transfer_filename = '_rsync_net_test_file'  # Just "heavy" file for TCP/IP speeding up
		# local_mgr_server:./migration-session/hosting_analysis_reports/
		self.local_analyser_data_folder_path = os.path.join(migrator_server.session_dir(), 'hosting_analysis_reports')
		if not os.path.exists(self.local_analyser_data_folder_path):
			os.mkdir(self.local_analyser_data_folder_path)
		# local_mgr_server:/opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/parallels/hosting_analyser/hosting_analyser_agent.py
		self.local_agent_full_path = self._generate_hosting_analyser_internal_file_path(self.agent_filename)
		# local_mgr_server:/opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/parallels/hosting_analyser/extras/64_mb_test_file
		self.local_network_analysis_transfer_file_full_path = self._get_extras_file_path(self.network_analysis_transfer_filename)
		self.data = {}

	# local_mgr_server:./migration-session/hosting_analysis_report/filename
	def _get_analyser_session_file_path(self, filename):
		return os.path.join(self.local_analyser_data_folder_path, filename)

	# local_mgr_server:/opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/parallels/hosting_analyser/64_mb_test_file
	def _generate_hosting_analyser_internal_file_path(self, filename):
		return os.path.join(os.path.dirname(os.path.realpath(__file__)), filename)

	def _get_extras_file_path(self, filename):
		return self._generate_hosting_analyser_internal_file_path(os.path.join('extras', filename))

	def _is_server_source(self, server):
		return True if isinstance(server, SourceServer) else False

	def _is_server_target(self, server):
		return True if isinstance(server, TargetServer) else False

	def _is_server_supported(self, server):
		if self._is_server_source(server):
			return True if isinstance(server, PleskSourceServer) else False
		elif self._is_server_target(server):
			return True if isinstance(server, PleskTargetServer) else False
		else:
			return False

	@staticmethod
	def _is_server_target_connections_supported(target_connections):
		return True if isinstance(target_connections, PleskTargetConnections) else False

	# local_mgr_server:./migration-session/hosting_analysis_reports/_tmp_file_1
	def _create_temp_file(self, filename, content):
		file_full_path = self._get_analyser_session_file_path(filename)
		if os.path.exists(file_full_path) and os.path.isfile(file_full_path):
			os.remove(file_full_path)
		with open(file_full_path, "wb") as fp:
			fp.write(content)

	# local_mgr_server:./migration-session/hosting_analysis_reports/_tmp_file_1
	def _delete_analyser_local_session_file(self, filename):
		os.remove(self._get_analyser_session_file_path(filename))

	def _clear_existed_data(self):
		try:
			for root, dirs, files in os.walk(self.local_analyser_data_folder_path):
				for name in files:
					os.remove(os.path.join(root, name))
		except:
			logger.warning(u"Unable to clean up the folder '%s'" % root)

	def _get_python_bin(self, server):
		# Plesk in Linux
		if not server.is_windows():
			logger.debug(u"Detected python for Linux platform: 'python'")
			return 'python'
		# Plesk in Windows
		win_python = windows_path_join(server.plesk_dir, self.remote_win_plesk_python_bin)
		logger.debug(u"Detected python for Windows platform: '%s'" % win_python)
		return win_python

	@staticmethod
	def _prepare_remote_dst_server_for_network_analysis(destination_runner, remote_dst_net_test_file):
		logger.debug(u"Preparing a target server for network speed analysis")
		try:
			destination_runner.remove_file(remote_dst_net_test_file)
			logger.debug(u"The target server is now ready for network speed analysis")
		except:
			logger.debug(u"The target server is ready for analysis")

	def _analyse_network_speed_via_rsync(self, destination_server, source_servers, ssh_key_pool):
		# remote_dst_server:/tmp/64_mb_test_file
		remote_dst_net_test_file = destination_server.get_session_file_path(self.network_analysis_transfer_filename)
		# Linux
		if not destination_server.is_windows():
			for source_server in source_servers.itervalues():
				logger.info(u"Preparing target and source '%s' nodes for network speed estimation" % source_server.node_id)
				key_pathname = ssh_key_pool.get(source_server, destination_server).key_pathname
				with source_server.runner() as source_runner:
					source_runner.upload_file(
						# local_mgr_server:/opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/parallels/hosting_analyser/extras/64_mb_test_file
						self.local_network_analysis_transfer_file_full_path,
						# remote_src_server:/tmp/64_mb_test_file
						source_server.get_session_file_path(self.network_analysis_transfer_filename)
					)

				logger.info(u"Analysing network speed")
				rsync_cmd, args = migrator_utils.create_rsync_command(
					key_pathname=key_pathname,
					source_runner=source_runner,
					source_user=source_server.user(),
					source_ip=source_server.ip(),
					# remote_src_server:/tmp/64_mb_test_file
					source_filepath=source_server.get_session_file_path(self.network_analysis_transfer_filename),
					# remote_dst_server:/tmp/64_mb_test_file
					target_filepath=remote_dst_net_test_file,
					# rsync verbose option
					rsync_additional_args=['-v']
				)

				with destination_server.runner() as destination_runner:
					self._prepare_remote_dst_server_for_network_analysis(destination_runner, remote_dst_net_test_file)
					#  /usr/bin/rsync '-e' 'ssh -i /root/.ssh/id_dsa.VTSDOl4T -o StrictHostKeyChecking=no \
					# -o GSSAPIAuthentication=no' '--archive' 'root@10.52.55.131:/tmp/rsync_file' '/tmp/rsync_file'
					exit_code, stdout, stderr = destination_runner.run_unchecked(rsync_cmd, args)

				if exit_code == 0:
					# fixme: [workaround] parallels.common.run_command.SSHRunner.upload_file_content() - Not Implemented
					# local_mgr_server:./migration-session/hosting_analysis_reports/_rsync_network_report
					self._create_temp_file(self.network_analysis_report_filename, stdout)
					source_runner.upload_file(
						# local_mgr_server:./migration-session/hosting_analysis_reports/_rsync_network_report
						self._get_analyser_session_file_path(self.network_analysis_report_filename),
						# remote_src_server:/tmp/_rsync_network_report
						source_server.get_session_file_path(self.network_analysis_report_filename)
					)
					# local_mgr_server:./migration-session/hosting_analysis_reports/_rsync_network_report
					self._delete_analyser_local_session_file(self.network_analysis_report_filename)
					logger.info(u"Completed")
				else:
					logger.warning(u"Failed")
		# Windows
		else:
			for source_server in source_servers.itervalues():
				logger.info(u"Preparing source node '%s' and target node for network speed estimation" % source_server.node_id)
				with source_server.runner() as source_runner:
					source_runner.upload_file(
						# local_mgr_server:/opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/parallels/hosting_analyser/extras/64_mb_test_file
						self.local_network_analysis_transfer_file_full_path,
						# remote_src_server:/tmp/64_mb_test_file
						source_server.get_session_file_path(self.network_analysis_transfer_filename)
					)

				logger.info(u"Analysing network speed")
				with destination_server.runner() as destination_runner:
					self._prepare_remote_dst_server_for_network_analysis(destination_runner, remote_dst_net_test_file)
					global_context = Registry.get_instance().get_context()
					rsync = global_context.get_rsync(source_server, destination_server, source_server.ip)

					try:
						stdout = rsync.sync(
							source_path='migrator/%s' % self.network_analysis_transfer_filename,
							target_path=windows_utils.convert_path_to_cygwin(
								remote_dst_net_test_file
							),
							exclude=None,
							rsync_additional_args=['-v']
						)

						self._create_temp_file(self.network_analysis_report_filename, stdout)
						source_runner.upload_file(
							# local_mgr_server:./migration-session/hosting_analysis_reports/_rsync_network_report
							self._get_analyser_session_file_path(self.network_analysis_report_filename),
							# remote_src_server:/tmp/_rsync_network_report
							source_server.get_session_file_path(self.network_analysis_report_filename)
						)
						# local_mgr_server:./migration-session/hosting_analysis_reports/_rsync_network_report
						self._delete_analyser_local_session_file(self.network_analysis_report_filename)

						logger.info(u"Completed")
					except:
						logger.warning(u"Failed")
		# clean up
		logger.debug(u"Cleaning up after network speed estimation")
		destination_runner.remove_file(remote_dst_net_test_file)
		ssh_key_pool.remove_all()
		logger.debug(u"Completed")

	def _get_update_source_nodes_analysis(self, connections):
		for source_server_id in connections.get_information_servers().keys():
			server = connections.get_source_node(source_server_id)
			try:
				with server.runner() as runner:
					agent_dst_full_path = server.get_session_file_path(self.agent_filename)
					if not runner.file_exists(agent_dst_full_path):
						runner.upload_file(self.local_agent_full_path, agent_dst_full_path)
					args = ' "-f" "-d" "%s" "-n" "%s" "-c"' % (server.vhosts_dir, server.get_session_file_path(self.network_analysis_report_filename))
					src = os.path.join(server.vhosts_dir, self.remote_agent_report_folder_name, self.remote_xml_report_filename)
					dst = self._get_analyser_session_file_path('update_%s.xml' % server.node_id)
					logger.info(u"Analysing source node '%s'", server.node_id)
					cmd = '"%s" "%s" %s' % (self._get_python_bin(server), agent_dst_full_path, args)
					script_exec_result = runner.sh_unchecked(cmd)
					# pick up XML report
					if script_exec_result[0] == 0:
						runner.get_file(src, dst)
						logger.info(u"Completed")
					else:
						logger.warning(u"Failed")
			except Exception as e:
				logger.warning(u"Internal error: Unable to re-analyse the source nodes. Contact Odin support for assistance")
				logger.debug(u"Exception: ", exc_info=e)

	def _get_node_analysis(self, server):
		try:
			with server.runner() as runner:
				# remote_server:/tmp/hosting_analyser_agent.py
				agent_dst_full_path = server.get_session_file_path(self.agent_filename)
				runner.upload_file(self.local_agent_full_path, agent_dst_full_path)
				args = ' "-f" '
				# source
				if self._is_server_source(server):
					# remote_src_server:/var/www/vhosts
					args += ' "-d" "%s" "-n" "%s" ' % (server.vhosts_dir, server.get_session_file_path(self.network_analysis_report_filename))
					# remote_src_server:/var/www/vhosts/hosting_analysis_report/summary.xml
					src = os.path.join(server.vhosts_dir, self.remote_agent_report_folder_name, self.remote_xml_report_filename)
					# local_mgr_server:./migration-session/hosting_analysis_reports/pfu5.xml
					dst = self._get_analyser_session_file_path('%s.xml' % server.node_id)
					logger.info(u"Analysing source node '%s'", server.node_id)
				# destination
				else:
					args += ' "-c" '
					# remote_dst_server:/tmp/hosting_analysis_report/summary.xml
					src = os.path.join(server.session_dir(), self.remote_agent_report_folder_name, self.remote_xml_report_filename)
					# local_mgr_server:./migration-session/hosting_analysis_reports/destination-plesk.xml
					dst = self._get_analyser_session_file_path(self.local_dst_plesk_server_report_filename)
					logger.info(u"Analysing target node")
				# SRV: 'python' '/tmp/hosting_analyser_agent.py' '-d' '/var/www/vhosts' '-n' '/tmp/_rsync_network_report'
				# DST: 'python' '/tmp/hosting_analyser_agent.py' '-c'
				cmd = '"%s" "%s" %s' % (self._get_python_bin(server), agent_dst_full_path, args)
				script_exec_result = runner.sh_unchecked(cmd)
				# pick up XML report
				if script_exec_result[0] == 0:
					runner.get_file(src, dst)
					logger.info(u"Completed")
				else:
					logger.warning(u"Failed")
		except Exception as e:
			logger.warning(u"Internal error: Unable to analyse a service node. Contact Odin support for assistance")
			logger.debug(u"Exception: ", exc_info=e)

	# Check nodes (remote_sources, remote_destination) types
	def is_nodes_type_supported(self, connections):
		target_connections = connections.target
		source_servers = {}
		for source_server_id in connections.get_information_servers().keys():
			source_servers[source_server_id] = connections.get_source_node(source_server_id)
		try:
			if not self._is_server_target_connections_supported(target_connections):
				return False
			for source_server in source_servers.itervalues():
				if not self._is_server_supported(source_server):
					return False
			return True
		except Exception as e:
			logger.debug(u"Exception: ", exc_info=e)
			return False

	def is_compression_needed(self, subscription):
		global_context = Registry.get_instance().get_context()
		source_server = subscription.web_source_server
		if self.is_nodes_type_supported(global_context.conn):
			logger.debug(u"Determining a suitable content transfer strategy")
			if self.has_input_data(source_server.node_id):
				transfer_strategy = self.get_webspace_transfer_strategy(source_server.node_id, subscription.name_idn)
				if transfer_strategy is not None:
					logger.info(transfer_strategy.message)
					return transfer_strategy.need_compression
			else:
				logger.info(
					u"Information for hosting environment analysis is not available. For this reason, a search for "
					u"an effective content transfer strategy will not be performed.\nTo gather this information, "
					u"run 'panel-migrator analyse-hosting config.ini'.\n"
				)
		return False

	def analyse(self, connections, ssh_key_pool):
		# clear analyser data folder before new analysis
		self._clear_existed_data()
		# Nodes initialisation
		target_server = connections.target.plesk_server
		source_servers = {}
		for source_server_id in connections.get_information_servers().keys():
			source_servers[source_server_id] = connections.get_source_node(source_server_id)
		# Step 1: Network speed analysis between SOURCES and DESTINATION
		self._analyse_network_speed_via_rsync(target_server, source_servers, ssh_key_pool)
		# Step 2: Summary nodes analysing
		self._get_node_analysis(target_server)  # Handling DESTINATION server
		for source_server in source_servers.itervalues():  # Handling SOURCE servers
			self._get_node_analysis(source_server)

	def has_input_data(self, source_node_id):
		# local_mgr_server:./migration-session/hosting_analysis_reports/pfu1.xml
		input_xml_file = self._get_analyser_session_file_path("%s.xml" % source_node_id)
		return True if os.path.exists(input_xml_file) and os.path.isfile(input_xml_file) else False

	def get_webspace_transfer_strategy(self, source_node_id, webspace_name):
		global_context = Registry.get_instance().get_context()
		global_section = ConfigSection(global_context.config, 'GLOBAL')
		hosting_analysis_ttl = int(global_section.get('hosting-analysis-ttl', 900))
		last_hosting_analysis_time = self._get_last_hosting_analysis_time(global_context)
		if last_hosting_analysis_time is None or (datetime.datetime.now() - last_hosting_analysis_time).seconds > hosting_analysis_ttl:
			logger.debug(u"Updating the results of source nodes analysis")
			self._get_update_source_nodes_analysis(global_context.conn)
			self._set_last_hosting_analysis_time(global_context, datetime.datetime.now())

		transfer_strategy_calculator = TransferStrategyCalculator()
		# local_mgr_server:./migration-session/hosting_analysis_reports/pfu1.xml
		input_xml_file = self._get_analyser_session_file_path("%s.xml" % source_node_id)
		update_input_xml_file = self._get_analyser_session_file_path("update_%s.xml" % source_node_id)

		try:
			transfer_strategy_calculator.load_data(input_xml_file)
			if os.path.exists(update_input_xml_file) and os.path.isfile(update_input_xml_file):
				transfer_strategy_calculator.load_data(update_input_xml_file)
		except Exception as e:
			logger.debug(u"Exception: ", exc_info=e)
			return None

		return transfer_strategy_calculator.get_strategy(webspace_name)

	@staticmethod
	def _get_last_hosting_analysis_time(global_context):
		return read_yaml(
			global_context.session_files.get_path_to_last_hosting_analysis_time(),
			True
		)

	@staticmethod
	def _set_last_hosting_analysis_time(global_context, last_hosting_analysis_time):
		write_yaml(
			global_context.session_files.get_path_to_last_hosting_analysis_time(),
			last_hosting_analysis_time
		)


class TransferStrategy():
	def __init__(self, webspace_name):
		# a10-52-42-65.qa.plesk.ru
		self.webspace_name = webspace_name
		# [bool] True/False
		self.need_compression = None
		# [string] Message that shortly describes the strategy
		self.message = ''


class TransferStrategyCalculator():
	def __init__(self):
		# self.webspaces['xn--80aaakae3a6b3ar7g.xn--p1ai'] | self.webspaces['webspace_name']
		self.webspaces = {}
		self.environment = None

	def load_data(self, input_xml_file):
		if os.path.exists(input_xml_file) and os.path.isfile(input_xml_file):
			xml = ElementTree.parse(input_xml_file)
		else:
			raise Exception(u"Unable to load input XML data '%s'" % input_xml_file)

		root = xml.getroot()
		if self._is_xml_structure_correct(root):
			for section in root:
				if section.tag == 'files':
					for webspace in section:
						webspace_name = webspace.find('name').text
						self.webspaces[webspace_name] = Webspace(
							name=webspace_name,
							directory=webspace.find('dir').text,
							bin_c=webspace.find('bin-files-counter').text,
							txt_c=webspace.find('txt-files-counter').text,
							unk_c=webspace.find('unk-files-counter').text,
							all_c=webspace.find('all-files-counter').text,
							bin_s=webspace.find('bin-files-size').text,
							txt_s=webspace.find('txt-files-size').text,
							unk_s=webspace.find('unk-files-size').text,
							all_s=webspace.find('all-files-size').text,
							symlinks_c=webspace.find('symlinks').text,
							unproc_c=webspace.find('unprocessed').text
						)
				elif (section.tag == 'os'):
					self.environment = Environment(
						cpu_usage=section.find('cpu-usage').text,
						ram_usage=section.find('ram-usage').text,
						hdd_write=section.find('hdd-write').text,
						hdd_read=section.find('hdd-read').text,
						network=section.find('network').text
					)
		else:
			logger.warning(u"Input XML file '%s' is corrupted" % input_xml_file)

	def _is_xml_structure_correct(self, root):
		for section in root:
			if section.tag == 'files':
				webspaces = section
				for webspace in webspaces:
					if webspace.find('name') is None or \
						webspace.find('dir') is None or \
						webspace.find('bin-files-counter') is None or \
						webspace.find('txt-files-counter') is None or \
						webspace.find('unk-files-counter') is None or \
						webspace.find('all-files-counter') is None or \
						webspace.find('bin-files-size') is None or \
						webspace.find('txt-files-size') is None or \
						webspace.find('unk-files-size') is None or \
						webspace.find('all-files-size') is None or \
						webspace.find('symlinks') is None or \
						webspace.find('unprocessed') is None:
							return False
			elif section.tag == 'os':
				environment = section
				if environment.find('cpu-usage') is None or \
					environment.find('cpu-usage') is None or \
					environment.find('ram-usage') is None or \
					environment.find('hdd-write') is None or \
					environment.find('hdd-read') is None or \
					environment.find('network') is None:
						return False
		return True

	def get_strategy(self, webspace_name):
		strategy = TransferStrategy(webspace_name)
		if webspace_name not in self.webspaces.keys():
			logger.info(u"Unable to find information about the '%s' webspace. Skipping the strategy analysis" % webspace_name)
			return strategy
		# (CPU, RAM, HDD, NET). example: (CRITICAL, ANY, ANY, ANY)
		env_estimation = self.environment.get_estimation()
		most_effective_strategy = self._select_strategy(env_estimation)
		logger.debug(u"The following content transfer strategy was selected: '%s'" % str(most_effective_strategy))
		if most_effective_strategy['compression'] is True:
			strategy.need_compression = True
		elif most_effective_strategy['compression'] is False:
			strategy.need_compression = False
		else:
			logger.debug(u"Unable to determine the proper strategy")
		strategy.message = most_effective_strategy['msg']
		return strategy

	def _select_strategy(self, env_estimation):
		context = Registry.get_instance().get_context()
		strategies = get_windows_strategies() if context.conn.target.is_windows else get_unix_strategies()
		logger.debug(u"Selecting the proper strategy")
		for estimation_pattern, known_strategy in strategies.items():
			if self._is_suitable_estimation(env_estimation, estimation_pattern):
				logger.debug(u"env_estimation '%s' fits estimation_pattern '%s'" % (str(env_estimation), str(estimation_pattern)))
				return known_strategy
			else:
				logger.debug(u"env_estimation '%s' does not fit estimation_pattern '%s'" % (str(env_estimation), str(estimation_pattern)))

	# example:
	# env_estimation (source) = (CRITICAL, ANY, ANY, ANY)
	# pattern_estimation (destination) = (ANY, ANY, ANY, ANY)
	@staticmethod
	def _is_suitable_estimation(env_estimation, pattern_estimation):
		for index in range(0, len(env_estimation)):
			if not env_estimation[index].issubset(pattern_estimation[index]):
				return False
		return True

class Webspace():
	def __init__(self, name, directory, bin_c, txt_c, unk_c, all_c, bin_s, txt_s, unk_s, all_s, symlinks_c, unproc_c):
		# [string] 'a10-52-55-131.qa.plesk.ru'
		self.name = str(name)
		# [string] '/var/www/vhosts/a10-52-55-131.qa.plesk.ru'
		self.directory = str(directory)
		# [integer] Binary files counter
		self.bin_counter = int(bin_c)
		# [integer] Text files counter
		self.txt_counter = int(txt_c)
		# [integer] Unknown files counter
		self.unk_counter = int(unk_c)
		# [integer] All files counter
		self.all_counter = int(all_c)
		# [integer] Binary files size
		self.bin_size = int(bin_s)
		# [integer] Text files size
		self.txt_size = int(txt_s)
		# [integer] Unknown files size
		self.unk_size = int(unk_s)
		# [integer] All files size
		self.all_size = int(all_s)
		# [integer] Symbolic links counter
		self.symlinks_counter = int(symlinks_c)
		# [integer] Unprocessed files counter
		self.unprocessed_counter = int(unproc_c)

	def is_bin_by_size(self):
		return True if self.get_bin_files_percent_by_size() >= self.get_txt_files_percent_by_size() else False

	def is_txt_by_size(self):
		return True if self.get_txt_files_percent_by_size() >= self.get_bin_files_percent_by_size() else False

	# 0%, 5%, 20%, 33%, 50%, 51%, 75%, 80%, 100%
	def get_bin_files_percent_by_size(self):
		return self.bin_size * 100 / self.all_size if self.all_size != 0 else 100

	# 0%, 5%, 20%, 33%, 50%, 51%, 75%, 80%, 100%
	def get_txt_files_percent_by_size(self):
		return self.txt_size * 100 / self.all_size if self.all_size != 0 else 100

	# 0%, 5%, 20%, 33%, 50%, 51%, 75%, 80%, 100%
	def get_unk_files_percent_by_size(self):
		return self.unk_size * 100 / self.all_size if self.all_size != 0 else 100

class Environment():
	def __init__(self, cpu_usage, ram_usage, hdd_write, hdd_read, network):
		# [integer] Unknown result special value
		self.unknown = -1
		# [float] Percent of CPU usage, -1 if Unknown
		self.cpu_usage = float(cpu_usage)
		# [float] Percent of RAM usage, -1 if Unknown
		self.ram_usage = float(ram_usage)
		# [float] HDD write speed (bytes/sec), -1 if Unknown
		self.hdd_write = float(hdd_write)
		# [float] HDD read speed (bytes/sec), -1 if Unknown
		self.hdd_read = float(hdd_read)
		# [float] Network upload speed (bytes/sec), -1 if Unknown
		self.network = float(network)
		logger.debug(u"Environment analysis")
		logger.debug(u"CPU usage: '%d'%%" % self.cpu_usage)
		logger.debug(u"RAM usage: '%d'%%" % self.ram_usage)
		logger.debug(u"HDD write: '%d' b/s" % self.hdd_write)
		logger.debug(u"HDD read: '%d' b/s" % self.hdd_read)
		logger.debug(u"Network upload speed: '%d' b/s" % self.network)

	def is_cpu_analysed(self):
		return True if self.cpu_usage != self.unknown else False

	def is_ram_analysed(self):
		return True if self.ram_usage != self.unknown else False

	def is_hdd_analysed(self):
		return True if self.hdd_write != self.unknown and self.hdd_read != self.unknown else False

	def is_network_analysed(self):
		return True if self.network != self.unknown else False

	# TODO implement more complicated logic here
	def get_estimation(self):
		# Order: (CPU, RAM, HDD, NET)
		cpu = UNKNOWN
		if self.is_cpu_analysed():
			if self.cpu_usage > 80:
				cpu = CRITICAL
			else:
				cpu = OK

		ram = UNKNOWN
		if self.is_ram_analysed():
			if self.ram_usage > 90:
				ram = CRITICAL
			else:
				ram = OK

		hdd = UNKNOWN
		if self.is_hdd_analysed():
			# < 2 MB/s
			if self.hdd_write < 2097152 or self.hdd_read < 2097152:
				hdd = CRITICAL
			else:
				hdd = OK

		net = UNKNOWN
		if self.is_network_analysed():
			# < 100 KBps ( set 200-300 KBps here? )
			if self.network < 102400:
				net = CRITICAL
			else:
				net = OK

		env_estimation = (cpu, ram, hdd, net)
		logger.debug(u"Environment estimation (CPU, RAM, HDD, NET): '%s'" % str(env_estimation))
		return env_estimation
