#-*- 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 __future__ import print_function
from __future__ import absolute_import
from calculate.consolegui import qt

DEBUG_LEVEL = 0

def debug(level, *args):
    if level <= DEBUG_LEVEL:
        for s in args:
            print(s, end=' ')
        print()
import calculate.contrib
from urllib.error import URLError
from suds import MethodNotFound
import re


from calculate.lib.utils.colortext.converter import XmlConverter
from calculate.lib.utils.colortext.output import SpanCssOutput
from calculate.lib.utils.tools import imap_regexp
from .utils import switch, create_obj
from .more import WorkPalette, ParameterWindow, get_system_rgb

from .more import get_sid, ClientServiceThread, show_msg, TaskWidget, ErrorWgt,\
                 ResultLayout, get_view_params, get_icon, dpivalue
from .more import LabelWordWrap as Label
from .SelectTable import SelectedTableWidget

class LabelWordWrap(Label):
    def __init__(self, name, parent=None, mono=False, margin_top=0):
        Label.__init__(self, name, parent, mono, margin_top)
        # set text selectable
        self.setTextInteractionFlags(self.textInteractionFlags() | \
                                     qt.Qt.TextSelectableByMouse)

class PlusButton(qt.QPushButton):
    def __init__(self, parent, ClientObj, method, disable_method=None):
        super().__init__(parent)
        icon = get_icon('list-add')
        if not icon.isNull():
            self.setIcon(icon)
        else:
            self.setText('+')
        self._parent = parent
        self.ClientObj = ClientObj
        self.method = method
        self.setFixedSize(30, 30)
        if disable_method:
            self.clicked.connect(disable_method)
        self.clicked.connect(self.call_method)

    def call_method(self):
        # Call server method
        if hasattr (self, 'get_Frame_thread'):
            if self.get_Frame_thread.isRunning():
                return 1
        sid = int(self.ClientObj.sid)
        view_params = get_view_params(self.ClientObj.client, \
                           self.method + '_view')
        self.get_Frame_thread = ClientServiceThread(self.ClientObj,\
                                self.method + '_view', sid, view_params)
        self.get_Frame_thread.signal.connect(self.after_call)
        self.get_Frame_thread.start()

    def after_call(self, view):
        if self.method in self.ClientObj.method_names:
            view_method = self._parent.ClientObj.method_names[self.method]
        else:
            view_method = self.method
        self._parent.ClientObj._parent.setWindowTitle(view_method +
                    ' - ' + self.ClientObj.Name)
        self._parent._parent.main_frame_view(view, self.method)

class MainFrameRes(qt.QWidget):
    valSignal = qt.Signal()
    def __init__(self, parent, ClientObj, method_name, meth_result,
                 change_offset=False):
        super().__init__(parent)
        self._parent = parent
        self.ClientObj = ClientObj
        self.method_name = method_name
        self.meth_result = meth_result
        self.client = ClientObj.client
        self.cur_pid = 0
        self.change_offset = change_offset
        self.show_last = True
        self.max_val = None
        self.buttons = []

        if self.meth_result.type == "pid":
            self.cur_pid = self.meth_result.message

        self.work_layout = ResultLayout(self)
        self.work_layout.kill_process_button.clicked.connect \
                                            (self.kill_process(self.cur_pid))

        self.progress_list = []
        self.task_list = []

        self._parent.methodname_wgt.show()
        self._parent.control_button.show()
        #DEBUG    
        # self._parent.control_button.del_button()
        if self.method_name in self.ClientObj.method_names:
            self._parent.methodname_wgt.setMethodName \
                    (self.ClientObj.method_names[self.method_name])
        else:
            self._parent.methodname_wgt.setMethodName(method_name)
        parent.main_frame.viewport().setObjectName('main_frame')
        #parent.main_frame.viewport().setStyleSheet("#main_frame "
        #                                    "{background-color: #FFFFFF;}")
        #                                    #"{background-color: #E4E1E0;}")
        #self.setObjectName("Frame_Res")
        #self.setStyleSheet("#Frame_Res {background-color: %s;}"% get_system_rgb(self, ParameterWindow))
        #self.setStyleSheet("#Frame_Res {background-color: green;}")
#                           "QWidget {border: 1px solid red;}")

        self.timer = qt.QTimer(self)
        self.timer.timeout.connect(self.show_bottom)
        self.timer.start(100)
        self.valSignal.connect(self.show_bottom)


    def initUI(self):
        #self.setSizePolicy(qt.QSizePolicy.Minimum,qt.QSizePolicy.Minimum)
        self.updateGeometry()

    def show_bottom(self):
        debug(20, "SHOW BOTTOM PAGE")
        max_val = self._parent.main_frame.verticalScrollBar().maximum()
        current_val = \
            self._parent.main_frame.verticalScrollBar().sliderPosition()

        if self.show_last:
            if current_val != max_val:
                if self.max_val != max_val:
                    self._parent.main_frame.verticalScrollBar(
                    ).setSliderPosition(max_val)
                else:
                    self.show_last = False
        else:
            if current_val == max_val:
                self.show_last = True
        self.max_val = max_val

