class ShuffleWidget(QWidget):
    def __init__(self, window):
        QWidget.__init__(self)
        self.window = window
        self.timer = QtCore.QTimer()
        self.update_inputs_timer = QtCore.QTimer()
        self.waiting_timeout = 180
        self.timer.timeout.connect(self.tick)
        self.update_inputs_timer.timeout.connect(self.update_inputs)
        self.update_inputs_timer.start(15000)
        self.coinshuffle_fee_constant = 1000
        # This is for debug
        # self.coinshuffle_fee_constant = 1000

        # self.coinshuffle_amounts = [1e7, 1e6]
        # Use this in test mode
        self.coinshuffle_amounts = [1e5, 1e6, 1e7]
        self.shuffle_grid = QGridLayout()
        self.shuffle_grid.setSpacing(8)
        self.shuffle_grid.setColumnStretch(3, 1)

        self.coinshuffle_servers = ServersList()
        self.coinshuffle_inputs = InputAdressWidget(
            decimal_point=self.window.get_decimal_point)
        self.coinshuffle_changes = ChangeAdressWidget()
        self.coinshuffle_fresh_changes = QCheckBox(
            _('Show only fresh change addresses'))
        self.coinshuffle_outputs = OutputAdressWidget()
        self.coinshuffle_amount_radio = AmountSelect(
            self.coinshuffle_amounts,
            decimal_point=self.window.get_decimal_point)
        self.coinshuffle_fee = QLabel(
            _(
                self.window.format_amount_and_units(
                    self.coinshuffle_fee_constant)))
        self.coinshuffle_text_output = ConsoleOutput()
        self.coinshuffle_timer_output = QLabel()

        self.coinshuffle_inputs.currentIndexChanged.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_amount_radio.button_group.buttonClicked.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_fresh_changes.stateChanged.connect(
            lambda: self.coinshuffle_changes.update(
                self.window.wallet,
                fresh_only=self.coinshuffle_fresh_changes.isChecked()))

        self.coinshuffle_start_button = EnterButton(
            _("Shuffle"), lambda: self.start_coinshuffle_protocol())
        self.coinshuffle_cancel_button = EnterButton(
            _("Cancel"), lambda: self.cancel_coinshuffle_protocol())
        self.coinshuffle_start_button.setEnabled(False)
        self.coinshuffle_cancel_button.setEnabled(False)

        self.shuffle_grid.addWidget(QLabel(_('Shuffle server')), 1, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle input address')), 2, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle change address')), 3, 0)
        self.shuffle_grid.addWidget(QLabel(_('Shuffle output address')), 5, 0)
        self.shuffle_grid.addWidget(QLabel(_('Amount')), 6, 0)
        self.shuffle_grid.addWidget(QLabel(_('Fee')), 7, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_servers, 1, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_fresh_changes, 4, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs, 2, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_changes, 3, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_outputs, 5, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_amount_radio, 6, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_fee, 7, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_start_button, 8, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_cancel_button, 8, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_timer_output, 8, 2)
        self.shuffle_grid.addWidget(self.coinshuffle_text_output, 9, 0, 1, -1)

        vbox0 = QVBoxLayout()
        vbox0.addLayout(self.shuffle_grid)
        hbox = QHBoxLayout()
        hbox.addLayout(vbox0)
        vbox = QVBoxLayout(self)
        vbox.addLayout(hbox)
        vbox.addStretch(1)

    def update_inputs(self):
        if not self.coinshuffle_cancel_button.isEnabled():
            self.coinshuffle_inputs.update(self.window.wallet)
            self.coinshuffle_outputs.update(self.window.wallet)

    def tick(self):
        self.waiting_timeout -= 1
        if self.waiting_timeout > 0:
            self.coinshuffle_timer_output.setText("{} s to break".format(
                self.waiting_timeout))
        else:
            self.logger.send("Error: timeout waiting for another players")

    def set_coinshuffle_addrs(self):
        self.coinshuffle_servers.setItems()
        self.coinshufle_input_addrs = map(lambda x: x.get('address'),
                                          self.window.wallet.get_utxos())
        self.coinshuffle_outputs_addrs = map(lambda x: x.get('address'),
                                             self.window.wallet.get_utxos())
        self.coinshuffle_inputs.setItmes(self.window.wallet)
        self.coinshuffle_changes.setItems(self.window.wallet)
        self.coinshuffle_outputs.setItems(self.window.wallet)

    def check_sufficient_ammount(self):
        coin_amount = self.coinshuffle_inputs.get_input_value()
        shuffle_amount = self.coinshuffle_amount_radio.get_amount()
        fee = self.coinshuffle_fee_constant
        if shuffle_amount and fee:
            if coin_amount > (fee + shuffle_amount):
                self.coinshuffle_start_button.setEnabled(True)
            else:
                self.coinshuffle_start_button.setEnabled(False)
        else:
            self.coinshuffle_start_button.setEnabled(False)

    def enable_coinshuffle_settings(self):
        self.coinshuffle_servers.setEnabled(True)
        self.coinshuffle_start_button.setEnabled(True)
        self.coinshuffle_inputs.setEnabled(True)
        self.coinshuffle_changes.setEnabled(True)
        self.coinshuffle_outputs.setEnabled(True)
        self.coinshuffle_amount_radio.setEnabled(True)
        self.waiting_timeout = 180
        self.coinshuffle_timer_output.setText("")

    def disable_coinshuffle_settings(self):
        self.coinshuffle_servers.setEnabled(False)
        self.coinshuffle_start_button.setEnabled(False)
        self.coinshuffle_inputs.setEnabled(False)
        self.coinshuffle_changes.setEnabled(False)
        self.coinshuffle_outputs.setEnabled(False)
        self.coinshuffle_amount_radio.setEnabled(False)

    def process_protocol_messages(self, message):
        if message.startswith("Error"):
            self.pThread.join()
            self.coinshuffle_text_output.setTextColor(QColor('red'))
            self.coinshuffle_text_output.append(message)
            self.enable_coinshuffle_settings()
            self.coinshuffle_cancel_button.setEnabled(False)
            self.coinshuffle_inputs.update(self.window.wallet)
            self.coinshuffle_outputs.update(self.window.wallet)
            self.timer.stop()
        elif message[-17:] == "complete protocol":
            self.coinshuffle_text_output.append(message)
            self.pThread.done.set()
            tx = self.pThread.protocol.tx
            if tx:
                self.pThread.join()
            else:
                print("No tx: " + str(tx.raw))
            self.enable_coinshuffle_settings()
            self.coinshuffle_cancel_button.setEnabled(False)
            self.coinshuffle_inputs.update(self.window.wallet)
            self.coinshuffle_outputs.update(self.window.wallet)
        elif "begins" in message:
            self.timer.stop()
            self.coinshuffle_timer_output.setText("")
            self.waiting_timeout = 180
        else:
            header = message[:6]
            if header == 'Player':
                self.coinshuffle_text_output.setTextColor(QColor('green'))
            if header[:5] == 'Blame':
                self.coinshuffle_text_output.setTextColor(QColor('red'))
                if "insufficient" in message:
                    pass
                elif "wrong hash" in message:
                    pass
                else:
                    self.pThread.join()
                    self.enable_coinshuffle_settings()
                    self.coinshuffle_text_output.append(
                        str(self.pThread.isAlive()))
            self.coinshuffle_text_output.append(message)
            self.coinshuffle_text_output.setTextColor(QColor('black'))

    def start_coinshuffle_protocol(self):

        from .client import ProtocolThread
        from electroncash.bitcoin import (regenerate_key, deserialize_privkey)
        from .shuffle import ConsoleLogger
        parent = self.window.top_level_window()
        password = None
        while self.window.wallet.has_password():
            password = self.window.password_dialog(parent=parent)
            if password is None:
                # User cancelled password input
                return
            try:
                self.window.wallet.check_password(password)
                break
            except Exception as e:
                self.window.show_error(str(e), parent=parent)
                continue
        try:
            server_params = self.coinshuffle_servers.get_current_server()
            server = server_params['server']
            port = server_params['port']
            ssl = server_params.get('ssl', False)
        except:
            self.coinshuffle_text_output.setText(
                'Wrong server connection string')
            return
        input_address = self.coinshuffle_inputs.get_input_address()
        possible_change_address = self.coinshuffle_changes.get_change_address()
        if possible_change_address:
            change_address = possible_change_address
        else:
            change_address = self.coinshuffle_inputs.get_input_address_as_string(
            )
        output_address = self.coinshuffle_outputs.get_output_address()
        #disable inputs
        self.disable_coinshuffle_settings()
        self.coinshuffle_cancel_button.setEnabled(True)

        amount = self.coinshuffle_amount_radio.get_amount()
        fee = self.coinshuffle_fee_constant
        self.logger = ConsoleLogger()
        self.logger.logUpdater.connect(
            lambda x: self.process_protocol_messages(x))
        priv_key = self.window.wallet.export_private_key(
            input_address, password)
        pub_key = self.window.wallet.get_public_key(input_address)
        sk = regenerate_key(deserialize_privkey(priv_key)[1])
        self.pThread = ProtocolThread(server,
                                      port,
                                      self.window.network,
                                      amount,
                                      fee,
                                      sk,
                                      pub_key,
                                      output_address,
                                      change_address,
                                      logger=self.logger,
                                      ssl=ssl)
        self.pThread.start()
        self.timer.start(1000)

    def cancel_coinshuffle_protocol(self):
        if self.pThread.is_alive():
            self.pThread.join()
            while self.pThread.is_alive():
                time.sleep(0.1)
            self.coinshuffle_cancel_button.setEnabled(False)
            self.timer.stop()
            self.enable_coinshuffle_settings()
