#-*- coding: utf-8 -*-

# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from calculate.consolegui import qt
from more import ButtonMenu, icon_visible, LabelWordWrap, get_sid, show_msg, \
                 ClientServiceThread, show_question, get_view_params, _print, \
    get_system_rgb


class StepLabel(qt.QLabel):
    clicked = qt.Signal()
    def __init__(self, text, parent):
        qt.QLabel.__init__(self, parent)
        self.setWordWrap(True)
        self.setText(text)
        self.updateGeometry()
        self.setCursor(qt.Qt.PointingHandCursor)
        bg = get_system_rgb(parent._parent, qt.QPalette.Highlight)
        self.setStyleSheet("QLabel {margin-left: 0px; margin-right: 0px;}"
                            "QLabel:hover {"#color: blue;"
#                           "QLabel:hover {color: white;"
                           "background-color: %s;}"%bg)
        self.setContentsMargins(26,0,26,0)
        self.adjustSize()
        self.setFixedHeight(self.height() + 13)

    def mousePressEvent(self, event):
        self.clicked.emit()

    def setBold(self, bold):
        font = self.font()
        font.setBold(bold)
        self.setFont(font)

class LeftMenu(qt.QScrollArea):
    def __init__(self, parent, ClientObj):
        qt.QScrollArea.__init__(self, parent)
        self._parent = parent
        self.ClientObj = ClientObj

        self.horizontalScrollBar().hide()
        self.old_title = None
#        self.setStyleSheet("QWidget { background-color: rgb (%s) ;}" \
#                         %ClientObj.method_background_color.replace(' ',',',2))
        # Set style
#        self.setStyleSheet("QScrollArea {"# D6D2D0
##                           "background-color: #EEEEEE;"
#                           "background-color: qlineargradient("
#                           "x1: 0, y1: 0, x2: 0, y2: 1, "
#                           "stop: 0 #EEEEEE, stop: 0.8 #EEEEEE, "
#                           "stop: 1 #E4E1E0);"
#
##                           "border: 4px solid red;"
#                           "border-right: 1px solid qlineargradient("
#                           "x1: 0, y1: 0, x2: 0, y2: 1, "
#                           "stop: 0 #A8A3A0, stop: 0.8 #A8A3A0, "
#                           "stop: 0.95 transparent, stop: 1 transparent);"
##                           "border-bottom-color: qlineargradient("
##                           "x1: 0, y1: 0, x2: 0, y2: 1, "
##                           "stop: 0 transparent, stop: 1 #888380);"
##                           "border-left-color: qlineargradient("
##                           "x1: 1, y1: 0, x2: 0, y2: 0, "
##                           "stop: 0 transparent, stop: 1 #888380);"
##                           "border-top-color: qlineargradient("
##                           "x1: 0, y1: 1, x2: 0, y2: 0, "
##                           "stop: 0 transparent, stop: 1 #888380);}")
#                           "border-bottom: 0px;"
#                           "border-left: 0px;"
#                           "border-top: 0px;}")
        self.setFrameShape(qt.QFrame.NoFrame)
        self.setAttribute(qt.Qt.WA_DeleteOnClose)

    def create_menu(self, display_wgt, groups, sub_groups, ClientObj):
        self.display_wgt = display_wgt
        # create left subgroup menu
        self.old_title = self._parent.ClientObj._parent.windowTitle()
#        icon_visible(self._parent.ClientObj.MainWidget, 'Methods', True)
        icon_visible(self._parent.ClientObj.MainWidget, 'Back', True)
        
        self.widget = qt.QWidget (self)

        #self.cur_palette = display_wgt._parent.viewport().palette()
        #self.widget.setPalette(self.cur_palette)
#        self.widget.setStyleSheet("QWidget { background-color: rgb(%s) }" \
#                        %ClientObj.method_background_color.replace(' ',',',2))
        #self.widget.setStyleSheet("QWidget { background-color: #EEEEEE;}")

        self.lable_list = []
        self.button_list = {}
        self.layout = qt.QVBoxLayout(self.widget)
        
        self.layout.setAlignment(qt.Qt.AlignTop | qt.Qt.AlignHCenter)
        

        self.group_name = LabelWordWrap(sub_groups[0].split('.')[0], self)
        
        self.group_name.setStyleSheet( \
        'QLabel'
        '{'
            'border-bottom: 2px outset black;'
            'border-radius: 3px;'
        '}')
        
        self.group_name.setAlignment(qt.Qt.AlignHCenter)
        self.layout.addWidget(self.group_name)
        
        for num in range(len(sub_groups)):
            if len(sub_groups[num].split('.')) > 1:
