from typing import overload, List
from pathlib import Path
import json
import re


class CompilationDatabase:
    @overload
    def __init__(self, database: str) -> None:
        ...
    @overload
    def __init__(self, database: List[dict]) -> None:
        ...
    def __init__(self, database):
        if type(database) is str:
            path = Path(database).expanduser()
            with open(path.resolve(), 'r') as f:
                self._database = json.loads(f.read())
        else:
            self._database = database

    def __str__(self):
        return json.dumps(self._database, indent=2)

    def _get_flags_from_command(self, command: str) -> List[str]:
        pattern = re.compile(".*  (.*?) -o.* -c")
        result = re.search(pattern, command)
        if result is not None:
            flags = result.group(1).split(" ")
        else:
            flags = command.split(" ")
        return flags

    def _get_include_flags_from_command(self, command: str) -> List[str]:
        pattern = re.compile("(-I.*?) ")
        flags = re.findall(pattern, command)
        pattern = re.compile("(-isystem .*?) ")
        for item in re.findall(pattern, command):
            flags.append(re.sub("-isystem ", "-I", item))
        return flags

    def _remove_duplicates(self, flags: List[str]) -> List[str]:
        return list(dict.fromkeys(flags))

    def get_all_include_flags(self) -> List[str]:
        flags = []
        for item in self._database:
            flags += self._get_include_flags_from_command(item["command"])
        flags = self._remove_duplicates(flags)
        return flags

    def get_file_flags(self, filename: str) -> List[str]:
        flags = []
        for item in self._database:
            if Path(item["file"]).resolve() == Path(filename).resolve():
                flags += self._get_flags_from_command(item["command"])
        flags = self._remove_duplicates(flags)
        return flags

    def remove_flags(self, flags: List[str]) -> List[dict]:
        for item in self._database:
            for flag in flags:
                pattern = re.compile(r"%s ?" % flag, flags=re.MULTILINE)
                command = re.sub(pattern, "", item["command"])
                item["command"] = command
        return self._database

    def add_flags(self, flags: List[str]) -> List[dict]:
        for item in self._database:
            pattern = re.compile(r"-o .*-c")
            match = re.search(pattern, item["command"])
            if match is not None:
                position = match.start(0)
                insert = " ".join([str(flag) for flag in flags]) + " "
                item["command"] = item["command"][:position] + insert + item["command"][position:]
        return self._database

from typing import overload, List
from pathlib import Path
import json
import re


class CompilationDatabase:
    @overload
    def __init__(self, database: str) -> None:
        ...
    @overload
    def __init__(self, database: List[dict]) -> None:
        ...
    def __init__(self, database):
        if type(database) is str:
            path = Path(database).expanduser()
            with open(path.resolve(), 'r') as f:
                self._database = json.loads(f.read())
        else:
            self._database = database

    def __str__(self):
        return json.dumps(self._database, indent=2)

    def _get_flags_from_command(self, command: str) -> List[str]:
        pattern = re.compile(".*  (.*?) -o.* -c")
        result = re.search(pattern, command)
        if result is not None:
            flags = result.group(1).split(" ")
        else:
            flags = command.split(" ")
        return flags

    def _get_include_flags_from_command(self, command: str) -> List[str]:
        pattern = re.compile("(-I.*?) ")
        flags = re.findall(pattern, command)
        pattern = re.compile("(-isystem .*?) ")
        for item in re.findall(pattern, command):
            flags.append(re.sub("-isystem ", "-I", item))
        return flags

    def _remove_duplicates(self, flags: List[str]) -> List[str]:
        return list(dict.fromkeys(flags))

    def get_all_include_flags(self) -> List[str]:
        flags = []
        for item in self._database:
            flags += self._get_include_flags_from_command(item["command"])
        flags = self._remove_duplicates(flags)
        return flags

    def get_file_flags(self, filename: str) -> List[str]:
        flags = []
        for item in self._database:
            if Path(item["file"]).resolve() == Path(filename).resolve():
                flags += self._get_flags_from_command(item["command"])
        flags = self._remove_duplicates(flags)
        return flags

    def remove_flags(self, flags: List[str]) -> List[dict]:
        for item in self._database:
            for flag in flags:
                pattern = re.compile(r"%s ?" % flag, flags=re.MULTILINE)
                command = re.sub(pattern, "", item["command"])
                item["command"] = command
        return self._database

    def add_flags(self, flags: List[str]) -> List[dict]:
        for item in self._database:
            pattern = re.compile(r"-o .*-c")
            match = re.search(pattern, item["command"])
            if match is not None:
                position = match.start(0)
                insert = " ".join([str(flag) for flag in flags]) + " "
                item["command"] = item["command"][:position] + insert + item["command"][position:]
        return self._database
