"""
Additional dialogs and panels used by the sequence viewer.
Copyright Schrodinger, LLC. All rights reserved.
"""
# Contributors: Piotr Rotkiewicz
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from . import maestro as my_maestro
from .fileio import load_fasta_file
from .sequence import Sequence
try:
    from schrodinger import maestro
except:
    maestro = None
[docs]class WeightColorsDialog(QtWidgets.QDialog):
    """
    This class implements a remove redundancy dialog.
    """
[docs]    def __init__(self, parent, sequence_group):
        # Initialize base class.
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowTitle("Adjust Color Range")
        self.sequence_group = sequence_group
        #: Dialog push buttons.
        self.button_ok = QtWidgets.QPushButton(self)
        self.button_ok.setText("OK")
        self.button_ok.setDefault(True)
        self.button_ok.clicked.connect(self.accept)
        self.button_reset = QtWidgets.QPushButton(self)
        self.button_reset.setText("Reset")
        self.button_reset.clicked.connect(self.resetSliders)
        self.button_layout = QtWidgets.QHBoxLayout()
        self.button_layout.addWidget(self.button_reset)
        self.button_layout.addWidget(self.button_ok)
        self.identity_label = QtWidgets.QLabel()
        self.min_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.min_slider.setRange(0, 100.0)
        self.min_slider.setTickInterval(10)
        self.min_slider.setValue(parent.min_weight_identity)
        self.min_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
        self.min_slider.valueChanged.connect(self.minValueChanged)
        self.slider_layout = QtWidgets.QGridLayout()
        self.slider_layout.addWidget(QtWidgets.QLabel("Background Color"), 0, 0)
        self.slider_layout.addWidget(self.min_slider, 0, 1)
        self.max_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.max_slider.setRange(0, 100.0)
        self.max_slider.setTickInterval(10)
        self.max_slider.setValue(parent.max_weight_identity)
        self.max_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
        self.max_slider.valueChanged.connect(self.maxValueChanged)
        self.slider_layout.addWidget(QtWidgets.QLabel("Full Color"), 1, 0)
        self.slider_layout.addWidget(self.max_slider, 1, 1)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.addWidget(self.identity_label)
        self.layout.addLayout(self.slider_layout)
        self.layout.addLayout(self.button_layout)
        # Update sliders.
        self.minValueChanged(self.min_slider.value())
        self.maxValueChanged(self.max_slider.value())
        self.sizePolicy().setVerticalPolicy(QtWidgets.QSizePolicy.Maximum)
        self.resize(600, 150) 
[docs]    def resetSliders(self):
        self.min_slider.setValue(20.0)
        self.max_slider.setValue(100.0)
        self.parent().updateView(update_colors=True) 
[docs]    def minValueChanged(self, value):
        if value >= self.parent().max_weight_identity:
            self.min_slider.setValue(self.parent().max_weight_identity - 1)
            return
        self.parent().min_weight_identity = value
        self.identity_label.setText("Sequence Identity Range: " + str(value) +
                                    "% - " +
                                    str(self.parent().max_weight_identity) +
                                    "%")
        self.parent().updateView(update_colors=True) 
[docs]    def maxValueChanged(self, value):
        if value <= self.parent().min_weight_identity:
            self.max_slider.setValue(self.parent().min_weight_identity + 1)
            return
        self.parent().max_weight_identity = value
        self.identity_label.setText("Sequence Identity Range: " +
                                    str(self.parent().min_weight_identity) +
                                    "% - " + str(value) + "%")
        self.parent().updateView(update_colors=True)  
