#!/usr/bin/python
# -*- coding: utf-8 -*-

import json, AnyQt

from pyforms_lite.utils.settings_manager import conf

from AnyQt.QtWidgets import QFrame
from AnyQt.QtWidgets import QVBoxLayout
from AnyQt.QtWidgets import QTabWidget
from AnyQt.QtWidgets import QSplitter
from AnyQt.QtWidgets import QHBoxLayout
from AnyQt.QtWidgets import QSpacerItem
from AnyQt.QtWidgets import QSizePolicy
from AnyQt.QtWidgets import QLabel
from AnyQt.QtGui     import QFont
from AnyQt.QtWidgets import QFileDialog
from AnyQt.QtWidgets import QApplication
from AnyQt           import QtCore, _api

from pyforms_lite.gui.controls.ControlBase import ControlBase

from AnyQt.QtWidgets import QMessageBox, QInputDialog

class vsplitter(object):
    def __init__(self, *args, **kwargs):
        self.items = args
        self.left_width = kwargs.get('left_width', 1)
        self.right_width = kwargs.get('right_width', 1)
    def __getitem__(self,index): return self.items[index]
    def __setitem__(self,index,value): self.items[index] = value
    def __len__(self):  return len(self.items)
    def __iter__(self): 
        self._index = -1; return self
    def __next__(self): 
        self._index += 1
        if self._index>=len(self.items): raise StopIteration
        return self.items[self._index]

class hsplitter(object):
    def __init__(self, *args, **kwargs):  self.items = args
    def __getitem__(self,index): return self.items[index]
    def __setitem__(self,index,value): self.items[index] = value
    def __len__(self):  return len(self.items)
    def __iter__(self): 
        self._index = -1; return self
    def __next__(self): 
        self._index += 1
        if self._index>=len(self.items): raise StopIteration
        return self.items[self._index]


