from casbin import persist
from casbin import model
from .file_adapter import FileAdapter
import os


class Filter:
    # P,G are string []
    P = []
    G = []


class FilteredAdapter(FileAdapter, persist.FilteredAdapter):
    filtered = False
    _file_path = ""
    filter = Filter()
    # new_filtered_adapte is the constructor for FilteredAdapter.
    def __init__(self, file_path):
        self.filtered = True
        self._file_path = file_path

    def load_policy(self, model):
        if not os.path.isfile(self._file_path):
            raise RuntimeError("invalid file path, file path cannot be empty")
        self.filtered = False
        self._load_policy_file(model)

    # load_filtered_policy loads only policy rules that match the filter.
    def load_filtered_policy(self, model, filter):
        if filter == None:
            return self.load_policy(model)

        if not os.path.isfile(self._file_path):
            raise RuntimeError("invalid file path, file path cannot be empty")

        try:
            filter_value = [filter.__dict__["P"]] + [filter.__dict__["G"]]
        except:
            raise RuntimeError("invalid filter type")

        self.load_filtered_policy_file(model, filter_value, persist.load_policy_line)
        self.filtered = True

    def load_filtered_policy_file(self, model, filter, hanlder):
        with open(self._file_path, "rb") as file:
            while True:
                line = file.readline()
                line = line.decode().strip()
                if line == "\n":
                    continue
                if not line:
                    break
                if filter_line(line, filter):
                    continue

                hanlder(line, model)

    # is_filtered returns true if the loaded policy has been filtered.
    def is_filtered(self):
        return self.filtered

    def save_policy(self, model):
        if self.filtered:
            raise RuntimeError("cannot save a filtered policy")

        self._save_policy_file(model)


def filter_line(line, filter):
    if filter == None:
        return False

    p = line.split(",")
    if len(p) == 0:
        return True
    filter_slice = []

    if p[0].strip() == "p":
        filter_slice = filter[0]
    elif p[0].strip() == "g":
        filter_slice = filter[1]
    return filter_words(p, filter_slice)


def filter_words(line, filter):
    if len(line) < len(filter) + 1:
        return True
    skip_line = False
    for i, v in enumerate(filter):
        if len(v) > 0 and (v.strip() != line[i + 1].strip()):
            skip_line = True
            break

    return skip_line
