#!/usr/local/bin/python3.13

# Read a file in GNU info format and output its nodes as subdocs,
# interfacing with recoll execm

import rclexecm
import sys
import os
import subprocess

# Prototype for the html document we're returning. Info files are
# normally ascii. Set no charset, and let it be provided by the
# environment if necessary
#
# Some info source docs contain charset info like:
# @documentencoding ISO-2022-JP
# But this seems to be absent from outputs.


# RclExecm interface
class InfoExtractor:
    def __init__(self, em):
        self.file = ""
        self.contents = []
        self.em = em

    def extractone(self, index):
        if index >= len(self.contents):
            return (False, "", "", True)

        nodename, docdata = self.contents[index]
        nodename = rclexecm.htmlescape(nodename)
        docdata = rclexecm.htmlescape(docdata)
        # strange whitespace to avoid changing the module tests (same as old)
        docdata = (
            b"\n<html>\n  <head>\n      <title>"
            + nodename
            + b"</title>\n"
            + b'      <meta name="rclaptg" content="gnuinfo">\n'
            + b"   </head>\n   <body>\n"
            + b'   <pre style="white-space: pre-wrap">\n   '
            + docdata
            + b"\n   </pre></body>\n</html>\n"
        )

        iseof = rclexecm.RclExecM.noteof
        if self.currentindex >= len(self.contents) - 1:
            iseof = rclexecm.RclExecM.eofnext
        self.em.setmimetype("text/html")
        return (True, docdata, str(index), iseof)

    ###### File type handler api, used by rclexecm ---------->
    def openfile(self, params):
        self.file = params["filename"]

        if not os.path.isfile(self.file):
            self.em.rclog("Openfile: %s is not a file" % self.file)
            return False

        cmd = b"info --subnodes -o - -f " + self.file
        nullstream = open(os.devnull, "w")
        try:
            infostream = subprocess.Popen(
                cmd, shell=True, bufsize=1, stderr=nullstream, stdout=subprocess.PIPE
            ).stdout
        except Exception as e:
            # Consider this as permanently fatal.
            self.em.rclog("Openfile: exec info: %s" % str(e))
            print("RECFILTERROR HELPERNOTFOUND info")
            sys.exit(1)

        self.currentindex = -1

        self.contents = InfoSimpleSplitter().splitinfo(self.file, infostream)

        # self.em.rclog("openfile: Entry count: %d"%(len(self.contents)))
        return True

    # Extract specific node
    def getipath(self, params):
        try:
            index = int(params["ipath"])
        except:
            return (False, "", "", True)
        return self.extractone(index)

    # Extract next in list
    def getnext(self, params):

        if self.currentindex == -1:
            # Return "self" doc
            self.currentindex = 0
            self.em.setmimetype("text/plain")
            if len(self.contents) == 0:
                eof = rclexecm.RclExecM.eofnext
            else:
                eof = rclexecm.RclExecM.noteof
            return (True, "", "", eof)

        if self.currentindex >= len(self.contents):
            self.em.rclog("getnext: EOF hit")
            return (False, "", "", rclexecm.RclExecM.eofnow)
        else:
            ret = self.extractone(self.currentindex)
            self.currentindex += 1
            return ret


# Info file splitter
class InfoSimpleSplitter:

    def splitinfo(self, filename, fin):
        gotblankline = 1
        index = 0
        listout = []
        node_dict = {}
        node = b""
        infofile = os.path.basename(filename)
        nodename = b"Unknown"

        for line in fin:

            # Top of node ?
            # It sometimes happens that info --subnodes produces a Node line
            # beginning with spaces (it's a bug probably, only seen it once)
            # Maybe we'd actually be better off directly interpreting the
            # info files
            if gotblankline and line.lstrip(b" ").startswith(b"File: "):
                prevnodename = nodename
                line = line.rstrip(b"\n\r")
                pairs = line.split(b",")
                up = b"Top"
                nodename = str(index)
                try:
                    for pair in pairs:
                        name, value = pair.split(b":")
                        name = name.strip(b" ")
                        value = value.strip(b" ")
                        if name == b"Node":
                            nodename = value
                        if name == b"Up":
                            up = value
                        if name == b"File":
                            infofile = value
                except Exception as err:
                    print(
                        "rclinfo.py: bad line in %s: [%s] %s\n" % (infofile, line, err),
                        file=sys.stderr,
                    )
                    nodename = prevnodename
                    node += line
                    continue

                if nodename in node_dict:
                    print(
                        "Info file %s Dup node: %s" % (filename, nodename),
                        file=sys.stderr,
                    )
                node_dict[nodename] = up

                if index != 0:
                    listout.append((prevnodename, node))
                node = b""
                index += 1

            if line.rstrip(b"\n\r") == b"":
                gotblankline = 1
            else:
                gotblankline = 0

            node += line

        # File done, add last dangling node
        if node != b"":
            listout.append((nodename, node))

        # Compute node paths (concatenate "Up" values), to be used
        # as page titles. It's unfortunate that this will crash if
        # the info file tree is bad
        listout1 = []
        for nodename, node in listout:
            title = b""
            loop = 0
            error = 0
            while nodename != b"Top":
                title = nodename + b" / " + title
                if nodename in node_dict:
                    nodename = node_dict[nodename]
                else:
                    print(
                        "Infofile: node's Up does not exist: file %s, path %s, up [%s]"
                        % (infofile, title, nodename),
                        sys.stderr,
                    )
                    error = 1
                    break
                loop += 1
                if loop > 50:
                    print("Infofile: bad tree (looping) %s" % infofile, file=sys.stderr)
                    error = 1
                    break

            if error:
                continue

            if title == b"":
                title = infofile
            else:
                title = infofile + b" / " + title
            title = title.rstrip(b" / ")
            listout1.append((title, node))

        return listout1


##### Main program: either talk to the parent or execute test loop
proto = rclexecm.RclExecM()
extract = InfoExtractor(proto)
rclexecm.main(proto, extract)