class BaseWidget(QFrame):
    """
    The class implements the most basic widget or window.
    """

    def __init__(self, *args, **kwargs):
        title = kwargs.get('title', args[0] if len(args)>0 else '')

        parent_win = kwargs.get('parent_win', kwargs.get('parent_widget', None))
        win_flag   = kwargs.get('win_flag', None)

        self._parent_widget = parent_win

        if parent_win is not None and win_flag is None: win_flag = QtCore.Qt.Dialog

        QFrame.__init__(self) if parent_win is None else QFrame.__init__(self, parent_win, win_flag)

        layout = QVBoxLayout()
        self.setLayout(layout)
        
        if _api.USED_API == _api.QT_API_PYQT5:
            layout.setContentsMargins(0,0,0,0)
        elif _api.USED_API == _api.QT_API_PYQT4:
            layout.setMargin(0)

        self.title = title

        self.title = title
        self.has_progress = False

        self.toolbar    = []
        self._mainmenu  = []
        self._splitters = []
        self._tabs = []
        self._formset = None
        self._formLoaded = False
        self.uid = id(self)

        self.setAccessibleName('BaseWidget')

    ##########################################################################
    ############ FUNCTIONS  ##################################################
    ##########################################################################

    def init_form(self):
        """
        Generate the module Form
        """
        if not self._formLoaded:

            if self._formset is not None:
                control = self.generate_panel(self._formset)
                self.layout().addWidget(control)
            else:
                allparams = self.controls
                for key, param in allparams.items():
                    param.parent = self
                    param.name = key
                    self.layout().addWidget(param.form)
            self._formLoaded = True

    def set_margin(self, margin):
        if _api.USED_API == _api.QT_API_PYQT5:
            self.layout().setContentsMargins(margin,margin,margin,margin)
        elif _api.USED_API == _api.QT_API_PYQT4:
            self.layout().setMargin(margin)


    def generate_tabs(self, formsetdict):
        """
        Generate QTabWidget for the module form
        @param formset: Tab form configuration
        @type formset: dict
        """
        tabs = QTabWidget(self)
        for key, item in sorted(formsetdict.items()):
            ctrl = self.generate_panel(item)
            tabs.addTab(ctrl, key[key.find(':') + 1:])
        return tabs

    def generate_panel(self, formset):
        """
        Generate a panel for the module form with all the controls
        formset format example: [('_video', '_arenas', '_run'), {"Player":['_threshold', "_player", "=", "_results", "_query"], "Background image":[(' ', '_selectBackground', '_paintBackground'), '_image']}, "_progress"]
        tuple: will display the controls in the same horizontal line
        list: will display the controls in the same vertical line
        dict: will display the controls in a tab widget
        '||': will plit the controls in a horizontal line
        '=': will plit the controls in a vertical line
        @param formset: Form configuration
        @type formset: list
        """
        control = None
        if '=' in formset or isinstance( formset, hsplitter ):
            control      = QSplitter(QtCore.Qt.Vertical)
            index        = list(formset).index('=')
            first_panel  = self.generate_panel(formset[0:index])
            second_panel = self.generate_panel(formset[index+1:])
            control.addWidget(first_panel)
            control.addWidget(second_panel)
            self._splitters.append(control)
            return control
        elif '||' in formset or isinstance( formset, vsplitter ):
            control      = QSplitter(QtCore.Qt.Horizontal)
            index        = list(formset).index('||')
            first_panel  = self.generate_panel(formset[0:index])
            second_panel = self.generate_panel(formset[index+1:])
            control.addWidget(first_panel)
            control.addWidget(second_panel)

            if isinstance( formset, vsplitter ):
                sizes = [formset.left_width, formset.right_width]
                control.setSizes(sizes)
            self._splitters.append(control)
            return control
        control = QFrame(self)
        layout = None
        if type(formset) is tuple:
            layout = QHBoxLayout()
            for row in formset:
                if isinstance(row, (list, tuple, vsplitter, hsplitter) ):
                    panel = self.generate_panel(row)
                    layout.addWidget(panel)
                elif row == " ":
                    spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
                    layout.addItem(spacer)
                elif type(row) is dict:
                    c = self.generate_tabs(row)
                    layout.addWidget(c)
                    self._tabs.append(c)
                else:
                    param = self.controls.get(row, None)
                    if param is None:
                        label = QLabel()
                        label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
                        # layout.addWidget( label )

                        if row.startswith('info:'):
                            label.setText(row[5:])
                            font = QFont()
                            font.setPointSize(10)
                            label.setFont(font)
                            label.setAccessibleName('info')
                        elif row.startswith('h1:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(17)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h1')
                        elif row.startswith('h2:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(16)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h2')
                        elif row.startswith('h3:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(15)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h3')
                        elif row.startswith('h4:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(14)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h4')
                        elif row.startswith('h5:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(12)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h5')
                        else:
                            label.setText(row)
                            font = QFont()
                            font.setPointSize(10)
                            label.setFont(font)
                            label.setAccessibleName('msg')
                        label.setToolTip(label.text())
                        layout.addWidget(label)
                    else:
                        param.parent = self
                        param.name = row
                        layout.addWidget(param.form)
        elif type(formset) is list:
            layout = QVBoxLayout()
            for row in formset:
                if isinstance(row, (list, tuple, vsplitter, hsplitter) ):
                    panel = self.generate_panel(row)
                    layout.addWidget(panel)
                elif row == " ":
                    spacer = QSpacerItem(
                        20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
                    layout.addItem(spacer)
                elif type(row) is dict:
                    c = self.generate_tabs(row)
                    layout.addWidget(c)
                    self._tabs.append(c)
                else:
                    param = self.controls.get(row, None)
                    if param is None:
                        label = QLabel()
                        label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
                        label.resize(30, 30)
                        # layout.addWidget( label )

                        if row.startswith('info:'):
                            label.setText(row[5:])
                            font = QFont()
                            font.setPointSize(10)
                            label.setFont(font)
                            label.setAccessibleName('info')
                        elif row.startswith('h1:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(17)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h1')
                        elif row.startswith('h2:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(16)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h2')
                        elif row.startswith('h3:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(15)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h3')
                        elif row.startswith('h4:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(14)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h4')
                        elif row.startswith('h5:'):
                            label.setText(row[3:])
                            font = QFont()
                            font.setPointSize(12)
                            font.setBold(True)
                            label.setFont(font)
                            label.setAccessibleName('h5')
                        else:
                            label.setText(row)
                            font = QFont()
                            font.setPointSize(10)
                            label.setFont(font)
                            label.setAccessibleName('msg')

                        label.setToolTip(label.text())

                        layout.addWidget(label)
                    else:
                        param.parent = self
                        param.name = row
                        layout.addWidget(param.form)
        
        if _api.USED_API == _api.QT_API_PYQT5:
            layout.setContentsMargins(0,0,0,0)
        elif _api.USED_API == _api.QT_API_PYQT4:
            layout.setMargin(0)
            
        control.setLayout(layout)
        return control

    def show(self):
        self.init_form()
        super(BaseWidget, self).show()

    def save_form(self, data={}, path=None):
        allparams = self.controls

        if hasattr(self, 'load_order'):
            for name in self.load_order:
                param = allparams[name]
                data[name] = {}
                param.save_form(data[name])
        else:
            for name, param in allparams.items():
                data[name] = {}
                param.save_form(data[name])
        return data

    def load_form(self, data, path=None):
        allparams = self.controls

        if hasattr(self, 'load_order'):
            for name in self.load_order:
                param = allparams[name]
                if name in data:
                    param.load_form(data[name])
        else:
            for name, param in allparams.items():
                if name in data:
                    param.load_form(data[name])
                # self.init_form()

    def save_window(self):
        allparams = self.controls
        data = {}
        self.save_form(data)

        filename, _ = QFileDialog.getSaveFileName(self, 'Select file')
        with open(filename, 'w') as output_file: json.dump(data, output_file)

    def load_form_filename(self, filename):
        with open(filename, 'r') as pkl_file:
            project_data = json.load(pkl_file)
        data = dict(project_data)
        self.load_form(data)

    def load_window(self):
        filename, _ = QFileDialog.getOpenFileNames(self, 'Select file')
        self.load_form_filename(str(filename[0]))

    def close(self):
        super(BaseWidget, self).close()


    def input_text(self, msg, title='', default=None):
        text, ok = QInputDialog.getText(self, title, msg, text=default)
        if ok:
            return str(text)
        else:
            return None

    def input_double(self, msg, title='', default=0,  min=-2147483647, max=2147483647, decimals=1):
        text, ok = QInputDialog.getDouble(self, title, msg, value=default, min=min, max=max, decimals=decimals)
        if ok:
            return float(text)
        else:
            return None
        
    def input_int(self, msg, title='', default=0, min=-2147483647, max=2147483647):
        text, ok = QInputDialog.getInt(self, title, msg, value=default, min=min, max=max)
        if ok:
            return int(text)
        else:
            return None


    def question(self, msg, title=None, buttons=['no', 'yes']):
        btns = None
        for btn in buttons:
            if btn.lower()=='cancel':
                b = QMessageBox.Cancel
            elif btn.lower()=='no':
                b = QMessageBox.No
            elif btn.lower()=='yes':
                b = QMessageBox.Yes

            if btns is None: 
                btns=b
            else: btns |= b 

        m = QMessageBox(QMessageBox.Question, title, msg, btns) 
        reply = m.exec()

        if reply==QMessageBox.Cancel: return 'cancel'
        elif reply==QMessageBox.No:   return 'no'
        elif reply==QMessageBox.Yes:  return 'yes'

        return None

    def message(self, msg, title=None, msg_type=None):
        if msg_type=='success':
            m = QMessageBox(QMessageBox.NoIcon, title, msg) 
        elif msg_type=='info':
            m = QMessageBox(QMessageBox.Information, title, msg)    
        elif msg_type=='warning':
            m = QMessageBox(QMessageBox.Warning, title, msg) 
        elif msg_type=='error':
            m = QMessageBox(QMessageBox.Critical, title, msg) 
        elif msg_type=='about':
            m = QMessageBox(QMessageBox.Question, title, msg) 
        elif msg_type=='aboutQt':
            m = QMessageBox(QMessageBox.Question, title, msg)
        else:
            m = QMessageBox(QMessageBox.NoIcon, title, msg)

        m.exec()

    def success(self,   msg, title=None):   self.message(msg, title, msg_type='success')
    def info(self,      msg, title=None):   self.message(msg, title, msg_type='info')
    def warning(self,   msg, title=None):   self.message(msg, title, msg_type='warning');
    def alert(self,     msg, title=None):   self.message(msg, title, msg_type='error')
    def critical(self,  msg, title=None):   self.message(msg, title, msg_type='error')
    def about(self,     msg, title=None):   self.message(msg, title, msg_type='about')
    def aboutQt(self,   msg, title=None):   self.message(msg, title, msg_type='aboutQt')

    def message_popup(self, msg, title='', buttons=None, handler=None, msg_type='success'):
        pass
    def success_popup(self, msg, title='', buttons=None, handler=None):
        return self.message_popup(msg, title, buttons, handler, msg_type='success')
    def info_popup(self, msg, title='', buttons=None, handler=None):
        return self.message_popup(msg, title, buttons, handler, msg_type='info')
    def warning_popup(self, msg, title='', buttons=None, handler=None):
        return self.message_popup(msg, title, buttons, handler, msg_type='warning')
    def alert_popup(self, msg, title='', buttons=None, handler=None):
        return self.message_popup(msg, title, buttons, handler, msg_type='alert')




    ##########################################################################
    ############ GUI functions ###############################################
    ##########################################################################

    def set_margin(self, margin):
        if AnyQt.USED_API=='pyqt5':
            self.layout().setContentsMargins(margin,margin,margin,margin)
        else:
            self.layout().setMargin(margin)

    ##########################################################################
    ############ EVENTS ######################################################
    ##########################################################################

    def before_close_event(self):
        """ 
        Do something before closing widget 
        Note that the window will be closed anyway    
        """
        pass

    ##########################################################################
    ############ Properties ##################################################
    ##########################################################################

    @property
    def controls(self):
        """
        Return all the form controls from the the module
        """
        result = {}
        for name, var in vars(self).items():
            try:
                if isinstance(var, ControlBase):
                    result[name] = var
            except:
                pass
        return result

    ############################################################################
    ############ GUI Properties ################################################
    ############################################################################


    @property
    def form_has_loaded(self):
        return self._formLoaded

    
    @property 
    def form(self): 
        return self 
    
    @property
    def visible(self):
        return self.isVisible()

    @property
    def mainmenu(self):
        return self._mainmenu
    @mainmenu.setter
    def mainmenu(self, value):
        self._mainmenu = value


    @property
    def controls(self):
        """
        Return all the form controls from the the module
        """
        result = {}
        for name, var in vars(self).items():
            try:
                if isinstance(var, ControlBase):
                    result[name] = var
            except:
                pass
        return result

    ############################################################################
    ############ GUI Properties ################################################
    ############################################################################


    @property
    def form_has_loaded(self):
        return self._formLoaded

    @property
    def parent_widget(self):
        return self._parent_widget

    @property
    def form(self):
        return self

    @property
    def title(self):
        return self.windowTitle()

    @title.setter
    def title(self, value):
        self.setWindowTitle(value)

    
    @property
    def formset(self):
        return self._formset

    @formset.setter
    def formset(self, value):
        self._formset = value

    @property
    def uid(self):
        return self._uid

    @uid.setter
    def uid(self, value):
        self._uid = value

    
    @property
    def visible(self):
        return self.isVisible()

    

    ##########################################################################
    ############ PRIVATE FUNCTIONS ###########################################
    ##########################################################################
    
    def closeEvent(self, event):
        self.before_close_event()
        super(BaseWidget, self).closeEvent(event)
