# AUTOGENERATED! DO NOT EDIT! File to edit: ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb.

# %% auto 0
__all__ = ['PersonalNoteTypeEnum', 'type_of_note', 'note_is_of_type', 'NoteTypeError', 'assert_note_is_of_type']

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 3
from deprecated import deprecated
from enum import Enum, auto
import os
from pathlib import Path
from typing import Optional, Union
import warnings

from trouver.helper import (
    file_existence_test
)
from trouver.markdown.obsidian.vault import (
    note_path_by_name, note_name_unique, VaultNote, NoteDoesNotExistError
)

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 6
# TODO: Make these methods private.
def _is_index_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be an index note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function only looks at the file name, so it may return
    incorrect results if the note is named incorrectly.
    """
    # file = file_existence_test(file, vault)
    return vault_note.name.startswith('_index')


def _is_index_of_notation_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be an index of notation note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function only looks at the file name, so it may return
    incorrect results if the note is named incorrectly.
    """
    return vault_note.name.startswith('_notation')


def _is_standard_information_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be a standard information note.

    This function looks for some headings to verify that the note
    is a standard information note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function may return incorrect results, especially
    false negatives.
    - This function returns True if a few tests pass, but will
    also print out a warning with the the note name if not enough
    tests pass.
    """
    # file = file_existence_test(file, vault)
    if (_is_index_of_notation_note(vault_note)
        or _is_template_note(vault_note)):
        return False
    # TODO
    text = vault_note.text()
    tokens = ['# Meta', '## References',
              '## Citations and Footnotes']
    passes = [x in text for x in tokens]
    total_passes = sum(passes)
    if total_passes == 0:
        return False
    elif total_passes <= 2:
        warnings.warn('The following file seems to be a standard information'
                      f' note, but this is ambiguous: {vault_note.name}')
    return True


# TODO: delete
@deprecated
def _is_module_information_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be a module information note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function may return incorrect results.
    """
    # TODO figure out which files the card is embedded in
    return 


def _is_notation_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be a notation note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function looks at the file name, so it may return
    incorrect results if the note is named incorrectly.
    """
    if (_is_index_of_notation_note(vault_note)
            or _is_standard_information_note(vault_note)):
        return False
    return 'notation' in vault_note.name


def _is_premise_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be a premise note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function may return incorrect results.
    """
    # TODO figure out which files the card is embedded in
    # TODO test
    return 'premise' in vault_note.name


def _is_common_terms_note(vault_note: VaultNote) -> bool:
    """Returns `True` if the markdown file is determined to
    be a common terms note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function only looks at the file name, so it may return
    incorrect results if the note is named incorrectly.
    """
    return vault_note.name.startswith('_common_terms')


def _is_template_note(vault_note: VaultNote):
    """Returns `True` if the markdown file is determined to
    be a template note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function only looks at the file name, so it may return
    incorrect results if the note is named incorrectly.
    """
    return vault_note.name.startswith('_template')


# TODO: delete
@deprecated
def _is_tag_note(vault_note: VaultNote):
    return


def _is_notes_note(vault_note: VaultNote):
    # TODO
    """Returns `True` if the markdown file is determined to
    be a notes note.

    A notes note usually is self-written.
    
    """
    return


def _is_mathematician_note(vault_note: VaultNote):
    """Returns `True` if the markdown file is determined to
    be a mathematician note.

    **Parameters**
    - `vault_note` - VaultNote
    
    **Returns**
    - `bool`
    
    **Notes**
    - This function only looks for headers `# Basic` and
    `# Notables`, so it may return incorrect results if the
    note is formatted incorrectly.
    """
    text = vault_note.text()
    tokens = ['# Basic', '# Notables']
    passes = [x in text for x in tokens]
    total_passes = sum(passes)
    return total_passes != 0


def _is_equation_note(vault_note: VaultNote):
    # TODO
    return


def _is_reference_note(vault_note: VaultNote):
    return vault_note.name.startswith('_reference')