################# API FUNCTION ###############################
    def show_view(self, view):
        pass

    def show_table(self, table, item):
        # method to display tables
        add_offset_flag = False

        if not table.body:
            table.body = [[]]
        self.show_normal(item)
        self.mytable = None

        if self.method_name in self.ClientObj.param_objects:
            if len(table.body[0]) >= self.ClientObj.count_row_res_table or \
                    self.ClientObj.param_objects[self.method_name]['offset']:

                if table.onClick and table.records != "0":
                    self.add_offset_buttons(len(table.body[0]),
                                            table.addAction,
                                            table.records)
                    add_offset_flag = True

        if table.addAction and not add_offset_flag:
            plus_but = PlusButton(self, self.ClientObj, table.addAction,
                                  self.disable_buttons)
            self.buttons.append(plus_but)
            self.work_layout._addWidget(plus_but)
        if table.onClick and table.body[0]:
            self.mytable = SelectedTableWidget(len(table.body[0]), \
                                               len(table.head[0]), self)
        if not self.mytable:
            if table.body:
                len_body = len(table.body[0])
            else:
                len_body = 0
            if table.head:
                len_head = len(table.head[0])
            else:
                len_head = 1
            if len_body:
                self.mytable = SelectedTableWidget(len_body, len_head, self,
                                                   readonly=True)
        if self.mytable:
            list_head = table.head[0]
            self.mytable.setHorizontalHeaderLabels(list_head)
            for line in range(len(table.body[0])):
                for i in range(len(table.body[0][line][0])):
                    tablewidgetitem = qt.QTableWidgetItem(
                        table.body[0][line][0][i])
                    self.mytable.setItem(line, i, tablewidgetitem)
            # set writeonly
            self.mytable.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)

            if table.onClick:
                self.mytable.itemClicked.connect(self.row_activate(table))

            self.mytable.setColor()
            minimum = qt.QSizePolicy.Minimum
            self.mytable.setSizePolicy(minimum, minimum)
            self.mytable.horizontalHeader().resizeSections(
                qt.QHeaderView.ResizeToContents)
            self.work_layout._addWidget(self.mytable)
            self.ClientObj.app.processEvents()
            self.mytable.resizeRowsToContents()
            self.mytable.resizeColumnsToContents()

        self.initUI()

    def row_activate(self, table):
        def wrapper(item):
            param_object = create_obj(self.client, table.onClick)
            for field in table.fields.string:
                if field:
                    if ":" in field:
                        field, op, value = field.partition(":")
                    else:
                        value = None
                    if hasattr (param_object, field):
                        if value:
                            param_object[field] = value
                        else:
                            param_object[field] = self.mytable.item(item.row(),0).\
                                              text()
            #print param_object, table.step
            param_object.CheckOnly = True
            # Calling method
            sid = int(self.ClientObj.sid)
            self.client.service[0][table.onClick](sid, param_object)

            # Calling View
            try:
                self.client.service.clear_pid_cache(sid, self.cur_pid)
            except:
                pass
            try:
                view_params = get_view_params(self.client,
                                       table.onClick + '_view', step = 0) #int(table.step) if table.step else 0)
                view = self.client.service[0][table.onClick + '_view'](
                    sid, view_params)
            except MethodNotFound as e:
                _print(e)
                return
            if table.onClick in self._parent.ClientObj.method_names:
                view_method = self._parent.ClientObj.method_names \
                                                        [table.onClick]
            else:
                view_method = table.onClick
            self._parent.ClientObj._parent.setWindowTitle(view_method + \
                        ' - ' + self.ClientObj.Name)
            #self.ClientObj.param_objects[self.method_name]['offset'] = 0
            self._parent.main_frame_view(
                view, table.onClick,
                new_step=table.step if table.step else None)
        return wrapper

    def disable_buttons(self):
        debug(11, "DISABLE", self.buttons)
        for button in self.buttons:
            button.setDisabled(True)
        self.timer.stop()

    def add_offset_buttons(self, len_body, addAction, records):
        offset_buttons = qt.QWidget()
        layout = qt.QHBoxLayout(offset_buttons)
        layout.setAlignment(qt.Qt.AlignLeft)

        offset = self.ClientObj.param_objects[self.method_name]['offset']
        count_records = int(self.ClientObj.count_row_res_table)
        debug(15, "DATA:", records, offset, count_records)
        records = int(records) or 0
        if records:
            if offset + count_records >= records:
                last = True
            else:
                last = False
        else:
            if len_body < self.ClientObj.count_row_res_table:
                last = True
            else:
                last = False


        begin_offset = qt.QPushButton(offset_buttons)
        begin_offset.setIcon(get_icon('go-first'))
        begin_offset.setToolTip('First page')
        begin_offset.clicked.connect(self.disable_buttons)
        begin_offset.clicked.connect(self.call_method_with_offset(0, True))
        begin_offset.setFixedSize(30, 30)
        self.buttons.append(begin_offset)

        layout.addWidget(begin_offset)

        minus_offset = qt.QPushButton(offset_buttons)
        minus_offset.setIcon(get_icon('go-previous'))
        minus_offset.setToolTip('Previous page')
        minus_offset.clicked.connect(self.disable_buttons)
        minus_offset.clicked.connect(self.call_method_with_offset(
            -count_records))
        minus_offset.setFixedSize(30, 30)
        layout.addWidget(minus_offset)
        self.buttons.append(minus_offset)

        if not offset:
            minus_offset.setDisabled(True)
            begin_offset.setDisabled(True)


        plus_offset = qt.QPushButton(offset_buttons)
        plus_offset.setIcon(get_icon('go-next'))
        plus_offset.setToolTip('Next page')
        plus_offset.clicked.connect(self.disable_buttons)
        plus_offset.clicked.connect(self.call_method_with_offset(
            count_records))
        plus_offset.setFixedSize(30, 30)
        layout.addWidget(plus_offset)
        self.buttons.append(plus_offset)

        last_offset = qt.QPushButton(offset_buttons)
        last_offset.setIcon(get_icon('go-last'))
        last_offset.setToolTip('Last page')
        last_offset.clicked.connect(self.disable_buttons)
        last_offset.clicked.connect(self.call_method_with_offset(
            0, False, records - count_records))
        last_offset.setFixedSize(30, 30)
        layout.addWidget(last_offset)
        self.buttons.append(last_offset)

        if last or not records:
            last_offset.setDisabled(True)
        if last:
            plus_offset.setDisabled(True)

        if addAction:
            plus_but = PlusButton(self, self.ClientObj, addAction,
                                  self.disable_buttons)
            self.buttons.append(plus_but)
            layout.addWidget(plus_but)

        self.work_layout._addWidget(offset_buttons)

    def call_method_with_offset(self, offset, begin=False, reset=None):
        def wrapper():
            debug(10, "CHANGE OFFSET FOR %s to %d" % (
                self.method_name, offset))
            if begin:
                self.ClientObj.param_objects[self.method_name]['offset'] = 0
            elif reset is not None:
                self.ClientObj.param_objects[self.method_name]['offset'] = \
                    reset
            else:
                self.ClientObj.param_objects[self.method_name]['offset'] += offset
                if self.ClientObj.param_objects[self.method_name]['offset'] < 0:
                    self.ClientObj.param_objects[self.method_name]['offset'] = 0

            # Calling View
            debug(10, "CALL VIEW", self.method_name)
            sid = int(self.ClientObj.sid)
            try:
                view_params = get_view_params(self.client,
                                       self.method_name + '_view', step = None)
                view = self.client.service[0][self.method_name + '_view'] \
                                                    (sid, view_params)
            except MethodNotFound:
                return
            #if self._parent.ClientObj.method_names.has_key(self.method_name):
            #    view_method = self._parent.ClientObj.method_names \
            #                                            [self.method_name]
            #else:
            view_method = self.method_name
            self._parent.ClientObj._parent.setWindowTitle(view_method + \
                        ' - ' + self.ClientObj.Name)
            self._parent.main_frame_view(view, view_method, change_offset=True)
        return wrapper

    def show_message(self, message, mono=False, space=0):
        message = self.processTags(message)
        # add normal message label
        lbl_temp = LabelWordWrap(message, self, mono=mono, margin_top=space)
        if mono:
            lbl_temp.setMinimumHeight(lbl_temp.minimumSizeHint().height())
            lbl_temp.setMaximumHeight(lbl_temp.sizeHint().height())
        else:
            lbl_temp.setMinimumHeight(lbl_temp.minimumSizeHint().height())
            lbl_temp.setMaximumHeight(lbl_temp.sizeHint().height())
        self.work_layout._addWidget(lbl_temp)
        self.initUI()
        return lbl_temp
        #self._parent.main_frame.verticalScrollBar().setSliderPosition \
        #    (self._parent.main_frame.verticalScrollBar().maximum())

    def show_normal(self, item, mono=False):
        if not hasattr(item, 'message'):
            return
        if item.message:
            self.show_message(item.message, mono)
            if not mono:
                if self.progress_list:
                    self.progress_list[-1].hide()
                    self.add_Progress()

    def show_error(self, message):
        # add error message label
        self.set_result_task(True)
        if self.progress_list:
            self.progress_list[len(self.progress_list)-1].hide()
        if message:
            message = self.processTags(message)
            lbl_temp = ErrorWgt(message, self)
            lbl_temp.set_error()
            lbl_temp.setMinimumHeight(lbl_temp.minimumSizeHint().height())
            lbl_temp.setMaximumHeight(lbl_temp.minimumSizeHint().height())
            #lbl_temp.setMinimumHeight(lbl_temp.sizeHint().height())
            self.work_layout._addWidget(lbl_temp)

        self.initUI()

    def show_warning(self, item):
        # add warning message label
        if item.message:
            item.message = self.processTags(item.message)
            lbl_temp = ErrorWgt(item.message, self)
            lbl_temp.set_warning()
            lbl_temp.setMinimumHeight(lbl_temp.minimumSizeHint().height())
            lbl_temp.setMaximumHeight(lbl_temp.minimumSizeHint().height())
            self.work_layout._addWidget(lbl_temp)
        self.initUI()

    def show_group(self, item, *args):
        pass

    def show_result(self, result):
        # add normal message label
        lbl_temp = LabelWordWrap(result.message, self)

        lbl_temp.setMinimumHeight(lbl_temp.sizeHint().height())
        self.work_layout._addWidget(lbl_temp)

        self.initUI()

    def processTags(self, s):
        xc = XmlConverter(SpanCssOutput(palette=WorkPalette()))
        return xc.transform(s)

    def cleanTags(self, s):
        xc = XmlConverter()
        return xc.transform(s)

    def startTask(self, item):
        if self.progress_list:
            self.progress_list[-1].hide()
        task_widget = TaskWidget(self.processTags(item.message),
                                 self, clean_text=self.cleanTags(item.message))

        self.task_list.append(task_widget)
        self.work_layout._addWidget(task_widget)
        self.add_Progress()
        self.initUI()

    def endTask(self, item, set_res = True):
        if self.progress_list:
            self.progress_list[-1].hide()
        message = item.message if item.message else ''
        if set_res:
            if message == "skip":
                self.set_result_task(skip=True)
            elif hasattr(item,"result") and not item.result is None:
                self.set_result_task(not item.result)
            else:
                self.set_result_task()
        if message and message != "skip":
            message = self.processTags(message)
            lbl_temp = LabelWordWrap(message, self)

            lbl_temp.setMinimumHeight(lbl_temp.sizeHint().height())
            self.work_layout._addWidget(lbl_temp)
        self.initUI()

    def set_result_task(self, error=False, skip=False):
        if not len(self.task_list):
            return
        if skip:
            self.task_list[len(self.task_list) - 1].set_skip()
        elif error:
            self.task_list[len(self.task_list) - 1].set_error()
        else:
            self.task_list[len(self.task_list) - 1].set_ok()

    def beginFrame(self, item):
        pass

    def endFrame(self, item):
        if self.progress_list:
            self.progress_list[len(self.progress_list)-1].hide()
        self.endTask(item)

        self.initUI()
        self.work_layout.hide_kill_button()
        self.closeDialogs()
        self.close_all_thread()

        if self.change_offset:
            self._parent.delete_MainFrameWgt()
            self._parent.MainFrameWgt = self
            self._parent.main_frame.setWidget (self._parent.MainFrameWgt)
            self._parent.main_frame.setWidgetResizable(True)
            self._parent.methodname_wgt.show()
            self._parent.control_button.show()

        #if hasattr (self, "mytable"):
        #    if not self.mytable.readonly:
        #        self.initUI()
        #        return 0

        #self._parent.control_button.add_clear_cache_button(self.cur_pid)
        #self.initUI()
        # TODO: возможно здесь не нужне return 1
        self._parent.control_button.add_clear_cache_button(self.cur_pid)
        self.initUI()
        return 0

