import functools

import matplotlib.widgets

import vaex.ui.plugin
from vaex.ui import undo
from vaex.ui.qt import *
from vaex.ui.icons import iconfile
import logging
import vaex.ui.undo as undo
import vaex.ui.qt as dialogs
import re
logger = logging.getLogger("vaex.plugin.tasks")

def loglog(plot_window):
	for layer in plot_window.layers:
		for i, expression in enumerate(layer.state.expressions):
			layer.set_expression("log10(%s)" % expression, i)
	plot_window.queue_history_change("task: log/log")

def removelog(plot_window):
	def remove_log(expression):
		return re.sub("^\s*(log|log2|log10)\((.*?)\)\s*$", "\\2", expression)
	for layer in plot_window.layers:
		for i, expression in enumerate(layer.state.expressions):
			layer.set_expression(remove_log(expression), i)
	plot_window.queue_history_change("task: remove log/log")

def loglog_and_sigma3(plot_window):
	removelog(plot_window)
	loglog(plot_window)
	plot_window.queue_history_change(None)
	sigma3(plot_window)
	plot_window.queue_history_change("task: log/log and 3 sigma region")

def sigma3(plot_window):
	if plot_window.layers:
		layer = plot_window.layers[0]


		if layer.dataset.is_local():
			executor = vaex.execution.Executor()
		else:
			executor = vaex.remote.ServerExecutor()
		subspace = layer.dataset.subspace(*layer.state.expressions, executor=executor, delay=True)
		means = subspace.mean()
		with dialogs.ProgressExecution(plot_window, "Calculating mean", executor=executor) as progress:
			progress.add_task(means)
			progress.execute()
		logger.debug("get means")
		means = means.get()
		logger.debug("got means")

		vars = subspace.var(means=means)
		with dialogs.ProgressExecution(plot_window, "Calculating variance", executor=executor) as progress:
			progress.add_task(vars)
			progress.execute()
		#limits  = limits.get()
		vars = vars.get()
		stds = vars**0.5
		sigmas = 3
		limits = list(zip(means-sigmas*stds, means+sigmas*stds))
		#plot_window.ranges_show = limits
		plot_window.set_ranges(range(len(limits)), limits, add_to_history=True, reason="3 sigma region")
		#plot_window.update_all_layers()
		#for layer in plot_window.layers:
		#	layer.flag_needs_update()
		logger.debug("means=%r", means)
		logger.debug("vars=%r", vars)
		logger.debug("limits=%r", limits)
		plot_window.queue_history_change("task: 3 sigma region")
		#plot_window.queue_update()

def subtract_mean(plot_window):
	if plot_window.layers:
		layer = plot_window.layers[0]

		executor = vaex.execution.Executor()
		subspace = layer.dataset.subspace(*layer.state.expressions, executor=executor, delay=True)
		means = subspace.mean()
		with dialogs.ProgressExecution(plot_window, "Calculating mean", executor=executor):
			executor.execute()
		means = means.get()
		new_expressions = ["(%s) - %s" % (expression, mean) for expression, mean in zip(layer.state.expressions, means)]
		for i in range(len(new_expressions)):
			vmin, vmax = layer.plot_window.state.ranges_viewport[i]
			vmin -= means[i]
			vmax -= means[i]
			layer.plot_window.set_range(vmin, vmax, i)
		for i in range(len(new_expressions)):
			layer.set_expression(new_expressions[i], i)
		plot_window.update_all_layers()
		plot_window.queue_history_change("task: remove mean")


