class ArrayDataCombo(ExtendedCombo):

    def __init__(self, h5_paths, **kwargs):

        super().__init__(**kwargs)
        self.update_model(h5_paths)

    def update_model(self, h5_paths):
        results_array_labels = set([])
        for h5_path in h5_paths:
            with h5py.File(h5_path, 'r') as h5_file:
                analysis_names = h5_file['results'].keys()

                for analysis_name in analysis_names:
                    for key in h5_file['results'][analysis_name].keys():
                        results_array_labels.add(analysis_name + ',' + key)

        model = QtGui.QStandardItemModel()

        item = QtGui.QStandardItem('shot number')
        model.setItem(0, 0, item)

        for i, idx in enumerate(results_array_labels):
            item = QtGui.QStandardItem(idx)
            model.setItem(i, 0, item)

        self.setModel(model)

    def get_idx(self):
        return tuple(str(self.currentText()).split(','))


class QuickWaterfallPlot(QuickDataPlot):

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.img = pg.ImageItem()
        self.plot.addItem(self.img)

        # Isocurve draplotsg
        self.iso = pg.IsocurveItem(level=1000, pen=color_palette[2])
        self.iso.setParentItem(self.img)
        self.iso.setZValue(5)

        # Contrast/color control
        self.hist = pg.HistogramLUTItem()
        self.hist.setImageItem(self.img)
        self.plots.addItem(self.hist)

        # Draggable line for setting isocurve level
        self.isoLine = pg.InfiniteLine(angle=0, movable=True, pen=color_palette[2])
        self.hist.vb.addItem(self.isoLine)
        self.hist.vb.setMouseEnabled(y=False)  # makes user interaction a little easier
        self.isoLine.setValue(1000)
        self.isoLine.setZValue(1000)  # bring iso line above contrast controls
        self.isoLine.sigDragged.connect(self.updateIsocurve)

        # Monkey-patch the image to use our custom hover function.
        # This is generally discouraged (you should subclass ImageItem instead),
        # but it works for a very simple use like this.
        self.img.hoverEvent = self.imageHoverEvent

        self.img.translate(-0.5, -0.5)

        self.scalex = 1
        self.scaley = 1

        self.cx = 0
        self.cy = 0

        self.nplots = 0

        self.table.setColumnCount(3)
        self.table.setRowCount(2)
        self.table.setColumnWidth(0, 200)
        self.table.setColumnWidth(1, 150)
        self.table.setColumnWidth(2, 150)
        self.table.setHorizontalHeaderLabels(['xvalue', 'yarray', 'zarray'])

        self.combox = NumericDataCombo(self.ap.df)
        self.comboy = ArrayDataCombo(self.ap.h5_paths)
        self.comboz = ArrayDataCombo(self.ap.h5_paths)

        self.table.setCellWidget(0, 0, self.combox)
        self.table.setCellWidget(0, 1, self.comboy)
        self.table.setCellWidget(0, 2, self.comboz)

        self.mk_buttons()

    def mk_buttons(self):
        self.bt_update = QPushButton('Update', self)
        self.bt_update.clicked.connect(self.update_from_h5)
        self.table.setCellWidget(1, 1, self.bt_update)

    def update_data_extractor(self):

        idxx = self.combox.get_idx()
        idxy = self.comboy.get_idx()
        idxz = self.comboz.get_idx()

        if idxx not in self.data_extractor.data_extractors:
            if idxx[0] == 'shot number':
                self.data_extractor[idxx] = EmptyDataExtractor()
            else:
                self.data_extractor[idxx] = SingleDataExtractor(idxx)

        if idxy not in self.data_extractor.data_extractors:
            self.data_extractor[idxy] = ArrayDataExtractor(idxy)

        if idxz not in self.data_extractor.data_extractors:
            self.data_extractor[idxz] = ArrayDataExtractor(idxz)

        self.data_extractor.clean_children([idxx, idxy, idxz])
        self.data_extractor.clean_memory(self.ap.h5_paths)

    def update(self, data=None):
        xs = np.array([])
        ys = np.array([])
        zs = np.array([])

        idxx = self.combox.get_idx()
        idxy = self.comboy.get_idx()
        idxz = self.comboz.get_idx()

        for i, h5_path in enumerate(self.ap.h5_paths_selected):

            data = self.data_extractor.get_data(h5_path)[0]

            if idxx[0] == 'shot number':
                x = self.ap.shotselector.get_selected_indices()[0][i]
            else:
                x = data[idxx]

            y = data[idxy]
            z = data[idxz]

            if y is not None and z is not None:
                xs = np.append(xs, x * np.ones_like(y))
                ys = np.append(ys, y)
                zs = np.append(zs, z)
            elif y is not None:
                xs = np.append(xs, x * np.ones_like(y))
                ys = np.append(ys, y)
                zs = np.append(zs, y * np.nan)
            elif z is not None:
                xs = np.append(xs, x * np.ones_like(z))
                ys = np.append(ys, z * np.nan)
                zs = np.append(zs, z)

        # here we don't want to assume that the data is on a grid
        # this can happen if the parameters where changed between two sweeps
        xi = np.linspace(xs.min(), xs.max(), 200)
        yi = np.linspace(ys.min(), ys.max(), 200)

        Xi, Yi = np.meshgrid(xi, yi)

        Zi = griddata((xs, ys), zs, (Xi, Yi), 'nearest')

        self.img.setImage(Zi.T)
        self.iso.setData(Zi.T)
        self.data_img = Zi

        # set position and scale of image
        newscalex = xi[1] - xi[0]
        newscaley = yi[1] - yi[0]

        transx = (xi[0] - (self.cx - 0.5 * self.scalex)) / newscalex - 0.5
        transy = (yi[0] - (self.cy - 0.5 * self.scaley)) / newscaley - 0.5

        self.img.scale(newscalex / self.scalex, newscaley / self.scaley)
        self.img.translate(transx, transy)

        self.scalex = newscalex
        self.scaley = newscaley

        self.cx = xi[0]
        self.cy = yi[0]

    def updateIsocurve(self):
        self.iso.setLevel(self.isoLine.value())

    def imageHoverEvent(self, event):
        """Show the position, pixel, and value under the mouse cursor.
        """
        if event.isExit():
            self.plot.setTitle("")
            return
        pos = event.pos()
        i, j = pos.y(), pos.x()
        i = int(np.clip(i, 0, self.data_img.shape[0] - 1))
        j = int(np.clip(j, 0, self.data_img.shape[1] - 1))
        val = self.data_img[i, j]
        ppos = self.img.mapToParent(pos)
        x, y = ppos.x(), ppos.y()
        self.plot.setTitle("pos: (%0.1f, %0.1f) value: %g" % (x, y, val))