#    def clear_pid_cache(self):
#        self.clear_proc_cache_button.setDisabled(True)
#        sid = int(self.ClientObj.sid)
#        res = self.client.service.clear_pid_cache(sid, self.cur_pid)
#        if res:
#            _print (_('Error closing the process'))
#        self._parent.back()

    def startGroup(self, item):
        if not hasattr(item, 'message'):
            return
        if item.message:
            item.message = self.processTags(item.message)
            # add normal message label
            lbl_temp = LabelWordWrap("<b>%s</b>"%item.message, self)
            lbl_temp.setMinimumHeight(lbl_temp.minimumSizeHint().height())
            lbl_temp.setMaximumHeight(lbl_temp.sizeHint().height())

            self.work_layout._addWidget(lbl_temp)
            self.initUI()
            #self._parent.main_frame.verticalScrollBar().setSliderPosition \
            #    (self._parent.main_frame.verticalScrollBar().maximum())

    def endGroup(self, item):
        pass

    def kill_process(self, pid):
        def wrapper():
            sid = int(self.ClientObj.sid)

            self.closeDialogs()
            # Call server method
            if hasattr (self, 'kill_process_thread'):
                if self.kill_process_thread.isRunning():
                    return 1
            self.kill_process_thread = ClientServiceThread(self.ClientObj,\
                                    'pid_kill', pid, sid)
            self.kill_process_thread.signal.connect(self.kill_process_after)
            self.kill_process_thread.start()
        return wrapper

    def kill_process_after(self, result):
        if result in [0,2]:
            return 0
        elif result == -1:
            msg = _("Certificate not found in the server!")
        elif result == -2:
            msg = _("Session not matching your certificate!")
        elif result == 1:
            msg = _("Failed to kill the process!")
        else:
            msg = 'error'

        show_msg(msg)

