from __future__ import division, print_function, absolute_import
import unittest
from .. import common
import tempfile

import os
i
mport platform

import numpy as num

from pyrocko import util, model
from pyrocko.pile import make_pile
from pyrocko import config, trace

if common.have_gui():  # noqa
    from pyrocko.gui.qt_compat import qc, qw, use_pyqt5
    if use_pyqt5:
        from PyQt5.QtTest import QTest
        Qt = qc.Qt
    else:
        from PyQt4.QtTest import QTest
        Qt = qc.Qt

    from pyrocko.gui.snuffler_app import SnufflerWindow
    from pyrocko.gui import pile_viewer as pyrocko_pile_viewer
    from pyrocko.gui import util as gui_util
    from pyrocko.gui import snuffling

    class DummySnuffling(snuffling.Snuffling):

        def setup(self):
            self.set_name('DummySnuffling')

        def call(self):
            figframe = self.figure_frame()
            ax = figframe.gca()
            ax.plot([0, 1], [0, 1])
            figframe.draw()

            self.enable_pile_changed_notifications()

            self.pixmap_frame()
            try:
                self.web_frame()
            except ImportError as e:
                raise unittest.SkipTest(str(e))

            self.get_pile()

    no_gui = False
else:
    no_gui = True


@common.require_gui
class GUITest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        '''
        Create a reusable snuffler instance for all tests cases.
        '''
        super(GUITest, cls).setUpClass()
        if no_gui:  # nosetests runs this even when class is has @skip
            return

        from pyrocko.gui import snuffler as sm

        cls.snuffler = sm.get_snuffler_instance()

        fpath = common.test_data_file('test2.mseed')
        p = make_pile(fpath, show_progress=False)
        cls.win = SnufflerWindow(pile=p, instant_close=True)
        cls.pile_viewer = cls.win.pile_viewer
        cls.viewer = cls.win.pile_viewer.viewer
        pv = cls.pile_viewer
        cls.main_control_defaults = dict(
            highpass_control=pv.highpass_control.get_value(),
            lowpass_control=pv.lowpass_control.get_value(),
            gain_control=pv.gain_control.get_value(),
            rot_control=pv.rot_control.get_value())

    @classmethod
    def tearDownClass(cls):
        '''
        Quit snuffler.
        '''
        if no_gui:  # nosetests runs this even when class is has @skip
            return

        QTest.keyPress(cls.pile_viewer, 'q')

    def setUp(self):
        '''
        reset GUI
        '''
        for k, v in self.main_control_defaults.items():
            getattr(self.pile_viewer, k).set_value(v)

        self.initial_trange = self.viewer.get_time_range()
        self.viewer.set_tracks_range(
            [0, self.viewer.ntracks_shown_max])
        self.tempfiles = []

    def tearDown(self):
        self.clear_all_markers()
        for tempfn in self.tempfiles:
            os.remove(tempfn)

        self.viewer.set_time_range(*self.initial_trange)

    def get_tempfile(self):
        fh, tempfn = tempfile.mkstemp()
        os.close(fh)
        self.tempfiles.append(tempfn)
        return tempfn

    def write_to_input_line(self, text):
        '''emulate writing to inputline and press return'''
        pv = self.pile_viewer
        il = pv.inputline
        QTest.keyPress(pv, ':')
        QTest.keyClicks(il, text)
        QTest.keyPress(il, Qt.Key_Return)

    def clear_all_markers(self):
        pv = self.pile_viewer
        QTest.keyPress(pv, 'A', Qt.ShiftModifier, 10)
        QTest.keyPress(pv, Qt.Key_Backspace)
        self.assertEqual(len(pv.viewer.get_markers()), 0)

    def trigger_menu_item(self, qmenu, action_text, dialog=False):
        ''' trigger a QMenu QAction with action_text. '''

        for iaction, action in enumerate(qmenu.actions()):
            if action.text() == action_text:

                if dialog:
                    def closeDialog():
                        dlg = self.snuffler.activeModalWidget()
                        QTest.keyClick(dlg, Qt.Key_Escape)

                    qc.QTimer.singleShot(150, closeDialog)

                action.trigger()
                break

    def get_slider_position(self, slider):
        style = slider.style()
        opt = qw.QStyleOptionSlider()
        return style.subControlRect(
            qw.QStyle.CC_Slider, opt, qw.QStyle.SC_SliderHandle)

    def drag_slider(self, slider):
        ''' Click *slider*, drag from one side to the other, release mouse
        button repeat to restore inital state'''
        position = self.get_slider_position(slider)
        QTest.mouseMove(slider, pos=position.topLeft())
        QTest.mousePress(slider, Qt.LeftButton)
        QTest.mouseMove(slider, pos=position.bottomRight())
        QTest.mouseRelease(slider, Qt.LeftButton)
        QTest.mousePress(slider, Qt.LeftButton)
        QTest.mouseMove(slider, pos=position.topLeft())
        QTest.mouseRelease(slider, Qt.LeftButton)

    def add_one_pick(self):
        '''Add a single pick to pile_viewer'''
        pv = self.pile_viewer
        QTest.mouseDClick(pv.viewer, Qt.LeftButton)
        position_tl = pv.pos()
        geom = pv.frameGeometry()
        QTest.mouseMove(pv.viewer, pos=position_tl)
        QTest.mouseMove(pv.viewer, pos=(qc.QPoint(
            position_tl.x()+geom.x() // 2, position_tl.y()+geom.y() // 2)))

        # This should be done also by mouseDClick().
        QTest.mouseRelease(pv.viewer, Qt.LeftButton)
        QTest.mouseClick(pv.viewer, Qt.LeftButton)

    def test_main_control_sliders(self):
        self.drag_slider(self.pile_viewer.highpass_control.slider)
        self.drag_slider(self.pile_viewer.lowpass_control.slider)
        self.drag_slider(self.pile_viewer.gain_control.slider)
        self.drag_slider(self.pile_viewer.rot_control.slider)

    def test_inputline(self):
        initrange = self.viewer.shown_tracks_range

        self.write_to_input_line('hide W.X.Y.Z')
        self.write_to_input_line('unhide W.X.Y.Z')
        self.pile_viewer.update()

        self.write_to_input_line('hide *')
        self.pile_viewer.update()

        assert(self.viewer.shown_tracks_range == (0, 1))
        self.write_to_input_line('unhide')

        assert(self.viewer.shown_tracks_range == initrange)

        self.write_to_input_line('markers')
        self.write_to_input_line('markers 4')
        self.write_to_input_line('markers all')

        # should error
        self.write_to_input_line('scaling 1000.')
        self.write_to_input_line('scaling -1000. 1000.')

        gotos = ['2015-01-01 00:00:00',
                 '2015-01-01 00:00',
                 '2015-01-01 00',
                 '2015-01-01',
                 '2015-01',
                 '2015']

        for gt in gotos:
            self.write_to_input_line('goto %s' % gt)

        # test some false input
        self.write_to_input_line('asdf')
        QTest.keyPress(self.pile_viewer.inputline, Qt.Key_Escape)

    def test_drawing_optimization(self):
        n = 505
        lats = num.random.uniform(-90., 90., n)
        lons = num.random.uniform(-180., 180., n)
        events = []
        for i, (lat, lon) in enumerate(zip(lats, lons)):
            events.append(
                model.Event(time=i, lat=lat, lon=lon, name='XXXX%s' % i))

        self.viewer.add_event(events[-1])
        assert len(self.viewer.markers) == 1
        self.viewer.add_events(events)
        assert len(self.viewer.markers) == n + 1

        self.viewer.set_time_range(-500., 5000)
        self.viewer.set_time_range(0., None)
        self.viewer.set_time_range(None, 0.)

    def test_follow(self):
        self.viewer.follow(10.)
        self.viewer.unfollow()

    def test_save_image(self):
        tempfn_svg = self.get_tempfile() + '.svg'
        self.viewer.savesvg(fn=tempfn_svg)

        tempfn_png = self.get_tempfile() + '.png'
        self.viewer.savesvg(fn=tempfn_png)

    def test_read_events(self):
        event = model.Event()
        tempfn = self.get_tempfile()
        model.event.dump_events([event], tempfn)
        self.viewer.read_events(tempfn)

    def test_add_remove_stations(self):
    