#                try:
                sub_group = sub_groups[num].split('.')[1]
#                except (UnicodeDecodeError, UnicodeEncodeError):
#                    pass
                attrubute_list = []
                sub_group_list = []
                if self.button_list.has_key(sub_group):
                    attrubute_list = self.button_list[sub_group][0]
                    sub_group_list = self.button_list[sub_group][1]
                self.button_list[sub_group] = []
                param_list = [groups[num*3], groups[num*3 +1], groups[num*3 +2]]
                self.button_list[sub_group].append \
                        (attrubute_list + param_list)
                sub_group_list.append(sub_groups[num].split('.',1)[1])
                self.button_list[sub_group].append \
                        (sub_group_list)
                
                Button = ButtonMenu(sub_group, sub_group, \
                                            'folder-documents,folder', self)
                Button.clicked.connect(display_wgt.groupActivated \
                                        (self.button_list[sub_group][0],\
                                         self.button_list[sub_group][1]))
                self.button_list[sub_group].append(Button)                
                
                continue
        for i in range (0, len(groups), 3):
            try:
                if len(sub_groups[i/3].split('.')) > 1:
                    continue
            except IndexError:
                pass
            Button = ButtonMenu(groups[i], groups[i + 1], groups[i + 2], self)
            Button.clicked.connect(self.onActivated)
            if not self.button_list.has_key(sub_groups[num]):
                self.button_list[sub_groups[num]] = []
            self.button_list[sub_groups[num]].append(Button)
        
        for num in range(len(self.button_list)):
            # add subgroup
            if len(sub_groups[num].split('.')) > 1:
                
                sub_group = sub_groups[num].split('.')[1]

                self.layout.addWidget(self.button_list[sub_group] \
                                [len(self.button_list[sub_group]) - 1])
                continue

            # add methos
            for button in self.button_list[sub_groups[num]]:
                self.layout.addWidget(button)

        self.setWidget(self.widget)
        
        self.setWidgetResizable(True)

#        self.setFixedWidth(self.sizeHint().width() + \
#                           self.verticalScrollBar().sizeHint().width())
        self.setFixedWidth(self.sizeHint().width())

    def groupActivated(self, groups, sub_group, title, ClientObj, back = False):
        ClientObj.MainWidget.delete_MainFrameWgt()
        ClientObj.MainWidget.MainFrameWgt = qt.QWidget \
                                                    (ClientObj.MainWidget)

        hlayout = qt.QHBoxLayout()
        hlayout.addItem(qt.QSpacerItem( 0, 0, \
            qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding ))  
        ClientObj.MainWidget.MainFrameWgt.setLayout(hlayout)
        

        ClientObj.MainWidget.main_frame.setWidget \
                                            (ClientObj.MainWidget.MainFrameWgt)
        ClientObj.MainWidget.main_frame.setWidgetResizable(True)        
        
        ClientObj.MainWidget.left_frame.update()
        ClientObj.MainWidget.left_frame.show()
        
        ClientObj._parent.setWindowTitle (title)
        self.old_title = title

        self.create_menu (self.display_wgt, groups, sub_group, ClientObj)

    def onActivated(self):
        method_name = self.sender().objectName()
        
        # set new Title
        new_title = self.sender().text()
        try:
            new_title = new_title.decode('utf-8')
        except (UnicodeDecodeError, UnicodeEncodeError):
            pass
        self._parent.ClientObj._parent.setWindowTitle \
                (new_title + ' - ' + self.old_title)
        
        step = 0
        self._parent.ClientObj.method_name = method_name

        self._parent.ClientObj.sid = \
                                get_sid(self._parent.ClientObj.client)
        # switch to the desired step
        if self._parent.ClientObj.param_objects.has_key(method_name):
            self._parent.ClientObj.param_objects[method_name]['step'] = step

        # Call server method
        if hasattr (self, 'onActivated_thread'):
            if self.onActivated_thread.isRunning():
                return 1
        view_params = get_view_params(self._parent.ClientObj.client, \
                                     str(method_name + '_view'), step = step)
        self.onActivated_thread = ClientServiceThread(self._parent.ClientObj, \
                               str(method_name + '_view'), \
                               int(self._parent.ClientObj.sid), view_params, \
                               return_except = True)
        self.onActivated_thread.signal.connect(self.onActivated_after)
        self.onActivated_thread.start()

    def onActivated_after(self, view):
        if type(view) == Exception:
            if hasattr (view.message, 'message'):
                view = view.message

            if type(view.message) == tuple:
                if view.message[0] == 403:
                    msg = _('Permission denied')
                else:
                    msg = ' '.join(map(lambda x: str(x), view.message))
            else:
                msg = view.message.__str__()
            show_msg(msg)
            return 1

        self._parent.ClientObj.MainWidget.main_frame_view(view, \
                                            self._parent.ClientObj.method_name)

    def create_steps (self, method_name, steps, icons = None):
        self.old_title = self._parent.ClientObj._parent.windowTitle()
        if not hasattr (self, 'step'):
            self.step = 0
