#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
*Advanced, Multi-Pass, Front Matter Editing Example*
=======================================================
.. module:: example2
:Program: example2
:Synopsis: Example program that performs the following actions:
    #. Derives a class from `EditFrontMatter`
    #. Performs execution in a try block
        #. raises an exception form the derived class for example purposes
        #. catches the exception and prints a messae
    #. Sets up a signal handler for `SIGHUP` and `SIGINT` for testing/example
    #. Set up a `try` block for catching exceptions: Can be tested by providing \
        a nonexistant file name for input
    #. Uses a Jinja2 template
        .. literalinclude:: ../../../../examples/data/template1.j2
            :language: jinja
    #. Reads a mardown file that contains yaml front matter via \
        :func:`editfrontmatter.EditFrontMatter.EditFrontMatter.readFile`
        .. literalinclude:: ../../../../examples/data/example1.md
            :language: md
    #. Extracts the front matter from the source file
    #. Prorammitically edits the front matter via \
        :func:`editfrontmatter.EditFrontMatter.EditFrontMatter.run`
    #. Concatinates the edited front matter with the original file content via \
        :func:`editfrontmatter.EditFrontMatter.EditFrontMatter.dumpFileData`
    #. Prints the edited file to `stdout`
    #. Resets the Jinja2 template for secondary processing
    #. Resets the input file for processing against a new template
        .. literalinclude:: ../../../../examples/data/template2.j2
            :language: jinja
    #. Reprocesses the previous output as input while concatinating the new input file
        .. literalinclude:: ../../../../examples/data/example2.md
            :language: md
    #. Prints the edited output to `stdout`
:Platform: Unix, Windows, |python_version|
:Dependencies:
    .. literalinclude:: ../../../../examples/requirements.txt
        :language: text
:License: :download:`MIT <../../../../LICENSE>`
.. :moduleauthor: `Karl N. Redman <https://karlredman.github.io>`_
:Author: `Karl N. Redman <https://karlredman.github.io>`_
:homepage: `EditFrontMatter Example 2 <https://karlredman.github.io/EditFrontMatter/examples/example2/readme.html>`_
:Current Release:
    version: |release|
.. versionadded:: 0.0.1
    Initial Version
"""
import os
import signal
from editfrontmatter import EditFrontMatter
from editfrontmatter import EditFrontMatter_Exception
# setup signal handler for kicks and giggles
[docs]class Signal_Caught(Exception):
    pass 
[docs]def SignalHandler(sig, frame):
    """Generic Signal handler"""
    message = ("Received signal {} on line {} in {}"
               .format(str(sig), str(frame.f_lineno), frame.f_code.co_filename))
    raise Signal_Caught(message) 
# catch signals
signal.signal(signal.SIGINT, SignalHandler)
signal.signal(signal.SIGHUP, SignalHandler)
# Derive class
[docs]class Derived_EditFrontMatter (EditFrontMatter):
    """EditFrontMatter derived class for example purposes"""
[docs]    def __init__(self, Superfluous, **kwargs):
        """A specialized signature for the derived class"""
        EditFrontMatter.__init__(self, **kwargs)
        self.Superfluous = Superfluous 
[docs]    def canPublish_method(self, var) -> bool:
        """Class level callback method
        Note:
            It's important that class level callbacks are codded to be reentrant.
            If the class is used in a threaded app class level veriables would not
            be thread-safe. Also, use critical sections if working with threads.
        Returns: a mock value
        """
        return "none"
        pass 
[docs]    def run(self, template_str, file_path, **kwargs) -> None:
        """A override method for the baseclass `run` method
        This is just a contrived example meant to demonstrate some advanced usage
        of the base class.
        """
        # update member vars
        self.template_str = template_str
        self.file_path = file_path
        # save file data and yaml object (fmatter) yaml_end point
        orig_file_lines = self.file_lines
        orig_yaml_obj = self.fmatter
        orig_yaml_end = self.yaml_end
        # read new (no front matter) file
        self.readFile(file_path)
        # replace filter with class method
        self.del_JinjaFilter('canPublish')
        self.add_JinjaFilter('canPublish', self.canPublish_method)
        # concatinate orig_file with new file
        orig_file_lines.append("\n")
        self.file_lines = orig_file_lines + self.file_lines
        # replace new yaml obj with original
        self.fmatter = orig_yaml_obj
        self.keys_toDelete = ['stuff']
        # procesess the data
        super().run(extraVars_dict={'weight': 10})
        # restore yaml_end so we can dump the file with the original end point
        # (.i.e so we can dump the new yaml with the old file content starting
        # point).
        self.yaml_end = orig_yaml_end 
[docs]    def parent_run(self, extra_vars):
        """cheezy method to call a parent method"""
        super().run(extra_vars)  
# callback function for jinja filter
[docs]def canPublish_func(var) -> bool:
    """Callback function for Jinja2 filters"""
    # ...do processing
    return True 
[docs]def main():
    """Main function
    Attributes:
        DATA_PATH (str):
            Path that points to the data file directory. Must end with a `/`
        file_path1 (str):
            Path to input source 1
        file_path2 (str):
            Path to input source 2
        template_str1 (str):
            Contents of template1
        template_str2 (str):
            Contents of template2
    :envvar: TEST_DATA_DIR
        Variable used to specify the path to the data files.
    Returns:
        program exit status (0 or 1)
    Example:
        To run from a non program directory use the environment variable::
            TEST_DATA_DIR="./data/" example2/example2.py
    """
    # generic path - overridden by env var `TEST_DATA_DIR`
    DATA_PATH = "../data/"
    if "TEST_DATA_DIR" in os.environ:
        DATA_PATH = os.path.abspath(os.environ.get("TEST_DATA_DIR")) + "/"
    # set path to input file
    file_path1 = os.path.abspath(DATA_PATH + "example1.md")
    file_path2 = os.path.abspath(DATA_PATH + "example2.md")      # no front matter
    # initialize `template_str` with template file content
    template_str1 = ''.join(open(os.path.abspath(DATA_PATH + "template1.j2"), "r").readlines())
    template_str2 = ''.join(open(os.path.abspath(DATA_PATH + "template2.j2"), "r").readlines())
    # create object
    proc = Derived_EditFrontMatter(None, template_str=template_str1, do_readFile=False)
    # add jinja filter for callback
    proc.add_JinjaFilter('canPublish', canPublish_func)
    try:
        # normal processing
        proc.readFile(file_path=file_path1)
        proc.parent_run({'toc': 'no effect', 'hasMath': "false",
                         'addedVariable': ['one', 'two', 'three']})
        print(proc.dumpFileData())
        print("##################### PASS SEPERATION #######################")
        # new swap the template
        proc.run(template_str2, file_path2)
        print(proc.dumpFileData())
    except Signal_Caught as e:
        print(str(e))
        os.exit(1)
    except EditFrontMatter_Exception as e:
        print(str(e))
        os.exit(1)
    else:
        print("No Exceptions.")
    finally:
        print("done.")
    print("end program") 
if __name__ == '__main__':
    main()