#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016  Carlos Henrique Silva <carlosqsilva@outlook.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import remi.gui as gui
import remi.server as server
from remi import App, start

from matplotlib.backends.backend_agg import FigureCanvasAgg

import os
import pandas as pd
import threading
import time

from io import BytesIO
from pyspc import *

control_charts = {"Cusum": [cusum],
                  "Ewma": [ewma],
                  "Sbar": [xbar_sbar, sbar],
                  "Rbar": [xbar_rbar, rbar],
                  "T-Square Single": [Tsquare_single],
                  "T-Square": [Tsquare],
                  "MEWMA": [mewma],
                  "Moving Range": [xmr, mr],
                  "C Chart": [c],
                  "NP Chart": [np],
                  "P Chart": [p],
                  "U Chart": [u],
                  "I-MR-R": [imrx, imrmr, imrr],
                  "I-MR-S": [imrx, imrmr, imrstd]}


class MatplotImage(gui.Image):
    ax = None

    def __init__(self, **kwargs):
        super(MatplotImage, self).__init__("/%s/get_image_data?update_index=0" % id(self), **kwargs)
        self._buf = None
        self._buflock = threading.Lock()

        self.data = None
        self.layer = []
        # self.redraw()

    def redraw(self):

        self.figure = spc(data=self.data) + rules()
        for chart in self.layer:
            self.figure + chart()
        self.figure.make(figsize=(8, 6))

        canv = FigureCanvasAgg(self.figure.fig)
        buf = BytesIO()
        canv.print_figure(buf, format='png')
        with self._buflock:
            if self._buf is not None:
                self._buf.close()
            self._buf = buf

        i = int(time.time() * 1e6)
        self.attributes['src'] = "/%s/get_image_data?update_index=%d" % (id(self), i)

        super(MatplotImage, self).redraw()

    def get_image_data(self, update_index):
        with self._buflock:
            if self._buf is None:
                return None
            self._buf.seek(0)
            data = self._buf.read()

        return [data, {'Content-type': 'image/png'}]


bgcolor = '#DCDCDC'
overflow = 'hidden'
display = 'block'