###############################################################################

    def analysis(self, meth_result):
            """ analysis of the bounced message method """
    #    for mess in meth_result:
            self.ClientObj.app.processEvents()
            mess = meth_result
            if mess.type == 'pid':
                self.get_messages(self.ClientObj.sid, mess.message)
            if mess.type == 'error':
                try:
                    self.show_error(self, mess.message)
                except:
                    pass
            if mess.type == 'warning':
                try:
                    self.show_warning(self, mess)
                except:
                    pass

    def get_message(self, item, sid, pid):
        try:
            if item.type == "error" and item.message == "403 Forbidden":
                return 0
            if self.cur_pid != pid:
                return 1
        except:
            return 1
        """ get one message by its type """
        if not hasattr(item,"type"):
            return 1
        for case in switch(item.type):
            if case('normal'):
                self.show_normal(item)
                return 1
            if case('pre'):
                self.show_normal(item,mono=True)
                return 1
            if case('plain'):
                self.show_normal(item)
                return 1
            if case('progress'):
                self.get_Progress(sid, pid, item.id)
                return 1
            if case('error'):
    #            for i in range(20):
                self.show_error(item.message)
                if item.message == "403 Forbidden":
    #             show_msg(item.message, 'Access Denied')
                    return 0
                return 1
            if case('warning'):
                self.show_warning(item)
                return 1
            if case('table'):
                self.get_Table(sid, pid, item)
                return 1
            if case('group'):
                self.show_group(item)
                return 1
            if case('question'):
                self.send_Message(sid, pid, item)
                return 1
            if case('confirm'):
                self.send_Confirm(sid, pid, item)
                return 1
            if case('choice'):
                self.send_Choice(sid, pid, item)
                return 1
            if case('password'):
                self.send_Password(sid, pid, item)
                return 1
            if case('startTask'):
                self.startTask(item)
                return 1
            if case('taskNumber'):
