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


import os
import sys
import time


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


from nixt.command import Commands, enable, command
from nixt.configs import Config
from nixt.defines import SYSTEMD
from nixt.handler import CLI
from nixt.kernels import boot, forever, init, pidfile, scanner, wrapped
from nixt.message import Message
from nixt.package import Mods, modules
from nixt.workdir import Workdir, moddir, pidname


"defines"


Config.ignore = "rst,web,wsd,udp"
Config.level = "info"
Config.name = "nixt" 
Config.version = 440


Workdir.wdr = os.path.expanduser(f"~/.{Config.name}")
sys.path.insert(0, Workdir.wdr)


try:
    import mods as MODS
except ModuleNotFoundError:
    MODS = None


"clients"


class Line(CLI):

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


class Console(Line):

    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


"scripts"


TXT = " ".join(sys.argv[1:])


def background():
    daemon(check("v"), check("m"))
    privileges()
    boot(TXT)
    pidfile(pidname(Config.name))
    scanner(MODS)
    enable(cmd, mod, ver)
    init(MODS, modules(MODS))
    forever()


def console():
    import readline
    readline.redisplay()
    if check("0"):
        Config.ignore = list()
    boot(TXT)
    scanner(MODS)
    enable(cmd, mod, ver)
    if "a" in Config.opts:
        mds = modules(MODS)
    else:
        mds = Config.sets.init
    init(MODS, mds, "w" in Config.opts)
    csl = Console()
    csl.start()
    forever()


def control():
    if len(sys.argv) == 1:
        return
    boot(TXT)
    scanner(MODS)
    enable(cmd, cpy, mod, srv, ver)
    cli = Line()
    evt = Message()
    evt.orig = repr(cli)
    evt.text = " ".join(sys.argv[1:])
    evt.type = "command"
    command(evt)
    evt.wait()


def service():
    privileges()
    boot(TXT)
    pidfile(pidname(Config.name))
    enable(cmd, mod, ver)
    scanner(MODS)
    init(MODS, modules(MODS))
    forever()


"commands"


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


def cpy(event):
    import shutil
    if os.path.exists("examples"):
        path = "examples"
    else:
        path = os.path.join(
                   Mods.path.rsplit("nixt")[-3],
                  "nixt",
                  "share",
                  "nixt",
                  "examples"
               ) 
    if not os.path.exists(path):
        event.reply(f"{path} doesn't exist.")
        return
    event.reply(f"using {path}")
    shutil.copytree(path, moddir(), dirs_exist_ok=True)
    event.reply("done")


def mod(event):
    event.reply(modules(MODS))


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


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


"utilities"


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


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)


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


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


"runtime"


def main():
    if check('z'):
        Config.debug = True
    if check("c"):
        wrap(console)
    elif check("d"):
        background()
    elif check("s"):
        wrapped(service)
    else:
        wrapped(control)


if __name__ == "__main__":
    main()