#        icon_visible(self._parent.ClientObj.MainWidget, 'Methods', True)
        icon_visible(self._parent.ClientObj.MainWidget, 'Back', True)

        self.widget = qt.QWidget (self)
        #--self.widget.setPalette(self.cur_palette)

#        self.widget.setStyleSheet("QWidget { background-color: rgb (%s) }" \
#                            %self._parent.ClientObj.method_background_color.\
#                             replace(' ',',',2))

        self.setDisabled(False)
        self.widget.setObjectName('QQQ')
        self.widget.setStyleSheet("QWidget#QQQ { "
                                  "background-color: %s;}"
            % get_system_rgb(self, qt.QPalette.Base))
        #self.setStyleSheet("QScrollArea { "
        #                   "background-color: qlineargradient("
        #                   "x1: 0, y1: 0, x2: 0, y2: 1, "
        #                   "stop: 0 %(start)s, stop: 0.7 %(start)s, "
        #                   "stop: 0.9 %(end)s, stop: 1 %(end)s);}"%
        #                   {'start':get_system_rgb(self, qt.QPalette.Base),
        #                    'end':get_system_rgb(self, qt.QPalette.Window),
        #                    })

        self.button_list = []
        self.layout = qt.QVBoxLayout(self.widget)
        self.layout.setAlignment(qt.Qt.AlignTop | qt.Qt.AlignHCenter)
#        self.layout.setContentsMargins(28,28,28,0)
        self.layout.setContentsMargins(2,28,2,0)
        self.layout.setSpacing(5)

        if not icons:
            icons = []

        width_list = []
        for num_step in range(len(steps)):
            self.button_list.append(StepLabel(steps[num_step], self))

            # collect parameters object
            self.button_list[num_step].clicked.connect(self.collect_object \
                                                      (method_name, num_step))
            # call function (or check parameters)
            self.button_list[num_step].clicked.connect(self.calling_method \
                                                      (method_name, num_step))
#            self.button_list[num_step].clicked.connect \
#                            (self.check_step(method_name, num_step))

            # calculate button width
            fmn = qt.QFontMetrics(qt.QFont('',-1,qt.QFont.Normal))
            normal_width = fmn.width(self.button_list[num_step].text())
            fmb = qt.QFontMetrics(qt.QFont('',-1,qt.QFont.Bold))
            bold_width = fmb.width(self.button_list[num_step].text())

            diff = bold_width - normal_width + 6
#            self.button_list[num_step].setFixedWidth \
#                        (self.button_list[num_step].sizeHint().width() + diff)

            width_list.append(self.button_list[num_step].sizeHint().width() \
                              + diff)
            self.layout.addWidget(self.button_list[num_step])

        if width_list:
            width_list.sort()
            max_width = width_list.pop()
        else:
            max_width = 0
        for num_step in range(len(steps)):
            self.button_list[num_step].setFixedWidth(max_width)
            

        # set bold button
        self.changed_step(self._parent.ClientObj.param_objects \
                          [method_name]['step'])

#        self.layout.addItem(qt.QSpacerItem(100, 100, \
#                    qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding))

        self.setWidget(self.widget)

        self.setWidgetResizable(True)

        self.setFixedWidth(self.sizeHint().width())# + \