def _is_glossary_note(vault_note: VaultNote):
    return vault_note.name.startswith('_glossary')

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 8
class PersonalNoteTypeEnum(Enum):
    """
    An Enum class for note types in my Obsidian math vault
    
    """
    INDEX_NOTE = auto()
    STANDARD_INFORMATION_NOTE = auto()
    MODULE_INFORMATION_NOTE = auto()
    INDEX_OF_NOTATION_NOTE = auto()
    NOTATION_NOTE = auto()
    PREMISE_NOTE = auto()
    COMMON_TERMS_NOTE = auto()
    TEMPLATE_NOTE = auto()
    TAG_NOTE = auto()
    NOTES_NOTE = auto()
    MATHEMATICIAN_NOTE = auto()
    EQUATION_NOTE = auto()
    REFERENCE_NOTE = auto()
    GLOSSARY_NOTE = auto()
    
    @classmethod
    def type_function(cls, note_type: 'PersonalNoteTypeEnum'):
        return cls._type_method_dict[note_type]


PersonalNoteTypeEnum._type_method_dict = {
    PersonalNoteTypeEnum.INDEX_NOTE: _is_index_note,
    PersonalNoteTypeEnum.STANDARD_INFORMATION_NOTE: _is_standard_information_note,
    PersonalNoteTypeEnum.MODULE_INFORMATION_NOTE: _is_module_information_note,
    PersonalNoteTypeEnum.INDEX_OF_NOTATION_NOTE: _is_index_of_notation_note,
    PersonalNoteTypeEnum.NOTATION_NOTE: _is_notation_note,
    PersonalNoteTypeEnum.PREMISE_NOTE: _is_premise_note,
    PersonalNoteTypeEnum.COMMON_TERMS_NOTE: _is_common_terms_note,
    PersonalNoteTypeEnum.TEMPLATE_NOTE: _is_template_note,
    PersonalNoteTypeEnum.TAG_NOTE: _is_tag_note,
    PersonalNoteTypeEnum.NOTES_NOTE: _is_notes_note,
    PersonalNoteTypeEnum.MATHEMATICIAN_NOTE: _is_mathematician_note,
    PersonalNoteTypeEnum.EQUATION_NOTE: _is_equation_note,
    PersonalNoteTypeEnum.REFERENCE_NOTE: _is_reference_note,
    PersonalNoteTypeEnum.GLOSSARY_NOTE: _is_glossary_note
}

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 11
def type_of_note(
        vault_note: VaultNote
        ) -> PersonalNoteTypeEnum:
    """Returns the type of the specified note.

    Assumes that `vault_note` represents an existing note.

    **Notes**
    - This function may return incorrect or unintended results,
    depending on the formatting or existence of the file.
    
    **Raises**
    - NoteDoesNoteExistError
        - If `vault_note` does not exist.
    """
    if not vault_note.exists():
        raise NoteDoesNotExistError(vault_note.name)
    for note_type in PersonalNoteTypeEnum:
        type_function = PersonalNoteTypeEnum.type_function(note_type)
        if type_function(vault_note):
            return note_type

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 12
def note_is_of_type(
        vault_note: VaultNote,
        note_type: Optional[PersonalNoteTypeEnum] # The type of note. If `None`, then any type of note; in this case, returns whether or not the note exists.
        ) -> bool:
    """Returns `True` if the Markdown vault note exists and is determined to
    be of the specified type.

    Assumes that `vault_note` represents an existing note.
    
    **Notes**
    - This function may return incorrect results, depending on the 
    formatting of the file.

    **Raises**
    - NoteDoesNoteExistError
        - If `vault_note` does not exist.
    """
    if not vault_note.exists():
        return False
    return type_of_note(vault_note) == note_type if note_type else True

# %% ../../../../nbs/14_markdown.obsidian.personal.note_type.ipynb 18
class NoteTypeError(ValueError):
    """Exception raised when the type of note is not of the expected type.
    
    **Attributes**
    - `note` - VaultNote
    - `expected_note_type` - PersonalNoteTypeEnum
    """
    def __init__(
            self,
            note: VaultNote,
            expected_note_type: PersonalNoteTypeEnum):
        self.note = note
        self.expected_note_type = expected_note_type
        super().__init__(
            f"Expected a note of type {expected_note_type}, "
            f"but got a note of a different type instead: {note.name}")


def assert_note_is_of_type(
        note: VaultNote,
        expected_type: PersonalNoteTypeEnum):
    """Raises a `NoteTypeError` if the note is not of the
    expected type.
    
    **Raises**
    - NoteTypeError
        - If the type of `note` is not `expected_type`.
    """
    if not note_is_of_type(note, expected_type):
        raise NoteTypeError(note, expected_type)
