class _TransferWidget(QFrame):
    cancel = pyqtSignal()
    cancelBeforeTransfer = pyqtSignal(int) # transfer ID
    retry = pyqtSignal(object, object, int) # filesOrData, peerID, transfer ID
    
    def __init__(self, parent, logger, filesOrData, name, targetDir, numFiles, totalSize, peerID, transferID, down):
        super(_TransferWidget, self).__init__(parent)
        
        self.logger = logger
        self._filesOrData = filesOrData
        self._targetDir = targetDir
        self._numFiles = numFiles
        self._totalSize = totalSize
        self._targetFile = None
        self._peerID = peerID
        self._transferID = transferID
        self._transferring = True
        self._down = down
        self._success = False
        self._connectedToThread = False
        self._currentFile = None
        
        self._initLayout()
        
        if type(filesOrData) is list and len(filesOrData) is 1:
            self._setCurrentFile(filesOrData[0])
        elif name:
            f = NamedTemporaryFile(suffix=name, delete=True)
            f.flush()
            self._setCurrentFile(f.name, name)
            f.close()
        else:
            self._setCurrentFile(None)
        self.reset()
        
    def _initLayout(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(0)
        
        nameLayout = QHBoxLayout()
        nameLayout.setContentsMargins(0, 0, 0, 0)
        
        self._fileIconLabel = QLabel(self)
        nameLayout.addWidget(self._fileIconLabel, 0, Qt.AlignLeft)
        
        self._nameLabel = QLabel(self)
        nameLayout.addSpacing(5)
        nameLayout.addWidget(self._nameLabel, 1, Qt.AlignLeft)
        
        layout.addLayout(nameLayout)
        
        progressWidget = QWidget(self)
        progressLayout = QHBoxLayout(progressWidget)
        progressLayout.setSpacing(5)
        progressLayout.setContentsMargins(0, 0, 0, 0)
        
        iconLabel = QLabel(progressWidget)
        if self._down:
            picFile = get_settings().get_resource("images", "down.png")
        else:
            picFile = get_settings().get_resource("images", "up.png")
        iconLabel.setPixmap(QPixmap(picFile))
        iconLabel.setFixedSize(15,15)
        progressLayout.addWidget(iconLabel, 0, Qt.AlignBottom)
        
        self._progress = QProgressBar(progressWidget)
        self._progress.setMinimum(0)
        self._progress.setMaximum(100)
        if getPlatform() == PLATFORM_MAC:
            self._progress.setAttribute(Qt.WA_MacMiniSize)
            self._progress.setMaximumHeight(16)
        progressLayout.addWidget(self._progress, 1)
        
        self._button = QPushButton(progressWidget)
        self._button.clicked.connect(self._buttonClicked)
        progressLayout.addSpacing(5)
        progressLayout.addWidget(self._button, 0, Qt.AlignCenter)
        
        layout.addWidget(progressWidget, 0, Qt.AlignBottom)
        
        self._statusLabel = QLabel(self)
        if getPlatform() == PLATFORM_MAC:
            self._statusLabel.setAttribute(Qt.WA_MacSmallSize)
        layout.addWidget(self._statusLabel)
        
        self.setObjectName(u"__transfer_widget")
        self.setFrameShape(QFrame.StyledPanel)
        self.setStyleSheet("QFrame#__transfer_widget{border-width: 1px; border-top-style: none; border-right-style: none; border-bottom-style: solid; border-left-style: none; border-color:palette(mid)}");
            
        self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        
    def reset(self):
        self._transferring = True
        self._statusLabel.setText(u"Waiting for data..." if self._down else u"Waiting for peer...")
        self._checkButtonFunction()
        self._progress.setMaximum(0)
        
    def isFinished(self):
        return not self._transferring
    
    def isSuccessful(self):
        return self._success
    
    def getFilePath(self):
        if self._numFiles is 1:
            return self._currentFile
        
    def _setFileIcon(self, curPath):
        if os.path.exists(curPath):
            fileInfo = QFileInfo(curPath)
            iconProvider = QFileIconProvider()
            icon = iconProvider.icon(fileInfo)
            self._fileIconLabel.setPixmap(icon.pixmap(16,16))
        
    def _setCurrentFile(self, path, dispName=None):
        if get_peers() is not None:
            peerName = get_peers().getDisplayedPeerName(self._peerID)
        else:
            peerName = u"<unknown peer>"
            
        if not path:
            if self._down:
                text = u"%d %s (total %s) \u2190 %s"
            else:
                text = u"%d %s (total %s) \u2192 %s"
            text = text % (self._numFiles, u"file" if self._numFiles is 1 else "files", formatSize(self._totalSize), peerName)
        else:
            if self._down:
                text = u"%s (%stotal %s) \u2190 %s"
            else:
                text = u"%s (%stotal %s) \u2192 %s"
            if dispName is None:
                dispName = os.path.basename(path)
            
            numFilesS = u"" if self._numFiles is 1 else u"%d files, " % self._numFiles
            text = text % (dispName, numFilesS, formatSize(self._totalSize), peerName)
            self._setFileIcon(path)
            
        self._currentFile = path
        self._nameLabel.setText(text)
        
    def _setIcon(self, baseName):
        if baseName is None:
            self._button.setStyleSheet("""
                QPushButton {min-width: 15px;
                             max-width: 15px;
                             min-height: 15px;
                             max-height: 15px;
                             margin: 0px;
                             padding: 0px;
                             border:none;
                }
            """)
        else:
            defPath = get_settings().get_resource("images", "%s32.png" % baseName)
            pressPath = get_settings().get_resource("images", "%s32p.png" % baseName)
            self._button.setStyleSheet("""
                QPushButton {min-width: 15px;
                             max-width: 15px;
                             min-height: 15px;
                             max-height: 15px;
                             margin: 0px;
                             padding: 0px;
                             border:none;
                             border-image: url(%s);
                }
                QPushButton:pressed {
                             border-image: url(%s);
                }
            """ % (defPath, pressPath)
            )
        
    def _checkButtonFunction(self):
        if self._transferring:
            self._setIcon("cancel")
        elif self._down:
            if self._success:
                self._setIcon("reveal")
            else:
                self._setIcon(None)
        else:
            if self._success:
                self._setIcon("reveal")
            else:
                self._setIcon("retry")
    
    def _reveal(self):
        filePath = self.getFilePath()
        if filePath:
            revealFile(filePath, self.logger)
        elif self._down:
            openFile(self._targetDir, self.logger)
        elif self._currentFile and os.path.exists(self._currentFile):
            revealFile(self._currentFile, self.logger)
    
    def _buttonClicked(self):
        if self._transferring:
            if self._connectedToThread:
                self.cancel.emit()
            else:
                self.cancelBeforeTransfer.emit(self._transferID)
        elif self._down:
            if self._success:
                self._reveal()
        else:
            if self._success:
                self._reveal()
            else:
                self.retry.emit(self._filesOrData, self._peerID, self._transferID)
                
    @loggingSlot(object, int)
    def nextFile(self, nameOrPath, _size):
        self._setCurrentFile(nameOrPath)
        
    def connectDataThread(self, dataThread):
        if not dataThread.isRunning():
            self.transferError(dataThread, u"Transfer didn't start.")
            return
        self._connectedToThread = True
        dataThread.progressChanged.connect(self.progressChanged)
        dataThread.errorOnTransfer.connect(self.transferError)
        dataThread.successfullyTransferred.connect(self.successfullyTransferred)
        dataThread.transferCanceled.connect(self.transferCanceled)
        dataThread.nextFile.connect(self.nextFile)
        self.cancel.connect(dataThread.cancelTransfer)

    def disconnectDataThread(self, dataThread):
        if self._connectedToThread:
            self._connectedToThread = False   
            dataThread.progressChanged.disconnect(self.progressChanged)
            dataThread.errorOnTransfer.disconnect(self.transferError)
            dataThread.successfullyTransferred.disconnect(self.successfullyTransferred)
            dataThread.transferCanceled.disconnect(self.transferCanceled)
            dataThread.nextFile.disconnect(self.nextFile)
            self.cancel.disconnect(dataThread.cancelTransfer)
    
    @loggingSlot(int, int)
    def progressChanged(self, newVal, maxVal):
        if newVal is 0:
            self._transferring = True
            self._progress.setMaximum(maxVal)
            self._statusLabel.setText(u"Receiving data" if self._down else u"Sending data")
        self._progress.setValue(newVal)
    
    @pyqtSlot(QThread)
    @loggingSlot(QThread, object)
    def successfullyTransferred(self, thread, _path=None):
        self._transferring = False
        self._success = True
        self._statusLabel.setText(u"Transfer finished successfully")
        self.disconnectDataThread(thread)
        self._checkButtonFunction()
    
    @loggingSlot(QThread, object)
    def transferError(self, thread, message=None):
        if not self._transferring:
            return
        self._transferring = False
        self._statusLabel.setText(u"Error transferring file (%s)" % message)
        self.disconnectDataThread(thread)
        self._checkButtonFunction()
        if self._progress.maximum() == 0:
            self._progress.setMaximum(100)
    
    @loggingSlot(QThread)
    def transferCanceled(self, thread):
        self._transferring = False
        self._statusLabel.setText(u"Transfer canceled")
        self.disconnectDataThread(thread)
        self._checkButtonFunction()
        
    def canceledBeforeTransfer(self, isTimeout):
        self._progress.setMaximum(100)
        self._transferring = False
        if isTimeout:
            self._statusLabel.setText(u"Transfer timed out")
        else:
            self._statusLabel.setText(u"Transfer canceled")
        self._checkButtonFunction()