# -*- coding: utf-8 -*-
from __future__ import print_function, division, unicode_literals
from __future__ import absolute_import

import time, numpy as np
import matplotlib.pyplot as plt


class DataGraphs(object):
    '''Bar graph display of average over samples'''

    def __init__(self, Wtime, ConfDict, sigName, XYmode):
        '''Args:   Wtime: waiting time between updates
        confDict: PicoScope Configuration dictionary
        XYmode: bool, xy-display if True
        '''

        # collect relevant configuration parameters
        self.Npoints = 120  # number of points for history
        self.bwidth = 0.5  # width of bars

        # get relevant settings from (PicoScope) ConfDict
        self.dT = Wtime / 1000.0
        self.NChan = ConfDict['NChannels']

        self.ChanLim = []
        CRanges = ConfDict['CRanges']
        COffsets = ConfDict['ChanOffsets']
        for i in range(self.NChan):
            self.ChanLim.append((-CRanges[i] - COffsets[i], CRanges[i] - COffsets[i]))

        self.ChanNams = ConfDict['Channels']
        self.ChanColors = ConfDict['ChanColors']

        self.XYmode = XYmode
        if self.NChan < 2:
            self.XYmode = True

        # data structures needed throughout the class
        self.Ti = self.dT * np.linspace(-self.Npoints + 1, 0, self.Npoints)
        self.ind = self.bwidth + np.arange(self.NChan)  # bar position for voltages
        #
        self.Vhist = np.zeros([self.NChan, self.Npoints])
        self.d = np.zeros([self.NChan, self.Npoints])

        # set up a figure to plot actual voltage and samplings from Picoscope
        if self.XYmode:
            fig = plt.figure("DataGraphs", figsize=(10.0, 5.5))
            fig.subplots_adjust(left=0.09, bottom=0.1, right=0.975, top=0.94, wspace=3.5, hspace=0.25)
        else:
            fig = plt.figure("DataGraphs", figsize=(4.0, 5.3))
            fig.subplots_adjust(left=0.2, bottom=0.08, right=0.8, top=0.94, wspace=None, hspace=0.25)

        axes = []

        # history plot
        if self.XYmode:
            axes.append(plt.subplot2grid((6, 5), (4, 0), rowspan=2, colspan=2))
        else:
            axes.append(plt.subplot2grid((6, 1), (4, 0), rowspan=2))
        if self.NChan > 1:
            axes.append(axes[0].twinx())

        for i, C in enumerate(self.ChanNams):
            if i > 1:
                break  # works for a maximum of 2 Channels only
            axes[i].set_ylim(*self.ChanLim[i])
            axes[i].set_ylabel('Chan ' + C + ' ' + sigName, color=self.ChanColors[i])
            axes[i].grid(True, color=self.ChanColors[i], linestyle='--', alpha=0.3)
        axes[0].set_xlabel('History (s)', size='x-large')

        # barchart
        if self.XYmode:
            axes.append(plt.subplot2grid((6, 5), (1, 0), rowspan=3, colspan=2))
        else:
            axes.append(plt.subplot2grid((6, 1), (1, 0), rowspan=3))
        axbar1 = axes[-1]
        axbar1.set_frame_on(False)
        if self.NChan > 1:
            axbar2 = axbar1.twinx()
            axbar2.set_frame_on(False)
        axbar1.get_xaxis().set_visible(False)
        axbar1.set_xlim(0.0, self.NChan)
        axbar1.axvline(0, color=self.ChanColors[0])
        if self.NChan > 1:
            axbar1.axvline(self.NChan, color=self.ChanColors[1])
        axbar1.set_ylim(*self.ChanLim[0])
        axbar1.axhline(0.0, color='k', linestyle='-', lw=2, alpha=0.5)
        axbar1.set_ylabel('Chan A ' + sigName, size='x-large', color=self.ChanColors[0])
        axbar1.grid(True, color=self.ChanColors[0], linestyle='--', alpha=0.3)
        if self.NChan > 1:
            axbar2.set_ylim(*self.ChanLim[1])
            axbar2.set_ylabel('Chan B ' + sigName, size='x-large', color=self.ChanColors[1])
            axbar2.grid(True, color=self.ChanColors[0], linestyle='--', alpha=0.3)

        # Voltage in Text format
        if self.XYmode:
            axes.append(plt.subplot2grid((6, 5), (0, 0), rowspan=1, colspan=2))
        else:
            axes.append(plt.subplot2grid((6, 1), (0, 0)))
        axtxt = axes[-1]
        axtxt.set_frame_on(False)
        axtxt.get_xaxis().set_visible(False)
        axtxt.get_yaxis().set_visible(False)
        axtxt.set_title('Voltmeter', size='xx-large')

        # XY display
        if self.XYmode:
            axes.append(plt.subplot2grid((6, 5), (0, 2), rowspan=6, colspan=3))
            axXY = axes[-1]
            axXY.set_xlim(*self.ChanLim[0])
            axXY.set_ylim(*self.ChanLim[1])
            axXY.set_xlabel('Chan ' + self.ChanNams[0] + ' ' + sigName, size='x-large', color=self.ChanColors[0])
            axXY.set_ylabel('Chan ' + self.ChanNams[1] + ' ' + sigName, size='x-large', color=self.ChanColors[1])
            axXY.set_title('XY-View', size='xx-large')
            axXY.grid(True, color='grey', linestyle='--', alpha=0.3)
        else:
            axXY = None

        self.fig = fig
        self.axes = axes
        self.axbar1 = axbar1
        if self.NChan > 1:
            self.axbar2 = axbar2
        self.axtxt = axtxt
        self.axXY = axXY

    # -- end def grVMeterIni

    def init(self):
        # initialize objects to be animated

        # a bar graph for the actual voltages
        (self.bgraph1,) = self.axbar1.bar(
            self.ind[0], 0.0, self.bwidth, align='center', color=self.ChanColors[0], alpha=0.5
        )
        if self.NChan > 1:
            (self.bgraph2,) = self.axbar2.bar(
                self.ind[1], 0.0, self.bwidth, align='center', color=self.ChanColors[1], alpha=0.5
            )
        # history graphs
        self.graphs = ()
        for i, C in enumerate(self.ChanNams):
            if i > 1:
                break  # max. of 2 channels
            (g,) = self.axes[i].plot(self.Ti, np.zeros(self.Npoints), color=self.ChanColors[i])
            self.graphs += (g,)
        self.animtxt = self.axtxt.text(0.01, 0.05, ' ', transform=self.axtxt.transAxes, size='large', color='darkblue')

        if self.XYmode:
            (g,) = self.axXY.plot([0.0], [0.0], color='firebrick')
            self.graphs += (g,)

        self.t0 = time.time()  # remember start time

        if self.NChan > 1:
            return (self.bgraph1,) + (self.bgraph2,) + self.graphs + (self.animtxt,)
        else:
            # -- end DataGraphs.init()
            return (self.bgraph1,) + self.graphs + (self.animtxt,)

    def __call__(self, data):
        # update graphics with actual data
        if data != None:
            n, dat = data
            if n == 0:
                return self.init()

            k = n % self.Npoints
            txt = []
            for i, C in enumerate(self.ChanNams):
                if i > 1:
                    break  # works for 2 channels only
                self.Vhist[i, k] = dat[i]
                # update history graph
                if n > 1:  # !!! fix to avoid permanent display of first object in blit mode
                    self.d[i] = np.concatenate((self.Vhist[i, k + 1 :], self.Vhist[i, : k + 1]), axis=0)
                    self.graphs[i].set_data(self.Ti, self.d[i])
                    if self.XYmode:
                        self.graphs[-1].set_data(self.d[0], self.d[1])
                txt.append('  %s:   %.3gV' % (C, self.Vhist[i, k]))
            # update bar chart
            if n > 1:  # !!! fix to avoid permanent display of first object in blit mode
                self.bgraph1.set_height(dat[0])
                if self.NChan > 1:
                    self.bgraph2.set_height(dat[1])
            else:
                self.bgraph1.set_height(0.0)
                if self.NChan > 1:
                    self.bgraph2.set_height(0.0)

            if self.NChan > 1:
                self.animtxt.set_text(txt[0] + '\n' + txt[1])
            else:
                self.animtxt.set_text(txt[0])
        # -- end if != None

        if self.NChan > 1:
            return (self.bgraph1,) + (self.bgraph2,) + self.graphs + (self.animtxt,)
        else:
            return (self.bgraph1,) + self.graphs + (self.animtxt,)


# - -end def DataGraphs.__call__
# -end class VoltMeter
