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

# Copyright (c) 2016 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a movement (goto) widget for the hex editor.
"""


from PyQt5.QtCore import pyqtSlot, Qt, QRegExp
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QWidget

from .Ui_HexEditGotoWidget import Ui_HexEditGotoWidget

import UI.PixmapCache
import Globals


class HexEditGotoWidget(QWidget, Ui_HexEditGotoWidget):
    """
    Class implementing a movement (goto) widget for the hex editor.
    """
    def __init__(self, editor, parent=None):
        """
        Constructor
        
        @param editor reference to the hex editor widget
        @type HexEditWidget
        @param parent reference to the parent widget
        @type QWidget
        """
        super(HexEditGotoWidget, self).__init__(parent)
        self.setupUi(self)
        
        self.__editor = editor
        
        # keep this in sync with the logic in on_gotoButton_clicked()
        self.__formatAndValidators = {
            "hex": (self.tr("Hex"), QRegExpValidator((QRegExp("[0-9a-f:]*")))),
            "dec": (self.tr("Dec"), QRegExpValidator((QRegExp("[0-9]*")))),
        }
        formatOrder = ["hex", "dec"]
        
        self.__currentFormat = ""
        
        self.closeButton.setIcon(UI.PixmapCache.getIcon("close.png"))
        
        for dataFormat in formatOrder:
            formatStr, validator = self.__formatAndValidators[dataFormat]
            self.formatCombo.addItem(formatStr, dataFormat)
        
        self.formatCombo.setCurrentIndex(0)
    
    @pyqtSlot()
    def on_closeButton_clicked(self):
        """
        Private slot to close the widget.
        """
        self.__editor.setFocus(Qt.OtherFocusReason)
        self.close()
    
    @pyqtSlot(int)
    def on_formatCombo_currentIndexChanged(self, idx):
        """
        Private slot to handle a selection of the format.
        
        @param idx index of the selected entry
        @type int
        """
        if idx >= 0:
            dataFormat = self.formatCombo.itemData(idx)
            
            if dataFormat != self.__currentFormat:
                txt = self.offsetEdit.text()
                newTxt = self.__convertText(
                    txt, self.__currentFormat, dataFormat)
                self.__currentFormat = dataFormat
                
                self.offsetEdit.setValidator(
                    self.__formatAndValidators[dataFormat][1])
                
                self.offsetEdit.setText(newTxt)
    
    @pyqtSlot(str)
    def on_offsetEdit_textChanged(self, offset):
        """
        Private slot handling a change of the entered offset.
        
        @param offset entered offset
        @type str
        """
        self.gotoButton.setEnabled(bool(offset))
        
    @pyqtSlot()
    def on_gotoButton_clicked(self):
        """
        Private slot to move the cursor and extend the selection.
        """
        dataFormat = self.formatCombo.itemData(self.formatCombo.currentIndex())
        if dataFormat == "hex":
            offset = self.offsetEdit.text().replace(":", "")
            # get rid of ':' address separators
            offset = int(offset, 16)
        else:
            offset = int(self.offsetEdit.text(), 10)
        
        fromCursor = self.cursorCheckBox.isChecked()
        backwards = self.backCheckBox.isChecked()
        extendSelection = self.selectionCheckBox.isChecked()
        
        self.__editor.goto(offset, fromCursor=fromCursor, backwards=backwards,
                           extendSelection=extendSelection)
    
    def show(self):
        """
        Public slot to show the widget.
        """
        self.offsetEdit.selectAll()
        self.offsetEdit.setFocus()
        super(HexEditGotoWidget, self).show()
    
    def reset(self):
        """
        Public slot to reset the input widgets.
        """
        self.offsetEdit.clear()
        self.formatCombo.setCurrentIndex(0)
        self.cursorCheckBox.setChecked(False)
        self.backCheckBox.setChecked(False)
        self.selectionCheckBox.setChecked(False)

    def keyPressEvent(self, event):
        """
        Protected slot to handle key press events.
        
        @param event reference to the key press event
        @type QKeyEvent
        """
        if event.key() == Qt.Key_Escape:
            self.close()
    
    def __convertText(self, txt, oldFormat, newFormat):
        """
        Private method to convert text from one format into another.
        
        @param txt text to be converted
        @type str
        @param oldFormat current format of the text
        @type str
        @param newFormat format to convert to
        @type str
        @return converted text
        @rtype str
        """
        if txt and oldFormat and newFormat and oldFormat != newFormat:
            # step 1: convert the text to an integer using the old format
            if oldFormat == "hex":
                txt = txt.replace(":", "")  # get rid of ':' address separators
                index = int(txt, 16)
            else:
                index = int(txt, 10)
            
            # step 2: convert the integer to text using the new format
            if newFormat == "hex":
                txt = "{0:x}".format(index)
                txt = Globals.strGroup(txt, ":", 4)
            else:
                txt = "{0:d}".format(index)
        
        return txt