#                self.startTask(item)
                return 1
            if case('endTask'):
                self.endTask(item)
                return 1
            if case('beginFrame'):
                self.beginFrame(item)
                return 1
            if case('endFrame'):
                self.endFrame(item)
                self.resize(self.sizeHint())
                return 0
            if case('startGroup'):
                self.startGroup(item)
                return 1
            if case('endGroup'):
                self.endGroup(item)
                return 1
            if case(): # default, could also just omit condition or 'if True'
                return 1

    def get_messages(self, sid, pid):
        """ get frame in a separate thread """
        #import threading
        #thread_messages = threading.Thread(target=self.get_Frame,\
        #                args = (sid, pid))
        #thread_messages.start()
        self.get_Frame(sid, pid)

    def get_Frame(self, sid, pid, def_end_frame = 1):
        """ get all messages, until type is not endFrame (or Error) """
        self.not_end_frame = def_end_frame

        if self.not_end_frame:
            # Call server method
            if hasattr (self, 'get_Frame_thread'):
                if self.get_Frame_thread.isRunning():
                    self.get_Frame_thread.wait()
            self.get_Frame_thread = ClientServiceThread(self.ClientObj,\
                           'get_frame', sid, pid, "gui",  return_except = True, \
                           through_object = (sid, pid))
            self.get_Frame_thread.signal_extended.connect(self.get_Frame_cycle)
            self.get_Frame_thread.start()

    def get_errno(self, exception):
        """
        Exception container with URLError
        """
        from socket import error as socket_error
        try:
            if (exception.args and type(exception.args[0]) == URLError and
                exception.args[0].args and
                type(exception.args[0].args[0]) == socket_error):
                return exception.args[0].args[0].errno
            if (exception.args[0].args and
                type(exception.args[0].args[0]) == socket_error):
                return exception.args[0].errno
        except:
            return None
        return None

    def get_Frame_cycle(self, current_frame, through_object):
        if type(current_frame) == Exception:
            _print (_("Failed to get a frame from the server."))
            #show_msg(_("Failed to get a frame from the server.") +'\n'+ \
            #         _('Try resfeshing this page later.'),'get frame error')
        sid, pid = through_object
        if current_frame in [None, [], ""]:
            try:
                if  self.cur_pid != pid:
                    return 1
            except:
                return 1
        elif not isinstance(current_frame,Exception):
            self.get_Frame_after(current_frame, sid, pid)
        if self.not_end_frame:
            # Call server method
            if hasattr (self, 'get_Frame_thread'):
                if self.get_Frame_thread.isRunning():
                    self.get_Frame_thread.wait()
            if self.ClientObj.host_name in ('localhost','127.0.0.1'):
                if self.get_errno(current_frame) == 111:
                    sleeptime = 5
                else:
                    sleeptime = int(self.ClientObj.client.frame_period)
            else:
                sleeptime = int(self.ClientObj.client.frame_period)
            self.get_Frame_thread = ClientServiceThread(self.ClientObj,
                          'get_frame', sid, pid, "gui",return_except = True,
                          sleeptime = sleeptime,
                          through_object = (sid, pid))
            self.get_Frame_thread.signal_extended.connect(self.get_Frame_cycle)
            self.get_Frame_thread.start()

    def get_Frame_after(self, current_frame, sid, pid):
        for item in range(len(current_frame[0])):
            self.not_end_frame = self.get_message(current_frame[0][item],
                                                                sid, pid)
            self.valSignal.emit()
            try:
                if  self.cur_pid != pid:
                    return 1
            except:
                return 1
            if len (current_frame[0]) > 3:
                if not item % 10:
                    self.ClientObj.app.processEvents()
            else:
                self.ClientObj.app.processEvents()
                self.valSignal.emit()

    def get_entire_frame(self, pid = None):
        """ get entire frame, from beginning (if client disconnected) """
        self.ClientObj.app.processEvents()
        sid = get_sid(self.ClientObj.client)
        if not pid:
            try:
                list_pid = self.ClientObj.client.service.list_pid(sid = sid)
            except URLError as e:
                _print ('get_entire_frame in MainFrameResult Exception')
                show_msg (e, _("Not connected!"))
                return 1
        else:
            list_pid = {}
            list_pid[0] = [pid]

        if list_pid[0] == [0]:
            return 0
        pid = list_pid[0][0]

        # Call server method
        if hasattr (self, 'get_Frame_thread'):
            if self.get_Frame_thread.isRunning():
                self.get_Frame_thread.wait()
        self.get_Frame_thread = ClientServiceThread(self.ClientObj,\
                       'get_entire_frame', sid, pid, return_except = True, \
                       through_object = (sid, pid))
        self.get_Frame_thread.signal_extended.connect \
                                                (self.get_entire_frame_after)
        self.get_Frame_thread.start()

    def get_entire_frame_after(self, current_frame, through_object):
        if type(current_frame) == Exception:
            _print (_('Failed to get the complete frame from the server.'))
