#!/usr/bin/env python3
# coding:utf-8

import os
from cplCommand import LocalClient


msg1101 = 'unable to create: \'{0}\''
msg1102 = 'path exists, but is not a directory: \'{0}\''
msg1103 = 'unable to find path config: \'{0}\''
msg1104 = 'missing user, host or path in sshfs configuration'
msg1105 = 'mounting \'{0}\' to \'{1}\''
msg1106 = 'unable to mount \'{0}\' at \'{1}\''
msg1107 = 'unmounting: \'{0}\''
msg1108 = 'unable to umount \'{0}\''
msg1109 = 'unknown host key policy \'{0}\', defaulting to \'reject\' from (add|reject|ignore)'


class SSHFS():

	def __init__(self):

		self.client_l = LocalClient(self.logger)
		self.sshfs_mounts = []


	def __del__(self):

		# disconnect all sshfs connections
		self._umountAllSSHFS()


	def _preparePaths(self, paths, mnt_base):

		def checkPath(path):

			if not self.client_l.exists(path):
				if not self.client_l.mkdir(path):
					self.logger.error(msg1101.format(path))
					return False

			elif not self.client_l.isdir(path):
				self.logger.error(msg1102.format(path))
				return False

			return True

		path = {}
		for pk, cfg in paths.items():

			try:
				if isinstance(cfg[pk], list):
					p = os.path.sep.join(cfg[pk])
				else:
					p = cfg[pk]

			except KeyError:
				self.logger.error(msg1103.format(pk))
				return path

			if cfg['sshhost']:

				mntp = os.path.join(mnt_base, pk)
				if not checkPath(mntp): return False

				if not self._mountSSHFS(mntp, pwd=cfg['sshpwd'], \
				   user=cfg['sshuser'], host=cfg['sshhost'], \
				   path=p, port=cfg['sshport'], key=cfg['sshkey'], \
				   save=cfg['sshhkeysave'], pol=cfg['sshhkeypol']):

					return path

				path[pk] = mntp
				self.sshfs_mounts.append(mntp)

			else:
				if not checkPath(p): return path
				path[pk] = p

		return path


	def _mountSSHFS(self, mnt, fs=None, pwd=None,
		user=None, host=None, path=None, port=None,
		key=None, save=True, pol='reject'):

		opts = []
		# opts.append('-o LogLevel=QUIET')
		# or ERROR

		pol_list = {
			'add' : 'accept-new',
			'reject' : 'yes',
			'ignore' : 'no'
			}

		if port:
			opts.append('-o port={0}'.format(port))

		if key:
			opts.append('-i {0}'.format(key))

		if not save:
			opts.append('-o UserKnownHostsFile=/dev/null')

		try:
			opts.append('-o StrictHostKeyChecking={0}'.format(pol_list[pol]))

		except KeyError:
			self.logger.warn(msg1109.format(pol))
			opts.append('-o StrictHostKeyChecking=yes')

		if not fs:

			if None in (user, host, path):
				self.logger.error(msg1104)
				return False

			fs='{0}@{1}:{2}'.format(user, host, path)

		self.logger.debug(msg1105.format(fs, mnt))

		if pwd:
			pwd = "'{0}'".format(pwd)
			opts.append('-o password_stdin')
			cmd = ' '.join(['echo', pwd, '|', 'sshfs', *opts, fs, mnt])
		else:
			cmd = ' '.join(['sshfs', *opts, fs, mnt])

		value, std_out, std_err = self.client_l.runCmd(cmd, add_sudo=False)

		if value != 0:
			self.logger.error(msg1106.format(fs, mnt))
			return False
		return True


	def _umountSSHFS(self, mnt):

		self.logger.debug(msg1107.format(mnt))
		cmd = "fusermount -u '{0}'".format(mnt)
		value, std_out, std_err = self.client_l.runCmd(cmd, add_sudo=False)

		if value != 0:
			self.logger.error(msg1108.format(mnt))
			return False

		self.sshfs_mounts.remove(mnt)
		return True 


	def _umountAllSSHFS(self):

		self.logger.debug('closing all sshfs connections')
		rc = True
		try:
			for mnt in [ m for m in self.sshfs_mounts]:
				if not self._umountSSHFS(mnt): rc = False
			return rc
		except AttributeError:
			pass