[docs]class SequenceEditorDialog(QtWidgets.QDialog):
[docs]    def __init__(self, parent, sequence, sequence_group, fasta_editor=False):
        # Initialize base class.
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowTitle("Sequence Editor")
        self.resize(600, 300)
        self.layout = QtWidgets.QVBoxLayout(self)
        h_layout = QtWidgets.QHBoxLayout()
        self.name_label = QtWidgets.QLabel("Sequence Name:")
        self.name_editor = QtWidgets.QLineEdit()
        if sequence:
            self.name_editor.setText(sequence.name)
            h_layout.addWidget(self.name_label)
        h_layout.addWidget(self.name_editor)
        self.layout.addLayout(h_layout)
        self.sequence_label = QtWidgets.QLabel("Sequence:")
        self.layout.addWidget(self.sequence_label)
        self.sequence_editor = QtWidgets.QTextEdit()
        self.sequence_editor.setAcceptRichText(False)
        if sequence:
            self.sequence_editor.setText(sequence.toString())
        self.layout.addWidget(self.sequence_editor)
        self.button_add = QtWidgets.QPushButton()
        self.button_add.setText("Append")
        self.button_replace = QtWidgets.QPushButton()
        self.button_replace.setText("Replace")
        self.button_cancel = QtWidgets.QPushButton()
        self.button_cancel.setText("Cancel")
        button_layout = QtWidgets.QHBoxLayout()
        button_layout.addWidget(self.button_add)
        button_layout.addWidget(self.button_replace)
        button_layout.addWidget(self.button_cancel)
        self.layout.addLayout(button_layout)
        self.sequence = sequence
        self.sequence_group = sequence_group
        self.button_add.clicked.connect(self.addSequence)
        self.button_replace.clicked.connect(self.replaceSequence)
        self.button_cancel.clicked.connect(self.reject)
        self.fasta_editor = fasta_editor
        if fasta_editor:
            self.name_editor.hide() 
[docs]    def addSequence(self):
        if self.fasta_editor:
            text = str(self.sequence_editor.toPlainText())
            text = text.rsplit("\n")
            load_fasta_file(self.sequence_group, None, text)
            self.hide()
        else:
            self.sequence = Sequence()
            self.sequence.name = str(self.name_editor.text())
            self.sequence.short_name = str(self.name_editor.text())
            if len(self.sequence.short_name) > 1 and \
                    
self.sequence.short_name[-2] == '_':
                self.sequence.chain_id = self.sequence.short_name[-1]
            self.sequence.appendResidues(self.sequence_editor.toPlainText())
            self.sequence.sanitize()
            if self.sequence.length() > 0:
                self.sequence_group.sequences.append(self.sequence)
            self.hide() 
[docs]    def replaceSequence(self):
        self.sequence.name = str(self.name_editor.text())
        self.sequence.short_name = self.sequence.name
        if len(self.sequence.short_name) > 1 and \
                
self.sequence.short_name[-2] == '_':
            self.sequence.chain_id = self.sequence.short_name[-1]
        self.sequence.residues = []
        self.sequence.appendResidues(self.sequence_editor.toPlainText())
        self.sequence.sanitize()
        self.hide()  
[docs]class RemoveRedundancyDialog(QtWidgets.QDialog):
    """
    This class implements a remove redundancy dialog.
    """
[docs]    def __init__(self, parent, sequence_group):
        # Initialize base class.
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowTitle("Remove Redundant Sequences")
        self.sequence_group = sequence_group
        #: Dialog push button.
        self.button_remove = QtWidgets.QPushButton(self)
        self.button_remove.setText("Remove")
        self.button_remove.setDefault(True)
        self.button_remove.clicked.connect(self.accept)
        #: Dialog push button.
        self.button_cancel = QtWidgets.QPushButton(self)
        self.button_cancel.setText("Close")
        self.button_cancel.clicked.connect(self.reject)
        #: Button layout.
        self.button_layout = QtWidgets.QHBoxLayout()
        self.button_layout.addWidget(self.button_remove)
        self.button_layout.addWidget(self.button_cancel)
        self.redundancy_label = QtWidgets.QLabel()
        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setTickInterval(10)
        self.slider.setValue(100)
        self.slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
        self.slider.valueChanged.connect(self.valueChanged)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.addWidget(self.redundancy_label)
        self.layout.addWidget(self.slider)
        self.layout.addLayout(self.button_layout)
        self.valueChanged(100)
        self.sizePolicy().setVerticalPolicy(QtWidgets.QSizePolicy.Maximum) 
