#!python
# This file is placed in the Public Domain.


import os
import sys
import threading
import time


sys.path.insert(0, os.getcwd())


from bigtalk.clients import CLI
from bigtalk.command import Commands
from bigtalk.kernels import Config, Kernel
from bigtalk.message import Message
from bigtalk.methods import Methods
from bigtalk.package import Mods
from bigtalk.statics import SYSTEMD
from bigtalk.utility import Utils
from bigtalk.workdir import Workdir


Config.ignore = "wsd,udp"
Config.level = "info"
Config.name = "bigtalk" 
Config.version = 2


class CLI(CLI):

    def raw(self, text):
        print(text.encode('utf-8', 'replace').decode("utf-8"))


class Console(CLI):

    def callback(self, event):
        if not event.text:
            return
        super().callback(event)
        event.wait()

    def poll(self):
        evt = Message()
        evt.text = input("> ")
        evt.kind = "command"
        return evt


class Runtime:

    @staticmethod
    def banner():
        tme = time.ctime(time.time()).replace("  ", " ")
        print("%s %s since %s (%s)" % (
                                       Config.name.upper(),
                                       Config.version,
                                       tme,
                                       Config.level.upper()
                                      ))
        sys.stdout.flush()

    @staticmethod
    def check(text):
        args = sys.argv[1:]
        for arg in args:
            if not arg.startswith("-"):
                continue
            for char in text:
                if char in arg:
                   return True

        return False

    @staticmethod
    def daemon(verbose=False, nochdir=False):
        pid = os.fork()
        if pid != 0:
            os._exit(0)
        os.setsid()
        pid2 = os.fork()
        if pid2 != 0:
            os._exit(0)
        if not verbose:
            with open('/dev/null', 'r', encoding="utf-8") as sis:
                os.dup2(sis.fileno(), sys.stdin.fileno())
            with open('/dev/null', 'a+', encoding="utf-8") as sos:
                os.dup2(sos.fileno(), sys.stdout.fileno())
            with open('/dev/null', 'a+', encoding="utf-8") as ses:
                os.dup2(ses.fileno(), sys.stderr.fileno())
        if not nochdir:
            os.umask(0)
            os.chdir("/")
        os.nice(10)

    @staticmethod
    def privileges():
        import getpass
        import pwd
        pwnam2 = pwd.getpwnam(getpass.getuser())
        os.setgid(pwnam2.pw_gid)
        os.setuid(pwnam2.pw_uid)

    @staticmethod
    def wrap(func):
        import termios
        old = None
        try:
            old = termios.tcgetattr(sys.stdin.fileno())
        except termios.error:
            pass
        try:
            Utils.wrapped(func)
        finally:
            if old:
                termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old)


class Scripts:

    @staticmethod
    def background():
        Runtime.daemon(check("v"), check("m"))
        Runtime.privileges()
        Workdir.pidfile(Workdir.pidname(Config.name))
        Commands.add(Cmds.cmd, Cmds.ver)
        Kernel.scanner(Mods.list() or "irc,rss")
        Kernel.init(Mods.list() or "irc,rss")
        Kernel.forever()

    @staticmethod
    def console():
        import readline
        Runtime.banner()
        Methods.parse(Config, " ".join(sys.argv[1:]))
        if "a" in Config.opts:
            Config.init = Mods.list()
        else:
            Config.init = Config.sets.init or Config.init
        Kernel.scanner(Config.init)
        Commands.add(Cmds.cmd, Cmds.ver)
        Kernel.init(Config.init, "w" in Config.opts)
        csl = Console()
        csl.start()
        Kernel.forever()

    @staticmethod
    def control():
        if len(sys.argv) == 1:
            return
        Kernel.scanner(Mods.list())
        Commands.add(Cmds.cmd, Cmds.srv, Cmds.ver)
        csl = CLI()
        csl.silent = False
        evt = Message()
        evt.orig = repr(csl)
        evt.text = " ".join(sys.argv[1:])
        evt.type = "command"
        Commands.command(evt)
        evt.wait()

    @staticmethod
    def service():
        Runtime.privileges()
        Workdir.pidfile(Utils.pidname(Config.name))
        Kernel.scanner(Config.init or "irc,rss")
        Commands.add(Cmds.cmd, Cmds.ver)
        Kernel.init(Config.init or "irc,rss")
        Kernel.forever()


class Cmds:

    @staticmethod
    def cmd(event):
        event.reply(",".join(sorted(Commands.names or Commands.cmds)))

    @staticmethod
    def srv(event):
        import getpass
        name = getpass.getuser()
        event.reply(SYSTEMD % (Config.name.upper(), name, name, name, Config.name))

    @staticmethod
    def ver(event):
        event.reply(f"{Config.name.upper()} {Config.version}")


def main():
    check = Runtime.check
    Kernel.configure(check("m"), check("n"))
    if check("b"):
        threading.excepthook = threadhook
    if check('z'):
        Config.debug = True
    if check("c"):
        Runtime.wrap(Scripts.console)
    elif check("d"):
        Scripts.background()
    elif check("s"):
        Utils.wrapped(Scripts.service)
    else:
        Utils.wrapped(Scripts.control)


if __name__ == "__main__":
    main()
