from parallels.plesk.source.plesk import messages
import logging
import posixpath

from parallels.plesk.utils.xml_rpc import plesk as plesk_api
from parallels.plesk.utils.xml_rpc.plesk import operator as plesk_ops
from parallels.plesk.utils.xml_rpc.plesk import get_max_supported_api_version
from parallels.core.utils import plesk_utils, plesk_api_utils
from parallels.core.utils.windows_utils import path_join as windows_path_join
from parallels.core.connections.plesk_server import PleskServer
from parallels.core.connections.source_server import SingleServerPanelSourceServer
from parallels.core.utils.common import cached

logger = logging.getLogger(__name__)


class PleskSourceServer(SingleServerPanelSourceServer, PleskServer):
	def get_unix_vhost_dirs(self, runner, domain_name):
		"""Return a list of domain hosting content directories."""
		return [posixpath.join(
			self.vhosts_dir, domain_name.encode('idna')
		)]

	def get_unix_domain_mail_dirs(self, runner, domain_name):
		"""Return a list of mail content directories."""
		return [posixpath.join(
			self.mail_dir, domain_name.encode('idna')
		)]

	@property
	@cached
	def panel_admin_password(self):
		config_password = self.node_settings.plesk_api.auth.password
		if config_password:
			# If specified in config explicitly - use it
			return config_password
		else:
			# If not specified in config - try to detect
			return super(PleskSourceServer, self).panel_admin_password

	@property
	@cached
	def plesk_version(self):
		"""Return a tuple with Plesk server version."""
		api = plesk_api.Client(
			self.node_settings.plesk_api.url,
			self.node_settings.plesk_api.auth.username,
			self.panel_admin_password,
			'1.5.2.1',
			pretty_print=True
		)
		version = plesk_api_utils.get_plesk_version(api)
		return tuple(map(int, (version.split("."))))

	@property
	@cached
	def plesk_major_version(self):
		return self.plesk_version[0]

	@property
	@cached
	def plesk_components(self):
		"""Return components installed on Plesk

		Returns dictionary with key - component name, value - information about
		the component.
		
		Example of result : {
			'mailman': ServerComponent(
				name='mailman', 
				version='2.1.9-6.el5_6.1'
			), 
			'psa-spamassassin': ServerComponent(
				name='psa-spamassassin', 
				version='10.13.4-cos5.build1013111102.18'
			)
		}
		"""
		logger.debug(u"Get installed Plesk components")
		result = self.plesk_api().send(
			plesk_ops.server.ServerOperator.Get([
				plesk_ops.server.ServerOperator.Dataset.COMPONENTS,
			])
		)
		server_info = result.data
		logger.debug(u"Server info: %s", server_info)
		return server_info.components

	@cached
	def plesk_api(self):
		"""Get Plesk API client object for this server"""

		# Minimal supported Plesk version is 9.0.2 which uses API version 1.6.0.2.
		# However, we can't just talk to each Plesk with this API version. Say, 10.2 introduced
		# support for IPv6 and if we ask for webspaces list with 1.6.3.0 protocol and some webspace
		# uses IPv6, error will be returned.
		# So it is needed to ask Plesk for it's version and use corresponding protocol version.
		# Returned client is cached to avoid doing this discovery every time.
		client = plesk_api.Client(
			self.node_settings.plesk_api.url,
			self.node_settings.plesk_api.auth.username, 
			self.panel_admin_password,
			plesk_api.api_versions['8.4'],
			pretty_print=True
		)

		# Get Plesk version.
		logger.debug(messages.LOG_GET_SERVER_INFO, self.node_id)
		result = client.send(
			plesk_ops.server.ServerOperator.Get([
				plesk_ops.server.ServerOperator.Dataset.STAT,
			])
		)
		server_info = result.data

		client.api_version = get_max_supported_api_version(
			server_info.statistics.versions.plesk_version
		)
		logger.debug(
			messages.LOG_PLESK_SERVER_INFO,
			server_info.statistics.versions.plesk_version,
			client.api_version
		)

		return client

	@cached
	def get_database_server_password(self, database_server):
		if self.plesk_version >= (11, 5):
			if self.is_windows():
				_, password = plesk_utils.get_windows_db_server_credentials(
					self,
					database_server.type(),
					database_server.host()
				)
				return password
			else:
				_, password = plesk_utils.get_unix_db_server_credentials(
					self,
					database_server.type(),
					database_server.host()
				)
				return password
		else:
			return None

	def get_path_to_mysqldump(self):
		if self.is_windows():
			return windows_path_join(self.plesk_dir, 'MySQL\\bin\\mysqldump')
		else:
			return 'mysqldump'

	def get_path_to_mysql(self):
		if self.is_windows():
			return windows_path_join(self.plesk_dir, 'MySQL\\bin\\mysql')
		else:
			return 'mysql'