[docs]    def valueChanged(self, value):
        self.redundancy_label.setText("Identity Threshold: " + str(value) + "%")
        self.sequence_group.selectRedundantSequences(value)
        self.parent().name_area.repaint()  
[docs]class RemoteQueryDialog(QtWidgets.QDialog):
    """
    This class implements a remote access query dialog.
    """
[docs]    def __init__(self, parent):
        # Initialize base class.
        QtWidgets.QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle("Attempting to Access Remote Server")
        self.setModal(True)
        self.resize(400, 200)
        #: Dialog push button.
        self.button_ok = QtWidgets.QPushButton(self)
        self.button_ok.setText("Continue")
        self.button_ok.clicked.connect(self.accept)
        #: Dialog push button.
        self.button_cancel = QtWidgets.QPushButton(self)
        self.button_cancel.setText("Cancel")
        self.button_cancel.setDefault(True)
        self.button_cancel.clicked.connect(self.reject)
        self.description = QtWidgets.QLabel(
            "Multiple Sequence Viewer is attempting to access a remote server.\n"
            "Would you like to continue?")
        self.never_ask = QtWidgets.QCheckBox("Do not ask this question again")
        #: Button layout.
        self.button_layout = QtWidgets.QHBoxLayout()
        self.button_layout.addWidget(self.button_ok)
        self.button_layout.addWidget(self.button_cancel)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.addWidget(self.description)
        self.layout.addWidget(self.never_ask)
        self.layout.addSpacing(20)
        self.layout.addLayout(self.button_layout) 
[docs]    def query(self, server=None):
        settings = QtCore.QSettings(QtCore.QSettings.IniFormat,
                                    QtCore.QSettings.UserScope,
                                    "multiple_sequence_viewer")
        if self.parent and hasattr(self.parent, "always_ask_action") and \
                
self.parent.always_ask_action:
            settings.setValue("viewer_ask_before_remote_access",
                              self.parent.always_ask_action.isChecked())
        always_ask = settings.value("viewer_ask_before_remote_access")
        if not always_ask:
            return True
        if self.exec_():
            always_ask = not self.never_ask.isChecked()
            settings.setValue("viewer_ask_before_remote_access", always_ask)
            if self.parent and hasattr(self.parent, "always_ask_action") and \
               
self.parent.always_ask_action:
                self.parent.always_ask_action.setChecked(always_ask)
            return True
        else:
            return False  
[docs]class RenumberResiduesDialog(QtWidgets.QDialog):
    """
    This class implements 'Renumber Residues' dialog.
    """
