# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial

import os
from typing import Optional

from PySide6.QtCore import QFileSystemWatcher, Slot
from PySide6.QtWidgets import QPlainTextEdit, QWidget


class FileDisplay(QPlainTextEdit):
    """A QPlainTextEdit displaying/watching a file."""

    def __init__(self, parent: Optional[QWidget] = None):
        super().__init__(parent)
        self.setReadOnly(True)
        self._file_watcher: Optional[QFileSystemWatcher] = None
        self._file_name: str = ''

    def reset(self) -> None:
        if self._file_watcher:
            watched = self._file_watcher.files()
            watched.extend(self._file_watcher.directories())
            if watched:
                self._file_watcher.removePaths(watched)
        self._file_name = ''
        self.clear()

    def load(self, file_name: str) -> bool:
        if self._file_name == file_name:
            return True
        self.reset()
        result = self._do_load(file_name)
        if result:
            self._file_name = file_name
            if not self._file_watcher:
                # Watch file for changes and the directory for deletion.
                self._file_watcher = QFileSystemWatcher(self)
                self._file_watcher.fileChanged.connect(self.reload)
                self._file_watcher.directoryChanged.connect(self.directory_changed)
            self._file_watcher.addPath(self._file_name)
            self._file_watcher.addPath(os.path.dirname(self._file_name))
        return result

    @Slot()
    def reload(self) -> None:
        if not self._do_load(self._file_name):
            self.reset()

    def _do_load(self, file_name: str) -> bool:
        result = False
        try:
            with open(file_name, "r") as f:
                self.setPlainText(f.read())
                result = True
        except FileNotFoundError:
            pass
        return result

    @Slot()
    def directory_changed(self):
        if self._file_name and not os.path.exists(self._file_name):
            self.reset()
