# Copyright (c) 2021 <NAME>. All rights reserved.
from __future__ import annotations
import abc
import asyncio


class AbstractApplication(abc.ABC):
    @abc.abstractmethod
    def run(self) -> None:
        """Run the application forever."""

    @abc.abstractmethod
    async def run_async(self) -> None:
        """Run the application asynchronously."""

    @abc.abstractmethod
    def quit(self) -> None:
        """Stop the application."""


class BaseApplication(AbstractApplication):
    _stop_event: asyncio.Event

    def run(self) -> None:
        try:
            loop = asyncio.get_event_loop()
            loop.run_until_complete(self.run_async())
        except RuntimeError:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(self.run_async())
            loop.stop()
            loop.close()

    async def run_async(self) -> None:
        self._stop_event = asyncio.Event()
        try:
            await self._stop_event.wait()
        except asyncio.exceptions.CancelledError:
            pass
        finally:
            del self._stop_event

    def quit(self) -> None:
        if hasattr(self, "_stop_event"):
            self._stop_event.set()
        else:
            raise RuntimeError("The application is not running")

# Copyright (c) 2021 <NAME>. All rights reserved.
from __future__ import annotations
import abc
import asyncio


class AbstractApplication(abc.ABC):
    @abc.abstractmethod
    def run(self) -> None:
        """Run the application forever."""

    @abc.abstractmethod
    async def run_async(self) -> None:
        """Run the application asynchronously."""

    @abc.abstractmethod
    def quit(self) -> None:
        """Stop the application."""


class BaseApplication(AbstractApplication):
    _stop_event: asyncio.Event

    def run(self) -> None:
        try:
            loop = asyncio.get_event_loop()
            loop.run_until_complete(self.run_async())
        except RuntimeError:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(self.run_async())
            loop.stop()
            loop.close()

    async def run_async(self) -> None:
        self._stop_event = asyncio.Event()
        try:
            await self._stop_event.wait()
        except asyncio.exceptions.CancelledError:
            pass
        finally:
            del self._stop_event

    def quit(self) -> None:
        if hasattr(self, "_stop_event"):
            self._stop_event.set()
        else:
            raise RuntimeError("The application is not running")

# Copyright (c) 2021 <NAME>. All rights reserved. Run the application forever. Run the application asynchronously. Stop the application.