[docs]    def __init__(self, parent, sequence_group):
        # Initialize base class.
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowTitle("Renumber Residues")
        self.sequence_group = sequence_group
        self.simple_page = QtWidgets.QWidget(self)
        self.simple_page_layout = QtWidgets.QVBoxLayout()
        self.simple_page.setLayout(self.simple_page_layout)
        self.start_num_label = QtWidgets.QLabel("First position:")
        self.start_num_le = QtWidgets.QLineEdit("1", self)
        self.start_num_layout = QtWidgets.QHBoxLayout()
        self.start_num_layout.addWidget(self.start_num_label)
        self.start_num_layout.addWidget(self.start_num_le)
        self.start_num_layout.addStretch(100)
        self.inc_num_label = QtWidgets.QLabel("Increment:")
        self.inc_num_le = QtWidgets.QLineEdit("1", self)
        self.inc_num_layout = QtWidgets.QHBoxLayout()
        self.inc_num_layout.addWidget(self.inc_num_label)
        self.inc_num_layout.addWidget(self.inc_num_le)
        self.inc_num_layout.addStretch(100)
        self.preserve_icodes_cb = QtWidgets.QCheckBox(self)
        self.preserve_icodes_cb.setText("Preserve insertion codes")
        self.preserve_icodes_cb.setChecked(False)
        self.simple_page_layout.addLayout(self.start_num_layout)
        self.simple_page_layout.addLayout(self.inc_num_layout)
        self.simple_page_layout.addWidget(self.preserve_icodes_cb)
        self.simple_page_layout.addStretch(100)
        self.template_page = QtWidgets.QWidget(self)
        self.template_page_layout = QtWidgets.QVBoxLayout()
        self.template_page.setLayout(self.template_page_layout)
        self.schemeTable = QtWidgets.QTableWidget(0, 1)
        self.schemeTable.setAlternatingRowColors(True)
        self.table_font = self.schemeTable.font()
        self.table_font.setPointSize(10)
        self.schemeTable.setFont(self.table_font)
        self.schemeTable.setHorizontalHeaderLabels(["Numbering scheme"])
        self.schemeTable.horizontalHeader().setStretchLastSection(True)
        self.schemeTable.resizeColumnsToContents()
        self.schemeTable.sortItems(1, QtCore.Qt.AscendingOrder)
        self.schemeTable.itemSelectionChanged.connect(self.schemeChanged)
        self.numbersTable = QtWidgets.QTableWidget(0, 3)
        self.numbersTable.setAlternatingRowColors(True)
        self.table_font = self.numbersTable.font()
        self.table_font.setPointSize(10)
        self.numbersTable.setFont(self.table_font)
        self.numbersTable.setHorizontalHeaderLabels(
            ["Residue number", "Insertion code", "Residue name"])
        self.numbersTable.horizontalHeader().setStretchLastSection(True)
        self.numbersTable.resizeColumnsToContents()
        self.numbersTable.sortItems(1, QtCore.Qt.AscendingOrder)
        self.template_page_layout.addWidget(self.schemeTable)
        self.template_page_layout.addWidget(self.numbersTable)
        self.button_import = QtWidgets.QPushButton(self)
        self.button_import.setText("Import template...")
        self.button_import.clicked.connect(self.importTemplate)
        self.template_page_layout.addWidget(self.schemeTable)
        self.template_page_layout.addWidget(self.numbersTable)
        self.template_page_layout.addWidget(self.button_import)
        self.tabs = QtWidgets.QTabWidget(self)
        self.tabs.addTab(self.simple_page, "Simple")
        self.tabs.addTab(self.template_page, "Template-based")
        #: Dialog push buttons.
        self.button_ok = QtWidgets.QPushButton(self)
        self.button_ok.setText("Renumber")
        self.button_ok.setDefault(True)
        self.button_ok.clicked.connect(self.accept)
        self.button_reset = QtWidgets.QPushButton(self)
        self.button_reset.setText("Close")
        self.button_reset.clicked.connect(self.reject)
        #: "Help" push button.
        self.button_help = QtWidgets.QPushButton(self)
        self.button_help.setText("Help")
        self.button_help.clicked.connect(self.helpCB)
        self.apply_to_maestro_cb = QtWidgets.QCheckBox(self)
        self.apply_to_maestro_cb.setText("Renumber residues in Maestro entries")
        self.apply_to_maestro_cb.setChecked(True)
        self.button_layout = QtWidgets.QHBoxLayout()
        self.button_layout.addWidget(self.apply_to_maestro_cb)
        self.button_layout.addStretch(100)
        self.button_layout.addWidget(self.button_help)
        self.button_layout.addWidget(self.button_reset)
        self.button_layout.addWidget(self.button_ok)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.addWidget(self.tabs)
        self.layout.addLayout(self.button_layout)
        self.schemes = {} 