#                           self.verticalScrollBar().sizeHint().width())

        if not self.isVisible():
            self.show()

    # create helper signals
    collect = qt.Signal()
    calling = qt.Signal()

    def collect_object(self, method_name, set_step = None):
        def wrapper():
            self.setDisabled(True)
            if hasattr (self, 'check_step_thread'):
                if self.check_step_thread.isRunning():
                    _print ('check_step_thread is running')
                    self.setEnabled(True)
                    return 1
            change_step = set_step if set_step else 0
            if self._parent.ClientObj.param_objects[method_name]['step'] > \
                                                                change_step:
#                self.setEnabled(True)
                return

            self.collect.connect(self._parent.ClientObj.MainWidget.\
                            MainFrameWgt.collect_object())
                            
            self.collect.emit()
            self.collect.disconnect()
        return wrapper

    def calling_method(self, method_name, set_step = None):
        def wrapper():
            if hasattr (self, 'check_step_thread'):
                if self.check_step_thread.isRunning():
                    self.setEnabled(True)
                    _print ('check_step_thread is running')
                    return 1

            change_step = set_step if set_step else 0
            if self._parent.ClientObj.param_objects[method_name]['step'] > \
                                                                change_step:
                self.check_step(method_name, set_step)
#                self.setEnabled(True)
                return
            self.calling.connect(self._parent.ClientObj.MainWidget.\
                          MainFrameWgt.calling(True, from_left_frame = True))
            self.calling.emit()
            self.calling.disconnect()
            self.check_step(method_name, set_step)
        return wrapper

    def check_step(self, method_name, set_step = None):
#        def wrapper():
            # Call server method
            if hasattr (self, 'check_step_thread'):
                if self.check_step_thread.isRunning():
                    _print ('check_step_thread is running')
                    self.setEnabled(True)
                    return 1

            self.step = set_step if set_step else 0

            self._parent.ClientObj.method_name = method_name
            self._parent.ClientObj.sid = \
                                get_sid(self._parent.ClientObj.client)

            expert = None
            if self._parent.ClientObj.MainWidget.MainFrameWgt. \
                                                            isBrief(self.step):
                num = None
                brief = True
                expert = True
            else:
                brief = False
                num = self.step

            view_params = get_view_params(self._parent.ClientObj.client, \
                                   str(method_name + '_view'), step = num, \
                                   expert = expert, brief = brief)
            self.check_step_thread = ClientServiceThread( \
                                        self._parent.ClientObj,\
                                        str(method_name + '_view'), \
                                        int(self._parent.ClientObj.sid), \
                                        view_params)
            self.check_step_thread.signal.connect(self.check_step_after)
            self.check_step_thread.start()
#        return wrapper

    def check_step_after(self, view = None):
        method_name = self._parent.ClientObj.method_name
        if self._parent.ClientObj.param_objects[method_name]['error']:
            if self._parent.ClientObj.param_objects[method_name]['step'] < \
                                                                    self.step:
                text = _('Error at this step.')
                informative_text = _('Do you want to continue?')
                reply = show_question(self._parent, text, informative_text, \
                              not_move = True, title = _('Calculate Console'))

                if reply == qt.QMessageBox.No:
                    self.setEnabled(True)
                    return

        if not view:
            self.setEnabled(True)
            return
        # set bold for current step
        self.changed_step(self.step)
        self._parent.ClientObj.param_objects[method_name]['step'] = self.step
        self._parent.ClientObj.MainWidget.main_frame_view(view, method_name)
        self.setEnabled(True)

    def changed_step(self, step):
        if not hasattr (self, 'button_list'):
            return 1
        # set bold for current step
        for i in range(len(self.button_list)):
            if i == step:
                self.button_list[i].text()
                self.button_list[i].setBold(True)
            else:
                self.button_list[i].setBold(False)

    def hideEvent (self, event):
        if hasattr (self, 'onActivated_thread'):
            if self.onActivated_thread.isRunning():
                self.onActivated_thread.close()
                self.onActivated_thread.wait()

        if hasattr (self, 'send_password_thread'):
            if self.check_step_thread.isRunning():
                self.check_step_thread.close()
                self.check_step_thread.wait()
        event.accept()