#            show_msg(_("Failed to get a frame from the server.") +'\n'+ \
#                     _('Try resfeshing this page later.'),'get frame error')
            return 1
        sid, pid = through_object
        end_frame = 1
        if not current_frame in [None, [], ""]:
#                for i in range (10):
            for item in range(len(current_frame[0])):
                end_frame = self.get_message(current_frame[0][item], sid, pid)
                self.valSignal.emit()
                try:
                    if self.cur_pid != pid:
                        return 1
                except:
                    return 1
                if len (current_frame[0]) > 3:
                    if not item % 10:
                        self.ClientObj.app.processEvents()
                else:
                    self.ClientObj.app.processEvents()

        self.get_Frame(sid, pid, def_end_frame = end_frame)

    def add_Progress(self):
        progressBar = qt.QProgressBar()
        progressBar.setMinimumHeight(progressBar.sizeHint().height())
        progressBar.setTextVisible(True)
        self.progress_list.append(progressBar)
        self.work_layout._addWidget(progressBar)

        progressBar.setMinimum(0)
        progressBar.setMaximum(0)
        self.initUI()
        return progressBar

    def get_Progress(self, sid, pid, id):
        """ get progress for the current job """
        #if self.progress_list and self.progress_list[-1].isVisible():
        if self.progress_list:
            progressBar = self.progress_list[-1]
        else:
            progressBar = self.add_Progress()
        #else:
        #    progressBar = self.add_Progress()
        #if self.progress_list:
        #    self.progress_list[-1].hide()

        temp_progress = -1
        # Call server method
        if hasattr (self, 'get_Progress_thread'):
            if self.get_Progress_thread.isRunning():
                self.get_Progress_thread.wait()
        self.get_Progress_thread = ClientServiceThread(self.ClientObj,\
                       'get_progress', sid, pid, id, return_except = True, \
                       through_object = (sid, pid, id, temp_progress, \
                       progressBar))
        self.get_Progress_thread.signal_extended.connect \
                                                (self.get_Progress_cycle)
        self.get_Progress_thread.start()

    def get_Progress_cycle(self, returnProgr, through_object):
        sid, pid, id, temp_progress, progressBar = through_object
        def nextProgress():
            if hasattr (self, 'get_Progress_thread'):
                if self.get_Progress_thread.isRunning():
                    self.get_Progress_thread.wait()
            self.get_Progress_thread = ClientServiceThread(self.ClientObj,\
                           'get_progress', sid, pid, id, return_except = True,\
                           sleeptime = 1, through_object = \
                           (sid, pid, id, temp_progress, progressBar))
            self.get_Progress_thread.signal_extended.connect \
                                                    (self.get_Progress_cycle)
            self.get_Progress_thread.start()

        if type(returnProgr) == Exception:
            _print (_('Failed to get the progress status from the server'))
#            show_msg(_('Failed to get the progress status from the server') + \
#                    '\n'+ \
#                   _('Try resfeshing this page later.'),'get progress error')
            nextProgress()
            return 1
