from typing import List, Dict
import spacy
import json, os, jsonpath_ng, importlib
from etk.tokenizer import Tokenizer
from etk.document import Document
from etk.etk_exceptions import InvalidJsonPathError
from etk.extraction_module import ExtractionModule


class ETK(object):

    def __init__(self, kg_schema=None, modules=None):
        self.parser = jsonpath_ng.parse
        self.default_nlp = spacy.load('en_core_web_sm')
        self.default_tokenizer = Tokenizer(self.default_nlp)
        self.parsed = dict()
        self.kg_schema = kg_schema
        if modules:
            if isinstance(modules, ExtractionModule):
                self.em_lst = [modules]
            elif type(modules) == str:
                self.em_lst = self.load_ems(modules)

    def create_document(self, doc: Dict, mime_type: str=None, url: str="http://ex.com/123") -> Document:
        """
        Factory method to wrap input JSON docs in an ETK Document object.

        Args:
            doc (object): a JSON object containing a document in CDR format.
            mime_type (str): if doc is a string, the mime_type tells what it is
            url (str): if the doc came from the web, specifies the URL for it

        Returns: wrapped Document

        """
        return Document(self, doc, mime_type, url)

    def invoke_parser(self, jsonpath):
        if jsonpath not in self.parsed:
            try:
                self.parsed[jsonpath] = self.parser(jsonpath)
            except Exception:
                raise InvalidJsonPathError("Invalid Json Path")

        return self.parsed[jsonpath]

    def process_ems(self, doc: Document):
        for a_em in self.em_lst:
            if a_em.document_selector(doc):
                a_em.process_document(doc)

    @staticmethod
    def load_glossary(file_path: str) -> List[str]:
        """
        A glossary is a text file, one entry per line.

        Args:
            file_path (str): path to a text file containing a glossary.

        Returns: List of the strings in the glossary.
        """
        with open(file_path) as fp:
            return fp.read().splitlines()

    @staticmethod
    def load_spacy_rule(file_path: str) -> Dict:
        """
        A spacy rule file is a json file.

        Args:
            file_path (str): path to a text file containing a spacy rule sets.

        Returns: Dict as the representation of spacy rules
        """
        with open(file_path) as fp:
            return json.load(fp)

    @staticmethod
    def load_master_config(file_path: str) -> Dict:
        """
        A spacy rule file is a json file.

        Args:
            file_path (str): path to a text file containing a master config file.

        Returns: Dict as the representation of spacy rules
        """
        with open(file_path) as fp:
            return json.load(fp)

    def load_ems(self, modules_path: str):
        """
        Load all extraction modules from the path

        Args:
            modules_path: str

        Returns:

        """
        modules_path = modules_path.strip(".").strip("/")
        em_lst = []
        for file_name in os.listdir(modules_path):
            if file_name.startswith("em_") and file_name.endswith(".py"):
                this_module = importlib.import_module(modules_path + "." + file_name[:-3])
                for em in self.classes_in_module(this_module):
                    em_lst.append(em(self))

        return em_lst

    @staticmethod
    def classes_in_module(module):
        md = module.__dict__
        return [
            md[c] for c in md if (
            isinstance(md[c], type) and
            issubclass(md[c], ExtractionModule) and
            md[c].__module__ == module.__name__)
        ]

@@ -249,16 +249,30 @@
 nModule%0A
+import codecs%0A
 %0A%0Aclass 
@@ -822,17 +822,19 @@
 ype: str
-=
+ = 
 None, ur
@@ -839,17 +839,19 @@
 url: str
-=
+ = 
 %22http://
@@ -1816,24 +1816,41 @@
 le_path: str
+, read_json=False
 ) -%3E List%5Bst
@@ -2007,17 +2007,81 @@
 ossary.%0A
+            read_json (bool): set True if file is in json format
 %0A
-
         
@@ -2150,57 +2150,89 @@
     
-with open(file_path) as fp:%0A            return fp
+return json.load(codecs.open(file_path)) if read_json else codecs.open(file_path)
 .rea
@@ -3721,16 +3721,24 @@
         
+        
 isinstan
@@ -3753,24 +3753,32 @@
 , type) and%0A
+        
             
@@ -3813,24 +3813,32 @@
 Module) and%0A
+        
             

add optional parameter to read json as glossary, use codecs to open file