#!/usr/bin/env python3

'''
  @file
  @ingroup <<<GROUP>>>
  @brief   <<<BRIEF>>>

           This code is Autogenerated from '<<<PYIFGENNAME>>>' with the MIT License.
           As such, please only hand-code within 'USER' tags.

  @author  <<<AUTHOR>>>
'''

import unittest
import threading
import queue

from <<<STATEMACHINENAME>>>Controller import *
from <<<STATEMACHINENAME>>>StateMachine import *
# {{{USER_IMPORTS}}}
# {{{USER_IMPORTS}}}

class Test<<<STATEMACHINENAME>>>Controller(<<<STATEMACHINENAME>>>Controller):
    ## Test context constructor.
    def __init__(self):
        <<<STATEMACHINENAME>>>Controller.__init__(self)
        # {{{USER_CONSTRUCTOR}}}
        # {{{USER_CONSTRUCTOR}}}

    # Overridden guards.
    #
    <<<PER_GUARD_BEGIN>>>
    def <<<GUARDNAME>>>(self, event) -> bool:
        # {{{USER_<<<GUARDNAME>>>}}}
        # {{{USER_<<<GUARDNAME>>>}}}
        return <<<STATEMACHINENAME>>>Controller.<<<GUARDNAME>>>(self, event)
    <<<PER_GUARD_END>>>

    ## Overridden on state entry/exit.
    #
    <<<PER_STATE_BEGIN>>>
    def On<<<STATENAME>>>Entry(self, event) -> None:
        <<<STATEMACHINENAME>>>Controller.On<<<STATENAME>>>Entry(self, event)
        # {{{USER_<<<STATENAME>>>_on_entry}}}
        # {{{USER_<<<STATENAME>>>_on_entry}}}

    def On<<<STATENAME>>>Exit(self, event) -> None:
        <<<STATEMACHINENAME>>>Controller.On<<<STATENAME>>>Exit(self, event)
        # {{{USER_<<<STATENAME>>>_on_exit}}}
        # {{{USER_<<<STATENAME>>>_on_exit}}}
    <<<PER_STATE_END>>>

    ## Overridden actions.
    # </summary>
    <<<PER_ACTION_BEGIN>>>
    def <<<ACTIONNAME>>>(self, event) -> None:
        <<<STATEMACHINENAME>>>Controller.<<<ACTIONNAME>>>(self, event);
        # {{{USER_<<<ACTIONNAME>>>_<<<EVENTNAME>>>}}}
        # {{{USER_<<<ACTIONNAME>>>_<<<EVENTNAME>>>}}}
    <<<PER_ACTION_END>>>
    # {{{USER_MEMBERS}}}
    # {{{USER_MEMBERS}}}

## Python Unittest
class Test<<<STATEMACHINENAME>>>(unittest.TestCase):

    def setUp(self):
        self.context = Test<<<STATEMACHINENAME>>>Controller()
        self.sm = <<<STATEMACHINENAME>>>StateMachine(self.context)

    def test_states(self):
        # {{{USER_UNIT_TEST_STATES}}}
        # {{{USER_UNIT_TEST_STATES}}}
        pass

## Console Runner Exit
#
class Exit(Exception):
    pass

## Console Runner Test Suite
# Run a statemachine on the console taking keypresses as events.
#
class ConsoleRunner(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.context = Test<<<STATEMACHINENAME>>>Controller()
        self.sm = <<<STATEMACHINENAME>>>StateMachine(self.context)
        self.__runThreaded = True
        self.__fifoQueue = queue.Queue()  # threadsafe by default.
        # {{{USER_CONSOLE_RUNNER}}}
        # {{{USER_CONSOLE_RUNNER}}}
        self.start()

    ## @brief Threading
    #
    # @{
    def run(self) -> None:
        while self.__runThreaded:
            try:
                event = self.__fifoQueue.get(block=True, timeout=5)  # 5s timeout for graceful shutdown.
                self.process(event)
                self.__fifoQueue.task_done()
            except queue.Empty:
                pass

    def stop(self) -> None:
        self.sm.stop()
        if self.__runThreaded:
            self.__runThreaded = False
            self.__fifoQueue.join()
            self.join()
    # @}

    def printHelp(self):
        print("##############################################")
        <<<PER_EVENT_BEGIN>>>
        print("<<<ALPH>>>      : send <<<EVENTNAME>>> event.")
        <<<PER_EVENT_END>>>
        <<<PER_GUARD_BEGIN>>>
        print('g<<<NUM>>>=0/1 : set <<<GUARDNAME>>> to false/true')
        <<<PER_GUARD_END>>>
        print("H      : print this HELP.")
        print("exit   : EXIT the console runner.")
        print("##############################################")

    def processConsoleInput(self, input):
        <<<PER_EVENT_BEGIN>>>
        if input == '<<<ALPH>>>':
            self.sm.Trigger<<<EVENTNAME>>>(<<<SIGNATUREWITHDEFAULTS>>>)
            return
        <<<PER_EVENT_END>>>
        <<<PER_GUARD_BEGIN>>>
        if 'g<<<NUM>>>=' in input:
            input = input.replace('g<<<NUM>>>=', '').strip()
            self.context.<<<guardName>>> = False if '0' in input else True
            print ("<<<guardName>>> set as ", "false" if not self.context.<<<guardName>>> else "true")
            return
        <<<PER_GUARD_END>>>
        if input == 'H':
            self.printHelp()
            return
        if input == 'exit':
            raise Exit
        print("'", input, '" not defined.')
    

    def startConsole(self):
        import sys
        self.printHelp()
        try:
            for line in sys.stdin:
                line = line.replace("\n", "")
                for var in line.split():
                    self.processConsoleInput(var)
        except Exit:
            print("Goodbye...")

    # {{{USER_TESTS}}}
    # {{{USER_TESTS}}}

if __name__ == '__main__':
    testrunner = ConsoleRunner()
    # {{{USER_MAIN}}}
    # {{{USER_MAIN}}}
    testrunner.startConsole()
    testrunner.stop()