#!/bin/python3

"""
Usage:

Search dependency name from dll name:

./tools/deps_search.py search mfc140u

Detect missing dependency from wine logs:

./tools/deps_search.py detect /path/to/wine/error/logs

or using with pipe

deepin-wine8-stable spyxx.exe 2>&1 | ./tools/deps_search.py detect -
"""

import sys
import pathlib
import argparse

pkgdatadir="/opt/apps/deepin-wine-builder/files/share/deepin-wine-builder"
if not pkgdatadir.startswith('/'):
    pkgdatadir = pathlib.Path(__file__).parent.parent.absolute().as_posix()
sys.path.insert(1, pkgdatadir)
sys.path.insert(1, pkgdatadir + '/../../lib/python3/dist-packages')


from typing import IO
from bottles.backend.utils.singleton import Singleton
from bottles.backend.utils.deps_searcher import DepsSearcher
from deepin.installer.private import ProgramsPrivate

class Programs(ProgramsPrivate, metaclass=Singleton):
    """
    Tools to search dependency from dllname or wine import log error
    """
    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)
        self.root_dir = pkgdatadir
        self._init_installer()
        self.deps_searcher = DepsSearcher(self.dependency_manager)

        self._init_args()

    def _init_args(self):
        self.parser = argparse.ArgumentParser("Tools to search missing dependency")

        command_parser = self.parser.add_subparsers(dest="command", help="sub-command")
        search_parser = command_parser.add_parser("search", help="search dependency from dll names")
        search_parser.add_argument("name", help="dll name, for example mfc40", nargs="*")

        detech_parser = command_parser.add_parser(
            "detect",
            help="detect missing dependency from wine error logs"
        )
        detech_parser.add_argument(
            "path",
            help="path of wine error logs, read from stdin if path is '-'",
        )

        command_parser.add_parser(
            "dump"
        )

        self.args = self.parser.parse_args()

        if self.args.command == "search":
            self._search_dlls()
        elif self.args.command == "detect":
            self._detech_logs()
        elif self.args.command == "dump":
            print(self.deps_searcher.dump_deps())

    def _search_dlls(self):
        if len(self.args.name) == 0:
            sys.stderr.writelines([
                "dll name required, for example:",
                "deps_search search dmime riched20 mfc40"
            ])
            sys.exit(1)

        searcher = DepsSearcher(self.dependency_manager)
        res = {}

        for dllname in self.args.name:
            deps_ret = searcher.from_dllname(dllname)
            for dll, dep in deps_ret.items():
                res[dll] = dep

        for dll, dep in res.items():
            print(dll, ":", dep)

    def _detech_logs(self):
        stream: IO

        if self.args.path == "-":
            stream = sys.stdin
        else:
            stream = open(self.args.path, encoding="utf-8")

        deps = DepsSearcher(self.dependency_manager).from_winelog_stream(stream)

        if len(deps) == 0:
            print("can't find missing dependencies from wine error logs")
        else:
            print("missing deps:")

        for dll in deps:
            print(dll, ":", deps.get(dll, []))

        stream.close()

if __name__ == "__main__":
    programs = Programs()
