import sys
import unittest
import numpy
import platform

from PyQt5 import QtGui, QtWidgets, QtPrintSupport
from PyQt5 import QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from unittest.mock import MagicMock
from mpl_toolkits.mplot3d import Axes3D

####### TEMP
import path_prepare
#######
from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.PlotterData import Data2D
from UnitTesting.TestUtils import WarningTestNotImplemented

# Tested module
import sas.qtgui.Plotting.Plotter2D as Plotter2D

if not QtWidgets.QApplication.instance():
    app = QtWidgets.QApplication(sys.argv)

class Plotter2DTest(unittest.TestCase):
    '''Test the Plotter 2D class'''
    def setUp(self):
        '''create'''
        class dummy_manager(object):
            def communicator(self):
                return Communicate()
            def perspective(self):
                return MyPerspective()
            def workspace(self):
                return None

        self.plotter = Plotter2D.Plotter2D(parent=dummy_manager(), quickplot=True)

        self.data = Data2D(image=[0.1]*4,
                           qx_data=[1.0, 2.0, 3.0, 4.0],
                           qy_data=[10.0, 11.0, 12.0, 13.0],
                           dqx_data=[0.1, 0.2, 0.3, 0.4],
                           dqy_data=[0.1, 0.2, 0.3, 0.4],
                           q_data=[1,2,3,4],
                           xmin=-1.0, xmax=5.0,
                           ymin=-1.0, ymax=15.0,
                           zmin=-1.0, zmax=20.0)

        self.data.title="Test data"
        self.data.id = 1
        self.data.ndim = 1
        self.isWindows = platform.system=="Windows"

    def tearDown(self):
        '''destroy'''
        self.plotter.figure.clf()
        self.plotter = None

    def testDataProperty(self):
        """ Adding data """
        self.plotter.data = self.data

        self.assertEqual(self.plotter.data0, self.data)
        self.assertEqual(self.plotter._title, self.data.title)
        self.assertEqual(self.plotter.xLabel, "$\\rm{Q_{x}}(A^{-1})$")
        self.assertEqual(self.plotter.yLabel, "$\\rm{Q_{y}}(A^{-1})$")

    def testPlot(self):
        """ Look at the plotting """
        self.plotter.data = self.data
        self.plotter.show()
        FigureCanvas.draw_idle = MagicMock()

        self.plotter.plot()

        self.assertTrue(FigureCanvas.draw_idle.called)
        self.plotter.figure.clf()

    def testCalculateDepth(self):
        ''' Test the depth calculator '''
        self.plotter.data = self.data

        # Default, log scale
        depth = self.plotter.calculateDepth()
        self.assertEqual(depth, (0.1, 1.e20))

        # Change the scale to linear
        self.plotter.scale = 'linear'
        depth = self.plotter.calculateDepth()
        self.assertEqual(depth[0], -32.)
        self.assertAlmostEqual(depth[1], 1.30103, 5)

    def testOnColorMap(self):
        ''' Respond to the color map event '''
        self.plotter.data = self.data
        self.plotter.plot()
        self.plotter.show()

        QtWidgets.QDialog.exec_ = MagicMock(return_value=QtWidgets.QDialog.Accepted)

        # Just this one plot
        self.plotter.onColorMap()

        # Check that exec_ got called
        self.assertTrue(QtWidgets.QDialog.exec_.called)

        self.assertEqual(self.plotter.cmap, "jet")
        self.assertAlmostEqual(self.plotter.vmin, 0.1, 6)
        self.assertAlmostEqual(self.plotter.vmax, 1e+20, 6)
        self.plotter.figure.clf()

    def testOnToggleScale(self):
        """ Respond to the event by replotting """
        self.plotter.data = self.data
        self.plotter.show()
        FigureCanvas.draw_idle = MagicMock()

        self.plotter.onToggleScale(None)

        self.assertTrue(FigureCanvas.draw_idle.called)
        self.plotter.figure.clf()

    def testOnBoxSum(self):
        """ Test the box sum display and functionality """

        # hacky way to make things work in manipulations._sum
        self.data.detector = [1]
        self.data.err_data = numpy.array([0.0, 0.0, 0.1, 0.0])
        self.plotter.data = self.data
        self.plotter.show()

        # Mock the main window
        self.plotter.manager.parent = MagicMock()

        # Call the main tested method
        self.plotter.onBoxSum()

        # Test various properties
        self.assertIsInstance(self.plotter.slicer.model(), QtGui.QStandardItemModel)
        self.assertTrue(self.plotter.boxwidget.isVisible())
        self.assertIsInstance(self.plotter.boxwidget.model, QtGui.QStandardItemModel)
        self.plotter.figure.clf()

    def testContextMenuQuickPlot(self):
        """ Test the right click menu """
        self.plotter.data = self.data
        self.plotter.createContextMenuQuick()
        actions = self.plotter.contextMenu.actions()
        self.assertEqual(len(actions), 7)

        # Trigger Print Image and make sure the method is called
        self.assertEqual(actions[1].text(), "Print Image")
        QtPrintSupport.QPrintDialog.exec_ = MagicMock(return_value=QtWidgets.QDialog.Rejected)
        actions[1].trigger()
        self.assertTrue(QtPrintSupport.QPrintDialog.exec_.called)

        # Trigger Copy to Clipboard and make sure the method is called
        self.assertEqual(actions[2].text(), "Copy to Clipboard")

        # Trigger Toggle Grid and make sure the method is called
        self.assertEqual(actions[4].text(), "Toggle Grid On/Off")
        self.plotter.ax.grid = MagicMock()
        actions[4].trigger()
        self.assertTrue(self.plotter.ax.grid.called)

        # Trigger Change Scale and make sure the method is called
        self.assertEqual(actions[6].text(), "Toggle Linear/Log Scale")
        FigureCanvas.draw_idle = MagicMock()
        actions[6].trigger()
        self.assertTrue(FigureCanvas.draw_idle.called)

        # Spy on cliboard's dataChanged() signal
        if not self.isWindows:
            return
        self.clipboard_called = False
        def done():
            self.clipboard_called = True
        QtCore.QObject.connect(QtWidgets.qApp.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
        actions[2].trigger()
        QtWidgets.qApp.processEvents()
        # Make sure clipboard got updated.
        self.assertTrue(self.clipboard_called)
        self.plotter.figure.clf()

    def testShowNoPlot(self):
        """ Test the plot rendering and generation """

        FigureCanvas.draw_idle = MagicMock()
        FigureCanvas.draw = MagicMock()

        # Test early return on no data
        self.plotter.showPlot(data=None,
                              qx_data=self.data.qx_data,
                              qy_data=self.data.qy_data,
                              xmin=self.data.xmin,
                              xmax=self.data.xmax,
                              ymin=self.data.ymin, ymax=self.data.ymax,
                              cmap=None, zmin=None,
                              zmax=None)

        self.assertFalse(FigureCanvas.draw_idle.called)
        self.assertFalse(FigureCanvas.draw.called)
        self.plotter.figure.clf()

    def testShow3DPlot(self):
        """ Test the 3Dplot rendering and generation """
        # Test 3D printout
        FigureCanvas.draw = MagicMock()
        Axes3D.plot_surface = MagicMock()
        self.plotter.figure.colorbar = MagicMock()

        self.plotter.dimension = 3
        self.plotter.data = self.data
        self.plotter.showPlot(data=self.plotter.data0.data,
                              qx_data=self.data.qx_data,
                              qy_data=self.data.qy_data,
                              xmin=self.data.xmin,
                              xmax=self.data.xmax,
                              ymin=self.data.ymin, ymax=self.data.ymax,
                              cmap=None, zmin=None,
                              zmax=None)
        self.assertTrue(Axes3D.plot_surface.called)
        self.assertTrue(FigureCanvas.draw.called)
        self.plotter.figure.clf()

    def testShow2DPlot(self):
        """ Test the 2Dplot rendering and generation """
        # Test 2D printout
        FigureCanvas.draw_idle = MagicMock()
        self.plotter.figure.colorbar = MagicMock()

        self.plotter.dimension = 2
        self.plotter.data = self.data
        self.plotter.showPlot(data=self.data.data,
                              qx_data=self.data.qx_data,
                              qy_data=self.data.qy_data,
                              xmin=self.data.xmin,
                              xmax=self.data.xmax,
                              ymin=self.data.ymin, ymax=self.data.ymax,
                              cmap=None, zmin=None,
                              zmax=None)
        self.assertTrue(FigureCanvas.draw_idle.called)
        self.plotter.figure.clf()


if __name__ == "__main__":
    unittest.main()