########################################
        try:
            percent = returnProgr.percent
        except AttributeError:
            if type(returnProgr) in [str,unicode]:
                _print ('Server return:', returnProgr)
            percent = temp_progress
        if percent <= 100 and percent >= 0 :
            if temp_progress != percent:
                if percent:
#                    progressBar.setProperty("value", 100)
                    progressBar.setMaximum(100)
#                    progressBar.setValue(percent)
                    self.set_progress_value(progressBar, returnProgr)
                if percent == 100:
                    return 0
                self.initUI()
                temp_progress = percent
            try:
                if  self.cur_pid != pid:
                    return 1
            except:
                return 1

            # Call server method
            nextProgress()
        if percent < 0:
            progressBar.setMaximum(100)
            returnProgr.percent = 0 - percent
            self.set_progress_value(progressBar, returnProgr)
            self.ClientObj.app.processEvents()
            self.initUI()

    def set_progress_value(self, progressBar, returnProgr):
        if returnProgr.long_message:
            if progressBar.fontMetrics().width(returnProgr.long_message) + \
                                   progressBar.fontMetrics().width(' 000%') \
                                                        < progressBar.width():
                progressBar.setFormat('%s %d%%' %(returnProgr.long_message, \
                                                  returnProgr.percent))
                progressBar.setValue(returnProgr.percent)
                self.ClientObj.app.processEvents()
                return 0
        if returnProgr.short_message:
            progressBar.setFormat('%s %d%%' %(returnProgr.short_message, \
                                                  returnProgr.percent))
            progressBar.setValue(returnProgr.percent)
            self.ClientObj.app.processEvents()
            return 0
        progressBar.setFormat('%d%%' %returnProgr.percent)
        progressBar.setValue(returnProgr.percent)
        self.ClientObj.app.processEvents()

    def get_Table(self, sid, pid, item):
        try:
            table = self.ClientObj.client.service.get_table(sid, pid, item.id)
        except URLError:
            self.show_error('Error get table from server')
            return 1

        self.show_table(table, item)
        self.ClientObj.app.processEvents()
        # Resize table
        if self.mytable:
            h = self.mytable.horizontalHeader().height() + \
                2 * self.mytable.frameWidth()
            h += self.mytable.horizontalScrollBar().sizeHint().height()
            for row_in_table in range(self.mytable.rowCount()):
                h += self.mytable.rowHeight(row_in_table)
            self.mytable.setFixedHeight(h)

    def send_Confirm(self, sid, pid, item):
        """ send answer to the question """
        if self.progress_list:
            self.progress_list[-1].hide()
        self.message = ConfirmDialog(self, item, sid, pid)
        self._parent.control_button.set_confirmation(self.message)
        self.message.show()

    def send_Choice(self, sid, pid, item):
        """ send answer to the question """
        if self.progress_list:
            self.progress_list[-1].hide()
        self.message = ChoiceDialog(self, item, sid, pid)
        self._parent.control_button.set_confirmation(self.message)
        self.message.show()

    def send_Message(self, sid, pid, item):
        """ send answer to the question """
        self.message = MessageDialog(self, item, sid, pid)
        self.message.show()

    def send_Password(self, sid, pid, item):
        """ send password """
        self.passwd = MessageDialog(self, item, sid, pid, True)
        self.passwd.show()

    def close_all_thread(self):
        if hasattr (self, 'get_Frame_thread'):
            if self.get_Frame_thread.isRunning():
                self.get_Frame_thread.close()
                self.get_Frame_thread.wait()

        if hasattr (self, 'get_Progress_thread'):
            if self.get_Progress_thread.isRunning():
                self.get_Progress_thread.close()
                self.get_Progress_thread.wait()

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

    def closeDialogs(self):
        if hasattr(self, "message") and self.message:
            self.message.close()
            self.message = None
        if hasattr(self, "passwd") and self.passwd:
            self.passwd.close()
            self.passwd = None
        self._parent.control_button.close_confirmation()
        self._parent.control_button.close_break_button()

    def closeEvent(self, event):
        self.timer.stop()
        self.cur_pid = 'no'
        self.close_all_thread()
        self._parent.methodname_wgt._hide()
        self._parent.control_button._hide()
        self.closeDialogs()
        event.accept()


class MessageDialog(qt.QWidget):
    # answer to the server question
    def __init__(self, parent, item, sid, pid, isPassword = False):
        super().__init__()
        self._parent = parent
