import os
import logging

from lighthouse.util.qt import *
from lighthouse.painting import CoveragePainter
from lighthouse.director import CoverageDirector
from lighthouse.coverage import DatabaseCoverage
from lighthouse.metadata import DatabaseMetadata

from lighthouse.util.disassembler import disassembler, DisassemblerContextAPI

logger = logging.getLogger("Lighthouse.Context")

#------------------------------------------------------------------------------
# Lighthouse Session Context
#------------------------------------------------------------------------------

class LighthouseContext(object):
    """
    A database/binary-unique instance of Lighthouse and its subsystems.
    """

    def __init__(self, core, dctx):
        disassembler[self] = DisassemblerContextAPI(dctx)
        self.core = core
        self.dctx = dctx
        self._started = False

        # the database metadata cache
        self.metadata = DatabaseMetadata(self)

        # the coverage engine
        self.director = CoverageDirector(self.metadata, self.core.palette)

        # the coverage painter
        self.painter = CoveragePainter(self, self.director, self.core.palette)

        # the coverage overview widget
        self.coverage_overview = None

        # the directory to start the coverage file dialog in
        self._last_directory = None

    @property
    def palette(self):
        return self.core.palette

    def start(self):
        """
        One-time activation a Lighthouse context and its subsystems.
        """
        if self._started:
            return
        self.core.palette.warmup()
        self.metadata.start()
        self.director.start()
        self.painter.start()

        # TODO/BINJA remove this ASAP, or find a better workaround... I hate having this here
        if disassembler.NAME == "BINJA":
            disassembler.hide_dockable("Feature Map")

        self._started = True

    def terminate(self):
        """
        Spin down any session subsystems before the session is deleted.
        """
        if not self._started:
            return
        self.painter.terminate()
        self.director.terminate()
        self.metadata.terminate()

    def select_coverage_files(self):
        """
        Prompt a file selection dialog, returning file selections.

        NOTE: This saves & reuses the last known directory for subsequent uses.
        """
        if not self._last_directory:
            self._last_directory = disassembler[self].get_database_directory()

        # create & configure a Qt File Dialog for immediate use
        file_dialog = QtWidgets.QFileDialog(
            None,
            'Open code coverage file',
            self._last_directory,
            'All Files (*.*)'
        )
        file_dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles)

        # prompt the user with the file dialog, and await filename(s)
        filenames, _ = file_dialog.getOpenFileNames()

        #
        # remember the last directory we were in (parsed from a selected file)
        # for the next time the user comes to load coverage files
        #

        if filenames:
            self._last_directory = os.path.dirname(filenames[0]) + os.sep

        # log the captured (selected) filenames from the dialog
        logger.debug("Captured filenames from file dialog:")
        for name in filenames:
            logger.debug(" - %s" % name)

        # return the captured filenames
        return filenames