[docs]    def accept(self):
        start = int(self.start_num_le.text())
        incr = int(self.inc_num_le.text())
        none_selected = not self.sequence_group.hasSelectedSequences()
        for seq in self.sequence_group.sequences:
            if seq.isValidProtein() and (seq.selected or none_selected):
                seq.renumberResidues(
                    start,
                    incr,
                    preserve_ins_codes=self.preserve_icodes_cb.isChecked())
                if my_maestro and self.apply_to_maestro_cb.isChecked():
                    my_maestro.renumberMaestroEntry(self.parent(), seq)
        self.close()
        return True 
[docs]    def importTemplate(self):
        """
        Import a PDB numbering template.
        """
        self.file_import_dialog = QtWidgets.QFileDialog()
        self.file_import_dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
        self.file_import_dialog.setOption(
            QtWidgets.QFileDialog.DontUseNativeDialog)
        self.file_import_dialog.setViewMode(QtWidgets.QFileDialog.Detail)
        self.file_import_dialog.setWindowTitle("Import Sequences")
        self.file_import_dialog.setNameFilters(
            ["PDB (*.pdb *.ent)", "Any File (*.*)"])
        self.file_import_dialog.exec_()
        scheme = []
        self.numbersTable.clearContents()
        self.numbersTable.setRowCount(0)
        if self.file_import_dialog.result():
            files = self.file_import_dialog.selectedFiles()
            if files:
                pdb_file = open(files[0], "r")
                if not pdb_file:
                    return
                lines = pdb_file.readlines()
                pdb_file.close()
                prev_res_id = ""
                scheme_name = "Scheme " + str(self.schemeTable.rowCount() + 1)
                for line in lines:
                    if line.startswith("HEAD"):
                        scheme_name = line[62:67] + line[10:50]
                    if not line.startswith("ATOM"):
                        continue
                    res_id = line[22:27]
                    if res_id == prev_res_id:
                        continue
                    res_num = res_id[:-1]
                    res_ins_code = res_id[-1]
                    prev_res_id = res_id
                    res_name = line[17:20]
                    row = self.numbersTable.rowCount()
                    self.numbersTable.insertRow(row)
                    new_item = QtWidgets.QTableWidgetItem(res_num)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 0, new_item)
                    new_item = QtWidgets.QTableWidgetItem(res_ins_code)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 1, new_item)
                    new_item = QtWidgets.QTableWidgetItem(res_name)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 2, new_item)
                    scheme.append((res_num, res_ins_code, res_name))
        if not scheme:
            return
        self.numbersTable.resizeColumnsToContents()
        self.numbersTable.horizontalHeader().setStretchLastSection(True)
        row = self.schemeTable.rowCount()
        self.schemeTable.insertRow(row)
        self.schemes[str(scheme_name)] = scheme
        new_item = QtWidgets.QTableWidgetItem(str(scheme_name))
        new_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
        self.schemeTable.setItem(row, 0, new_item) 
[docs]    def schemeChanged(self):
        selected = self.schemeTable.selectedItems()
        if selected:
            self.numbersTable.clearContents()
            self.numbersTable.setRowCount(0)
            key = str(selected[0].text())
            if key in list(self.schemes):
                scheme = self.schemes[key]
                for item in scheme:
                    res_num, res_ins_code, res_name = item
                    row = self.numbersTable.rowCount()
                    self.numbersTable.insertRow(row)
                    new_item = QtWidgets.QTableWidgetItem(res_num)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 0, new_item)
                    new_item = QtWidgets.QTableWidgetItem(res_ins_code)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 1, new_item)
                    new_item = QtWidgets.QTableWidgetItem(res_name)
                    new_item.setFlags(QtCore.Qt.ItemIsSelectable |
                                      QtCore.Qt.ItemIsEnabled)
                    self.numbersTable.setItem(row, 2, new_item) 
[docs]    def helpCB(self):
        """
        Invokes a Homology Modeling help page.
        """
        if maestro:
            maestro.command("helptopic TOOLS_MENU_MSV_RENUMBER_RESIDUES")