class ShuffleWidget(QWidget):
    def __init__(self, window):
        QWidget.__init__(self)
        self.window = window
        self.timer = QtCore.QTimer()
        self.update_inputs_timer = QtCore.QTimer()
        self.waiting_timeout = 180
        self.timer.timeout.connect(self.tick)
        self.update_inputs_timer.timeout.connect(self.update_inputs)
        self.update_inputs_timer.start(15000)
        self.coinshuffle_fee_constant = 1000
        self.bot_thread = None
        self.bot_limit_value = 1
        self.bot_maximum_value = 3
        self.bot_period_value = 1
        self.bot_stopper = False
        # This is for debug
        # self.coinshuffle_fee_constant = 10
        #
        # self.coinshuffle_amounts = [1e7, 1e6]
        # Use this in test mode
        self.coinshuffle_amounts = [1e5, 1e6, 1e7]
        self.shuffle_grid = QGridLayout()
        self.shuffle_grid.setSpacing(8)
        self.shuffle_grid.setColumnStretch(3, 1)

        self.coinshuffle_servers = ServersList()
        self.coinshuffle_enable_bot = QCheckBox(_('Use bot'))
        self.coinshuffle_inputs_label = QLabel(_('Shuffle input address '))
        self.coinshuffle_inputs_total_label = QLabel(
            _('Total amount in selected coins'))
        self.coinshuffle_inputs_total_output = QLabel()
        self.coinshuffle_changes = ChangeAdressWidget()
        self.coinshuffle_changes_label = QLabel(_('Shuffle change address'))
        self.coinshuffle_fresh_changes = QCheckBox(
            _('Show only fresh change addresses'))
        self.coinshuffle_use_external_output = QCheckBox(
            _('Use external output address'))
        self.coinshuffle_outputs = OutputAdressWidget()
        self.coinshuffle_outputs_label = QLabel(_('Shuffle output address'))
        self.coinshuffle_external_output = ExternalOutput(
            testnet=self.window.config.get("testnet", False))
        self.coinshuffle_amount_radio = AmountSelect(self.coinshuffle_amounts,
                                                     window=self.window)
        self.coinshuffle_fee = QLabel(
            _(
                self.window.format_amount_and_units(
                    self.coinshuffle_fee_constant)))
        self.coinshuffle_amount_label = QLabel(_('Amount'))
        self.coinshuffle_text_output = ConsoleOutput()
        self.coinshuffle_timer_output = QLabel()

        self.coinshuffle_inputs_list = InputAddressesWidget(
            decimal_point=self.window.get_decimal_point, parent=self.window)

        self.coinshuffle_bot_limit = QLineEdit()
        self.coinshuffle_bot_limit.setValidator(QIntValidator(1, 100))
        self.coinshuffle_bot_limit.setText(str(self.bot_limit_value))
        self.coinshuffle_bot_limit_label = QLabel(
            _('Minimal number of players in pool'))
        self.coinshuffle_bot_maximum = QLineEdit()
        self.coinshuffle_bot_maximum.setValidator(QIntValidator(1, 100))
        self.coinshuffle_bot_maximum.setText(str(self.bot_maximum_value))
        self.coinshuffle_bot_maximum_label = QLabel(
            _('Maximum players to support pool'))
        self.coinshuffle_bot_period = QLineEdit()
        self.coinshuffle_bot_period.setValidator(QIntValidator(1, 1000))
        self.coinshuffle_bot_period.setText(str(self.bot_period_value))
        self.coinshuffle_bot_period_label = QLabel(
            _('Lookup period in minutes'))

        self.coinshuffle_bot_start_button = EnterButton(
            _("Run bot"), lambda: self.start_bot())
        self.coinshuffle_bot_stop_button = EnterButton(
            _("Stop bot"), lambda: self.cancel_bot())
        self.coinshuffle_bot_start_button.setEnabled(True)
        self.coinshuffle_bot_stop_button.setEnabled(False)

        self.coinshuffle_bot_limit.hide()
        self.coinshuffle_bot_maximum.hide()
        self.coinshuffle_bot_period.hide()
        self.coinshuffle_bot_limit_label.hide()
        self.coinshuffle_bot_maximum_label.hide()
        self.coinshuffle_bot_period_label.hide()
        self.coinshuffle_bot_start_button.hide()
        self.coinshuffle_bot_stop_button.hide()

        self.coinshuffle_inputs_list.clicked.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_amount_radio.button_group.buttonClicked.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_fresh_changes.stateChanged.connect(
            lambda: self.coinshuffle_changes.update(
                self.window.wallet,
                fresh_only=self.coinshuffle_fresh_changes.isChecked()))
        self.coinshuffle_use_external_output.stateChanged.connect(
            lambda: self.coinshuffle_change_outputs(
                self.coinshuffle_use_external_output.isChecked()))
        self.coinshuffle_external_output.textChanged.connect(
            self.check_sufficient_ammount)
        self.coinshuffle_enable_bot.stateChanged.connect(self.switch_bot)

        self.coinshuffle_start_button = EnterButton(
            _("Shuffle"), lambda: self.start_coinshuffle_protocol())
        self.coinshuffle_cancel_button = EnterButton(
            _("Cancel"), lambda: self.cancel_coinshuffle_protocol())
        self.coinshuffle_start_button.setEnabled(False)
        self.coinshuffle_cancel_button.setEnabled(False)

        self.shuffle_grid.addWidget(QLabel(_('Shuffle server')), 1, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs_label, 2, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs_total_label, 3, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs_total_output, 3, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_changes_label, 4, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_outputs_label, 6, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_amount_label, 9, 0)
        self.shuffle_grid.addWidget(QLabel(_('Fee')), 10, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_servers, 1, 1, 1, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_enable_bot, 1, 2, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_fresh_changes, 5, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_use_external_output, 7, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_external_output, 8, 1, 1,
                                    -1)
        self.shuffle_grid.addWidget(self.coinshuffle_inputs_list, 2, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_changes, 4, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_outputs, 6, 1, 1, -1)
        self.shuffle_grid.addWidget(self.coinshuffle_amount_radio, 9, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_fee, 10, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_start_button, 11, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_cancel_button, 11, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_timer_output, 11, 2)
        self.shuffle_grid.addWidget(self.coinshuffle_text_output, 12, 0, 1, -1)

        self.shuffle_grid.addWidget(self.coinshuffle_bot_limit, 2, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_maximum, 4, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_period, 5, 1)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_limit_label, 2, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_maximum_label, 4, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_period_label, 5, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_start_button, 6, 0)
        self.shuffle_grid.addWidget(self.coinshuffle_bot_stop_button, 6, 1)

        self.shuffle_grid.addWidget(self.coinshuffle_inputs_list, 13, 1, 1, -1)

        self.window.cashaddr_toggled_signal.connect(
            lambda: self.update_inputs(force_update=True))

        self.check_sufficient_ammount()

        vbox0 = QVBoxLayout()
        vbox0.addLayout(self.shuffle_grid)
        hbox = QHBoxLayout()
        hbox.addLayout(vbox0)
        vbox = QVBoxLayout(self)
        vbox.addLayout(hbox)
        vbox.addStretch(1)

    def disable_bot_settings(self):
        self.coinshuffle_servers.setEnabled(False)
        self.coinshuffle_enable_bot.setEnabled(False)
        self.coinshuffle_bot_limit.setEnabled(False)
        self.coinshuffle_bot_maximum.setEnabled(False)
        self.coinshuffle_bot_period.setEnabled(False)

    def enable_bot_settings(self):
        self.coinshuffle_servers.setEnabled(True)
        self.coinshuffle_enable_bot.setEnabled(True)
        self.coinshuffle_bot_limit.setEnabled(True)
        self.coinshuffle_bot_maximum.setEnabled(True)
        self.coinshuffle_bot_period.setEnabled(True)

    def start_bot(self):
        server_params = self.coinshuffle_servers.get_current_server()
        server = server_params['server']
        port = server_params['port']
        info = server_params['info']
        ssl = server_params.get('ssl', False)
        stat_endpoint = "http{}://{}:{}/stats".format("s" if ssl else "",
                                                      server, info)
        limit_value = self.coinshuffle_bot_limit.text()
        limit = int(
            limit_value) if not limit_value == "" else self.bot_limit_value
        maximum_value = self.coinshuffle_bot_maximum.text()
        maximum = int(maximum_value
                      ) if not maximum_value == "" else self.bot_maximum_value
        period_value = self.coinshuffle_bot_period.text()
        period = int(
            period_value) if not period_value == "" else self.bot_period_value
        basic_logger = SimpleLogger(logchan=self.coinshuffle_text_output)
        coin = Coin(self.window.network)
        fee = self.coinshuffle_fee_constant
        password = None
        parent = self.window.top_level_window()
        while self.window.wallet.has_password():
            password = self.window.password_dialog(parent=parent)
            if password is None:
                # User cancelled password input
                return
            try:
                self.window.wallet.check_password(password)
                break
            except Exception as e:
                self.window.show_error(str(e), parent=parent)
                continue
        bot_logger = ConsoleLogger()
        bot_logger.logUpdater.connect(
            lambda x: self.coinshuffle_text_output.append(x))
        self.bot_thread = BotThread(stat_endpoint, server, port,
                                    self.window.network, ssl, limit, maximum,
                                    SimpleLogger, self.window.wallet, password,
                                    fee, bot_logger, True, period)
        self.bot_thread.start()
        self.disable_bot_settings()
        self.coinshuffle_bot_start_button.setEnabled(False)
        self.coinshuffle_bot_stop_button.setEnabled(True)

    def cancel_bot(self):
        self.coinshuffle_bot_stop_button.setEnabled(False)
        if self.bot_thread:
            self.bot_thread.join()
        self.coinshuffle_bot_start_button.setEnabled(True)
        self.enable_bot_settings()

    def switch_bot(self, checked):
        if checked:
            self.coinshuffle_inputs_list.hide()
            self.coinshuffle_inputs_label.hide()
            self.coinshuffle_inputs_total_label.hide()
            self.coinshuffle_inputs_total_output.hide()
            self.coinshuffle_changes.hide()
            self.coinshuffle_changes_label.hide()
            self.coinshuffle_fresh_changes.hide()
            self.coinshuffle_outputs_label.hide()
            self.coinshuffle_outputs.hide()
            self.coinshuffle_use_external_output.hide()
            self.coinshuffle_external_output.hide()
            self.coinshuffle_amount_label.hide()
            self.coinshuffle_amount_radio.hide()
            self.coinshuffle_start_button.hide()
            self.coinshuffle_cancel_button.hide()
            self.coinshuffle_timer_output.hide()

            self.coinshuffle_bot_limit.show()
            self.coinshuffle_bot_maximum.show()
            self.coinshuffle_bot_period.show()
            self.coinshuffle_bot_limit_label.show()
            self.coinshuffle_bot_maximum_label.show()
            self.coinshuffle_bot_period_label.show()
            self.coinshuffle_bot_start_button.show()
            self.coinshuffle_bot_stop_button.show()

        else:
            self.coinshuffle_bot_limit.hide()
            self.coinshuffle_bot_maximum.hide()
            self.coinshuffle_bot_period.hide()
            self.coinshuffle_bot_limit_label.hide()
            self.coinshuffle_bot_maximum_label.hide()
            self.coinshuffle_bot_period_label.hide()
            self.coinshuffle_bot_start_button.hide()
            self.coinshuffle_bot_stop_button.hide()

            self.coinshuffle_inputs_list.show()
            self.coinshuffle_inputs_label.show()
            self.coinshuffle_inputs_total_label.show()
            self.coinshuffle_inputs_total_output.show()
            self.coinshuffle_changes.show()
            self.coinshuffle_changes_label.show()
            self.coinshuffle_fresh_changes.show()
            self.coinshuffle_outputs_label.show()
            self.coinshuffle_outputs.show()
            self.coinshuffle_use_external_output.show()
            self.coinshuffle_external_output.show()
            self.coinshuffle_amount_label.show()
            self.coinshuffle_amount_radio.show()
            self.coinshuffle_start_button.show()
            self.coinshuffle_cancel_button.show()
            self.coinshuffle_timer_output.show()

    def coinshuffle_change_outputs(self, checked):
        if checked:
            self.coinshuffle_external_output.setEnabled(True)
            self.coinshuffle_outputs.setEnabled(False)
        else:
            self.coinshuffle_external_output.setEnabled(False)
            self.coinshuffle_outputs.setEnabled(True)
        self.check_sufficient_ammount()

    def update_inputs(self, force_update=False):
        if not self.coinshuffle_cancel_button.isEnabled():
            self.coinshuffle_inputs_list.update(self.window.wallet,
                                                force_update=force_update)
            self.coinshuffle_outputs.update(self.window.wallet)
            self.coinshuffle_changes.update(
                self.window.wallet,
                fresh_only=self.coinshuffle_fresh_changes.isChecked())

    def tick(self):
        self.waiting_timeout -= 1
        if self.waiting_timeout > 0:
            self.coinshuffle_timer_output.setText("{} s to break".format(
                self.waiting_timeout))
        else:
            self.logger.send("Error: timeout waiting for another players")

    def set_coinshuffle_addrs(self):
        self.coinshuffle_servers.setItems()
        self.coinshufle_input_addrs = map(lambda x: x.get('address'),
                                          self.window.wallet.get_utxos())
        self.coinshuffle_outputs_addrs = map(lambda x: x.get('address'),
                                             self.window.wallet.get_utxos())
        self.coinshuffle_inputs_list.setItems(self.window.wallet)
        self.coinshuffle_changes.setItems(
            self.window.wallet,
            fresh_only=self.coinshuffle_fresh_changes.isChecked())
        self.coinshuffle_outputs.setItems(self.window.wallet)

    def get_sufficient_amount(self):
        return self.coinshuffle_amount_radio.get_amount(
        ) + self.coinshuffle_fee_constant

    def check_sufficient_ammount(self):
        coin_amount = self.coinshuffle_inputs_list.get_selected_amount()
        self.coinshuffle_inputs_total_output.setText(
            self.window.format_amount_and_units(coin_amount))
        shuffle_amount = self.coinshuffle_amount_radio.get_amount()
        fee = self.coinshuffle_fee_constant
        if shuffle_amount and fee:
            if coin_amount > (fee + shuffle_amount):
                self.coinshuffle_start_button.setEnabled(True)
                if self.coinshuffle_use_external_output.isChecked():
                    if not Address.is_valid(
                            self.coinshuffle_external_output.text()):
                        self.coinshuffle_start_button.setEnabled(False)
            else:
                self.coinshuffle_start_button.setEnabled(False)
        else:
            self.coinshuffle_start_button.setEnabled(False)

    def enable_coinshuffle_settings(self):
        # self.check_sufficient_ammount()
        self.coinshuffle_servers.setEnabled(True)
        self.coinshuffle_start_button.setEnabled(True)
        self.coinshuffle_inputs_list.setEnabled(True)
        self.coinshuffle_changes.setEnabled(True)
        self.coinshuffle_outputs.setEnabled(True)
        self.coinshuffle_amount_radio.setEnabled(True)
        self.waiting_timeout = 180
        self.coinshuffle_timer_output.setText("")
        self.coinshuffle_use_external_output.setEnabled(True)
        self.coinshuffle_external_output.setEnabled(True)
        self.coinshuffle_fresh_changes.setEnabled(True)
        self.coinshuffle_enable_bot.setEnabled(True)

    def disable_coinshuffle_settings(self):
        self.coinshuffle_servers.setEnabled(False)
        self.coinshuffle_start_button.setEnabled(False)
        self.coinshuffle_inputs_list.setEnabled(False)
        self.coinshuffle_changes.setEnabled(False)
        self.coinshuffle_outputs.setEnabled(False)
        self.coinshuffle_amount_radio.setEnabled(False)
        self.coinshuffle_use_external_output.setEnabled(False)
        self.coinshuffle_external_output.setEnabled(False)
        self.coinshuffle_fresh_changes.setEnabled(False)
        self.coinshuffle_enable_bot.setEnabled(False)

    def process_protocol_messages(self, message):
        if message.startswith("Error"):
            self.pThread.join()
            self.coinshuffle_text_output.setTextColor(QColor('red'))
            self.coinshuffle_text_output.append(message)
            self.enable_coinshuffle_settings()
            self.coinshuffle_cancel_button.setEnabled(False)
            self.coinshuffle_inputs_list.update(self.window.wallet)
            self.coinshuffle_outputs.update(self.window.wallet)
            self.timer.stop()
        elif message[-17:] == "complete protocol":
            self.coinshuffle_text_output.append(message)
            self.pThread.done.set()
            tx = self.pThread.protocol.tx
            if tx:
                self.pThread.join()
            else:
                print("No tx: " + str(tx.raw))
            self.enable_coinshuffle_settings()
            self.coinshuffle_cancel_button.setEnabled(False)
            self.coinshuffle_inputs_list.update(self.window.wallet)
            self.coinshuffle_outputs.update(self.window.wallet)
        elif "begins" in message:
            self.timer.stop()
            self.coinshuffle_timer_output.setText("")
            self.waiting_timeout = 180
        else:
            header = message[:6]
            if header == 'Player':
                self.coinshuffle_text_output.setTextColor(QColor('green'))
            if header[:5] == 'Blame':
                self.coinshuffle_text_output.setTextColor(QColor('red'))
                if "insufficient" in message:
                    pass
                elif "wrong hash" in message:
                    pass
                else:
                    self.pThread.join()
                    self.enable_coinshuffle_settings()
                    self.coinshuffle_text_output.append(
                        str(self.pThread.isAlive()))
            self.coinshuffle_text_output.append(message)
            self.coinshuffle_text_output.setTextColor(QColor('black'))

    def start_coinshuffle_protocol(self):
        from .client import ProtocolThread
        from electroncash.bitcoin import (regenerate_key, deserialize_privkey)
        from .shuffle import ConsoleLogger
        parent = self.window.top_level_window()
        password = None
        while self.window.wallet.has_password():
            password = self.window.password_dialog(parent=parent)
            if password is None:
                # User cancelled password input
                return
            try:
                self.window.wallet.check_password(password)
                break
            except Exception as e:
                self.window.show_error(str(e), parent=parent)
                continue
        try:
            server_params = self.coinshuffle_servers.get_current_server()
            server = server_params['server']
            port = server_params['port']
            ssl = server_params.get('ssl', False)
        except:
            self.coinshuffle_text_output.setText(
                'Wrong server connection string')
            return

        inputs_utxos = self.coinshuffle_inputs_list.get_checked_utxos()
        possible_change_address = self.coinshuffle_changes.get_change_address()
        if possible_change_address:
            change_address = possible_change_address
        else:
            change_address = inputs_utxos[0]['address'].to_string(
                Address.FMT_LEGACY)
        if self.coinshuffle_use_external_output.isChecked():
            output_address = self.coinshuffle_external_output.text()
        else:
            output_address = self.coinshuffle_outputs.get_output_address()
        #disable inputs
        self.disable_coinshuffle_settings()
        self.coinshuffle_cancel_button.setEnabled(True)
        #
        amount = self.coinshuffle_amount_radio.get_amount()
        fee = self.coinshuffle_fee_constant
        self.logger = ConsoleLogger()
        self.logger.logUpdater.connect(
            lambda x: self.process_protocol_messages(x))
        sks = {}
        inputs = {}
        for utxo in inputs_utxos:
            public_key = self.window.wallet.get_public_key(utxo['address'])
            priv_key = self.window.wallet.export_private_key(
                utxo['address'], password)
            sks[public_key] = regenerate_key(deserialize_privkey(priv_key)[1])
            if not public_key in inputs:
                inputs[public_key] = []
            inputs[public_key].append(utxo['prevout_hash'] + ":" +
                                      str(utxo['prevout_n']))
        pub_key = list(inputs.keys())[0]
        sk = sks[pub_key]
        self.pThread = ProtocolThread(server,
                                      port,
                                      self.window.network,
                                      amount,
                                      fee,
                                      sk,
                                      sks,
                                      inputs,
                                      pub_key,
                                      output_address,
                                      change_address,
                                      logger=self.logger,
                                      ssl=ssl)
        self.pThread.start()
        self.timer.start(1000)

    def cancel_coinshuffle_protocol(self):
        if self.pThread.is_alive():
            self.pThread.join()
            while self.pThread.is_alive():
                time.sleep(0.1)
            self.coinshuffle_cancel_button.setEnabled(False)
            self.timer.stop()
            self.enable_coinshuffle_settings()