class Pyspc(App):

    def __init__(self, *args):
        super(Pyspc, self).__init__(*args)

    def main(self):
        # root widget
        # vertical_container = gui.Widget(width='100%', height='100%')
        # vertical_container.style['background-color'] = bgcolor
        # vertical_container.style['display'] = display
        # vertical_container.style['overflow'] = overflow

        horizontal_container = gui.Widget(width='100%', height='100%', layout_orientation=gui.Widget.LAYOUT_HORIZONTAL)
        horizontal_container.style['background-color'] = bgcolor
        horizontal_container.style['display'] = display
        horizontal_container.style['overflow'] = 'scroll'
        horizontal_container.style['text-align'] = 'center'

        sub_container_left = gui.Widget(width='50%', layout_orientation=gui.Widget.LAYOUT_VERTICAL)
        sub_container_left.style['background-color'] = bgcolor
        sub_container_left.style['display'] = display
        sub_container_left.style['overflow'] = overflow
        sub_container_left.style['text-align'] = 'center'

        sub_container_right = gui.Widget(width='50%', layout_orientation=gui.Widget.LAYOUT_VERTICAL)
        sub_container_right.style['background-color'] = bgcolor
        sub_container_right.style['display'] = display
        sub_container_right.style['overflow'] = overflow
        sub_container_right.style['text-align'] = 'center'

        vbox1 = gui.Widget(width='100%', layout_orientation=gui.Widget.LAYOUT_HORIZONTAL, margin='0px')
        vbox1.style['background-color'] = bgcolor

        open_file = gui.Button('Open File', width='auto', height=30, margin='10px')
        open_file.set_on_click_listener(self, 'open_file_pressed')
        open_file.attributes['title'] = 'Clik here to open a .CSV file with your data'
        # open_file.style['font-size'] = 'large'

        open_clipboard = gui.Button('From Clipboard', widht='auto', height=30, margin='10px')
        open_clipboard.set_on_click_listener(self, 'open_clipboard_pressed')
        open_clipboard.attributes['title'] = 'Clik here to Paste data from the Clipboard eg: excel, html table, etc...'
        # open_clipboard.style['font-size'] = 'large'

        self.data_table = gui.Table(width='100%', height='100%', margin='10px')
        self.data_table.style['overflow'] = overflow
        # self.data_table.style['display'] = display

        vbox1.append(open_file)
        vbox1.append(open_clipboard)

        vbox2 = gui.Widget(width='100%', layout_orientation=gui.Widget.LAYOUT_HORIZONTAL, margin='0px')
        vbox2.style['background-color'] = bgcolor

        charts = ["Cusum", "Ewma", "Sbar", "Rbar", "T-Square Single", "T-Square", "MEWMA", "C Chart",
                  "NP Chart", "P Chart", "U Chart", "Moving Range", "I-MR-R", "I-MR-S"]
        self.dropdown = gui.DropDown.new_from_list(charts, width='auto', height=30, margin='10px')
        self.dropdown.attributes['title'] = 'Choose the right control for the that you have'
        # self.dropdown.style['font-size'] = 'large'

        plot_chart = gui.Button('Plot Chart', width='auto', height=30, margin='10px')
        plot_chart.set_on_click_listener(self, 'plot_chart_pressed')
        # plot_chart.style['font-size'] = 'large'
        save_chart = gui.Button('Save Chart', width='auto', height=30, margin='10px')
        save_chart.set_on_click_listener(self, 'save_chart_pressed')
        # save_chart.style['font-size'] = 'large'

        self.mpl = MatplotImage(width='100%', height='auto')
        self.mpl.style['margin'] = '10px'

        vbox2.append(self.dropdown)
        vbox2.append(plot_chart)
        vbox2.append(save_chart)

        self.status_txt = gui.Label('', width='100%', height=20, margin='10px')

        sub_container_left.append(vbox1)
        sub_container_left.append(self.status_txt)
        sub_container_left.append(self.data_table)

        sub_container_right.append(vbox2)
        sub_container_right.append(self.mpl)

        horizontal_container.append(sub_container_left)
        horizontal_container.append(sub_container_right)

        # vertical_container.append(horizontal_container)

        return horizontal_container

    def open_file_pressed(self):
        self.open_filedialog = gui.FileSelectionDialog(title='File Selection Dialog', message='Select a .CSV file',
                                                       multiple_selection=False, allow_folder_selection=False)
        self.open_filedialog.set_on_confirm_value_listener(self, 'file_selection_confirm')
        self.open_filedialog.show(self)

    def file_selection_confirm(self, filepath):
        try:
            self.data = pd.read_csv(filepath[0])

            self.data_table.empty()
            table = [list(self.data.columns)] + [[str(x) for x in row] for row in self.data.values]
            self.data_table.from_2d_matrix(table)
        except Exception as e:
            self.text_message(repr(e))
        rows, columns = self.data.shape
        filename = os.path.basename(filepath[0])
        self.status_txt.set_text("File Selected: {0} | {1} Rows {2} Columns".format(filename, rows, columns))

    def open_clipboard_pressed(self):
        try:
            self.data = pd.read_clipboard()

            self.data_table.empty()
            table = [list(self.data.columns)] + [[str(x) for x in row] for row in self.data.values]
            self.data_table.from_2d_matrix(table)
        except Exception as e:
            self.text_message(repr(e))
        pass

    def plot_chart_pressed(self):
        try:
            chart = self.dropdown.get_value()
            self.mpl.data = self.data
            self.mpl.layer = control_charts[chart]
            self.mpl.redraw()
        except Exception as e:
            self.text_message(repr(e))

    def save_chart_pressed(self):
        self.save_dialog = gui.InputDialog('Save Dialog', 'Give a name to file:', initial_value='Untitled.png',
                                           width=500, height=160)
        self.save_dialog.set_on_confirm_value_listener(self, 'save_dialog_confirm')
        self.save_dialog.show(self)

    def save_dialog_confirm(self, filename):
        self.mpl.figure.save(filename)
        _root = os.path.abspath(os.path.dirname(__file__))
        self.status_txt.set_text('File Saved in: %s' % os.path.join(_root, filename))

    def text_message(self, message):
        self.custom_dialog = gui.GenericDialog(title='Dialog Box', width='600px')
        text_input = gui.TextInput(single_line=False)
        text_input.set_text(message)

        self.custom_dialog.add_field_with_label('text_input_messade', 'System Message', text_input)
        self.custom_dialog.show(self)


if __name__ == "__main__":
    start(Pyspc, debug=True, address='127.0.0.1', port=8081)
    # s = server.StandaloneServer(Pyspc, start=True, title="Pyspc: Statistical Process Control Library for Humans")