#        self.item = item
        self.sid = sid
        self.pid = pid
        self.setWindowTitle(self._parent.ClientObj._parent.windowTitle())
        self.layout = qt.QGridLayout(self)

        self.label = LabelWordWrap(item.message, self)

        self.pass_edit = qt.QLineEdit(self)
        self.layout.addWidget(self.label,0,0)
        self.layout.addWidget(self.pass_edit,0,1)

        x = 1
        if isPassword:
            self.pass_edit.setEchoMode(self.pass_edit.Password)
            if item.id == 2:
                if hasattr(self,'pass_edit2'):
                    self.pass_edit2 = qt.QLineEdit(self)
                    self.pass_edit2.setEchoMode(self.pass_edit2.Password)

                self.layout.addWidget(LabelWordWrap(_('Repeat'), self), x, 0)
                self.layout.addWidget(self.pass_edit2, x, 1)
                x += 1
                self.pass_edit.textChanged.connect(self.check_passwd)
                if hasattr(self,'pass_edit2'):
                    self.pass_edit2.textChanged.connect(self.check_passwd)

        self.send_button = qt.QPushButton(_('Send'), self)
        self.send_button.setShortcut(qt.QKeySequence(qt.Qt.Key_Return))
        self.send_button.clicked.connect(self.send_password)

        self.layout.addWidget(self.send_button,x,1)

        self.move(parent.ClientObj._parent.geometry().x() + \
                  parent.ClientObj._parent.geometry().width() / 2 \
                  - self.sizeHint().width() / 2, \
                  parent.ClientObj._parent.geometry().y() + \
                  parent.ClientObj._parent.geometry().height() / 2 \
                  - self.sizeHint().height() / 2)
        self.setWindowFlags (qt.Qt.WindowMinimizeButtonHint)

    def send_password(self):
        answer = self.pass_edit.text()
        if not hasattr(self,"pass_edit2") or \
            answer == self.pass_edit2.text():

            # Call server method
            if hasattr (self, 'send_password_thread'):
                if self.send_password_thread.isRunning():
                    return 1
            self.send_password_thread = ClientServiceThread(\
                            self._parent.ClientObj, 'send_message', self.sid, \
                            self.pid, answer, return_except = True)
            self.send_password_thread.signal.connect(self.send_password_after)
            self.send_password_thread.start()
        else:
            self.send_button.setDisabled(True)

    def send_password_after(self, result):
        if type(result) == Exception:
            show_msg(_('Failed to send the message (password) to the server'))
            self.close()
            return 1
        self._parent.show_result(result)
        self.close()

    def check_passwd(self):
        if self.pass_edit.text() != self.pass_edit2.text():
            self.send_button.setDisabled(True)
        else:
            self.send_button.setEnabled(True)


class ButtonDialog(qt.QWidget):
    button_size = 144

    def __init__(self, parent, item, sid, pid):
        super().__init__()
        self._parent = parent
        self.sid = sid
        self.pid = pid
        self.layout = qt.QHBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 4, 0)
        self.header_label = None

        minimum = qt.QSizePolicy.Fixed
        self.setSizePolicy(minimum, minimum)
        self.setFixedHeight(dpivalue(32))
        self.init(item)

    def init(self, item):
        pass

    def createButton(self, label, answer, shortcut=None):
        """
        Создать кнопку в диалоге
        """
        button = qt.QPushButton(label, self)
        if type(shortcut) in (list, tuple):
            action = qt.QAction(self)
            action.setShortcuts(map(qt.QKeySequence,
                                    shortcut))
            action.triggered.connect(button.animateClick)
            button.addAction(action)
        elif shortcut:
            button.setShortcut(qt.QKeySequence(shortcut))
        button.clicked.connect(self.send(answer, label))
        button.setFixedWidth(self.button_size)
        button.setFixedHeight(dpivalue(32))
        self.layout.addWidget(button)

    def send(self, answer, human_answer=None):
        # Call server method
        def wrapper():
            self._parent._parent.control_button.close_confirmation()
            if human_answer and self.header_label:
                self.header_label.setText(
                    self.header_label.text() + " " +
                    human_answer)
            if hasattr(self, 'send_password_thread'):
                if self.send_password_thread.isRunning():
                    return 1
            self.send_password_thread = ClientServiceThread( \
                self._parent.ClientObj, 'send_message', self.sid, \
                self.pid, answer, return_except=True)
            self.send_password_thread.signal.connect(self.send_after)
            self.send_password_thread.start()

        return wrapper

    def send_after(self, result):
        if type(result) == Exception:
            show_msg(_('Failed to send the message (password) to the server'))
            self.close()
            return 1
        #self._parent.show_result(result)
        self.close()


class ConfirmDialog(ButtonDialog):
    """
    Диалог подтверждения действия
    """
    def init(self, item):
        self._parent._parent.control_button.set_confirm_question(
            "<b>%s</b>" % item.message)
        self.createButton(_("Yes"), "yes", [qt.Qt.Key_Enter,
                                            qt.Qt.Key_Return])
        self.createButton(_("No"), "no", qt.Qt.Key_Escape)


class ChoiceDialog(ButtonDialog):
    """
    Диалог выбора ответа из нескольких
    """
    def init(self, item):
        message, answers = item.message.split('|')

        self._parent._parent.control_button.set_confirm_question(
            "<b>%s</b>" % message)

        reAnswer = re.compile("^(.*)\((.*)\)$")
        answers = imap_regexp(reAnswer, answers.split(','))

        for answer, label in answers:
            self.createButton(label, answer)