@vaex.ui.plugin.pluginclass
class TasksPlugin(vaex.ui.plugin.PluginPlot):
	name = "tasks"
	def __init__(self, dialog):
		super(TasksPlugin, self).__init__(dialog)
		dialog.plug_toolbar(self.plug_toolbar, 1.6)


	def plug_toolbar(self):
		logger.info("adding %s plugin" % self.name)

		self.menu = QtGui.QMenu("&Tasks")
		self.dialog.menu_bar.addMenu(self.menu)

		self.tasks_button = QtGui.QToolButton()
		self.tasks_button.setIcon(QtGui.QIcon(iconfile('gear')))
		self.tasks_button.setText("Tasks")
		self.tasks_button.setPopupMode(QtGui.QToolButton.InstantPopup)
		self.tasks_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
		self.tasks_button.setMenu(self.menu)

		#self.action_tasks = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Tasks', self.dialog)
		self.dialog.toolbar.addWidget(self.tasks_button)


		self.action_tasks_loglog = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Log-Log', self.dialog)
		self.menu.addAction(self.action_tasks_loglog)
		self.action_tasks_loglog.triggered.connect(lambda *arg: loglog(self.dialog))

		self.action_tasks_loglog = QtGui.QAction(QtGui.QIcon(iconfile('gear')), '3 sigma region', self.dialog)
		self.menu.addAction(self.action_tasks_loglog)
		self.action_tasks_loglog.triggered.connect(lambda *arg: sigma3(self.dialog))

		self.action_tasks_loglog_3sigma = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Log-Log and 3 sigma region', self.dialog)
		self.menu.addAction(self.action_tasks_loglog_3sigma)
		self.action_tasks_loglog_3sigma.triggered.connect(lambda *arg: loglog_and_sigma3(self.dialog))

		self.action_tasks_removelog = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Remove log', self.dialog)
		self.menu.addAction(self.action_tasks_removelog)
		self.action_tasks_removelog.triggered.connect(lambda *arg: removelog(self.dialog))

		self.action_tasks_subtract_mean = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Subtract mean', self.dialog)
		self.menu.addAction(self.action_tasks_subtract_mean)
		self.action_tasks_subtract_mean.triggered.connect(lambda *arg: subtract_mean(self.dialog))


	def __(self):

		self.action_store  = QtGui.QAction(QtGui.QIcon(iconfile('gear')), 'Store', self.dialog)
		self.action_store.setShortcut("Ctrl+B")
		self.action_store_toolbar  = QtGui.QAction(QtGui.QIcon(iconfile('star')), 'Store', self.dialog)


		self.dialog.toolbar.addAction(self.action_store_toolbar)
		self.action_store.triggered.connect(self.on_store)
		self.action_store_toolbar.triggered.connect(self.on_store)
		self.changed_handle = storage_plots.changed.connect(self.load_options_menu)
		self.load_options_menu()

		self.dialog.menu_mode.addSeparator()
		self.action_zoom_rect = QtGui.QAction(QtGui.QIcon(iconfile('zoom')), '&Zoom to rect', self.dialog)
		self.action_zoom_rect.setShortcut("Ctrl+Alt+Z")
		self.dialog.menu_mode.addAction(self.action_zoom_rect)

		self.action_zoom_x = QtGui.QAction(QtGui.QIcon(iconfile('zoom_x')), '&Zoom x', self.dialog)
		self.action_zoom_y = QtGui.QAction(QtGui.QIcon(iconfile('zoom_y')), '&Zoom y', self.dialog)
		self.action_zoom = QtGui.QAction(QtGui.QIcon(iconfile('zoom')), '&Zoom(you should not read this)', self.dialog)

		self.action_zoom_x.setShortcut("Ctrl+Alt+X")
		self.action_zoom_y.setShortcut("Ctrl+Alt+Y")
		self.dialog.menu_mode.addAction(self.action_zoom_x)
		self.dialog.menu_mode.addAction(self.action_zoom_y)


		self.dialog.menu_mode.addSeparator()
		self.action_zoom_out = QtGui.QAction(QtGui.QIcon(iconfile('zoom_out')), '&Zoom out', self.dialog)
		self.action_zoom_in = QtGui.QAction(QtGui.QIcon(iconfile('zoom_in')), '&Zoom in', self.dialog)
		self.action_zoom_fit = QtGui.QAction(QtGui.QIcon(iconfile('arrow_out')), '&Reset view', self.dialog)
		#self.action_zoom_use = QtGui.QAction(QtGui.QIcon(iconfile('chart_bar')), '&Use zoom area', self.dialog)
		self.action_zoom_out.setShortcut("Ctrl+Alt+-")
		self.action_zoom_in.setShortcut("Ctrl+Alt++")
		self.action_zoom_fit.setShortcut("Ctrl+Alt+0")
		self.dialog.menu_mode.addAction(self.action_zoom_out)
		self.dialog.menu_mode.addAction(self.action_zoom_in)
		self.dialog.menu_mode.addAction(self.action_zoom_fit)



		self.dialog.action_group_main.addAction(self.action_zoom_rect)
		self.dialog.action_group_main.addAction(self.action_zoom_x)
		self.dialog.action_group_main.addAction(self.action_zoom_y)

		#self.dialog.toolbar.addAction(self.action_zoom_out)
		#self.dialog.add_shortcut(self.action_zoom_in,"+")
		#self.dialog.add_shortcut(self.action_zoom_out,"-")

		#self.dialog.add_shortcut(self.action_zoom_rect,"Z")
		#self.dialog.add_shortcut(self.action_zoom_x,"Alt+X")
		#self.dialog.add_shortcut(self.action_zoom_y,"Alt+Y")
		#self.dialog.add_shortcut(self.action_zoom_fit, "0")

		self.dialog.toolbar.addAction(self.action_zoom)
		self.zoom_menu = QtGui.QMenu()
		self.action_zoom.setMenu(self.zoom_menu)
		self.zoom_menu.addAction(self.action_zoom_rect)
		self.zoom_menu.addAction(self.action_zoom_x)
		self.zoom_menu.addAction(self.action_zoom_y)
		if self.dialog.dimensions == 1:
			self.lastActionZoom = self.action_zoom_x # this makes more sense for histograms as default
		else:
			self.lastActionZoom = self.action_zoom_rect

		self.dialog.toolbar.addSeparator()
		#self.dialog.toolbar.addAction(self.action_zoom_out)
		self.dialog.toolbar.addAction(self.action_zoom_fit)

		self.action_zoom.triggered.connect(self.onActionZoom)
		self.action_zoom_out.triggered.connect(self.onZoomOut)
		self.action_zoom_in.triggered.connect(self.onZoomIn)
		self.action_zoom_fit.triggered.connect(self.onZoomFit)
		#self.action_zoom_use.triggered.connect(self.onZoomUse)


		self.action_zoom.setCheckable(True)
		self.action_zoom_rect.setCheckable(True)
		self.action_zoom_x.setCheckable(True)
		self.action_zoom_y.setCheckable(True)

