import subprocess
import json
import pkg_resources

from ocrd_utils import getLogger
from pathlib import Path

MAIN = "de.lmu.cis.ocrd.cli.Main"
JAR = pkg_resources.resource_filename('ocrd_cis', 'data/ocrd-cis.jar')

def JavaAligner(n, loglvl):
    """Create a java process that calls -c align -D '{"n":n}'"""
    return JavaProcess(JAR, ['-c', 'align',
                             '--log-level', loglvl,
                             '--parameter', '{}'.format(json.dumps({'n':n}))])

def JavaPostCorrector(mets, ifg, ofg, params, loglvl):
    return JavaProcess(JAR, ['-c', 'post-correct',
                             '--log-level', loglvl,
                             '--input-file-grp', ifg,
                             '--output-file-grp', ofg,
                             '--mets', mets,
                             '-p', "{}".format(json.dumps(params))])


class JavaProcess:
    def __init__(self, jar, args):
        self.jar = jar
        self.args = args
        self.main = MAIN
        self.log = getLogger('cis.JavaProcess')
        if not Path(jar).is_file():
            raise FileNotFoundError("no such file: {}".format(jar))

    def run(self, _input):
        """
        Run the process with the given input and get its output.
        The process writes _input to stdin of the process.
        """
        cmd = self.get_cmd()
        self.log.info('command: %s', " ".join(cmd))
        self.log.debug('input: %s', _input)
        with subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stdin=subprocess.PIPE,
                stderr=subprocess.PIPE,
                # only since 3.6: encoding='utf-8',
        ) as p:
            output, err = p.communicate(input=_input.encode('utf-8'))
            self.log_stderr(err)
            output = output.decode('utf-8')
            self.log.debug("got output")
            retval = p.wait()
            self.log.debug("waited")
            self.log.debug("%s: %i", " ".join(cmd), retval)
            if retval != 0:
                raise ValueError(
                    "cannot execute {}: {}\n{}"
                    .format(" ".join(cmd), retval, err.decode('utf-8')))
            # self.log.info('output: %s', output)
            return output

    def exe(self):
        """
        Run the process with no imput returning no output.
        """
        cmd = self.get_cmd()
        self.log.info('command: %s', " ".join(cmd))
        with subprocess.Popen(
                cmd,
                stderr=subprocess.PIPE
        ) as p:
            sout, eout = p.communicate()
            self.log_stderr(eout)
            retval = p.wait()
            if retval != 0:
                raise ValueError(
                    "cannot execute {}: {}\n{}"
                    .format(" ".join(cmd), retval, eout.decode('utf-8')))

    def log_stderr(self, err):
        for line in err.decode("utf-8").split("\n"):
            if line.startswith("DEBUG"):
                self.log.debug(line[6:])
            elif line.startswith("INFO"):
                self.log.info(line[5:])

    def get_cmd(self):
        cmd = ['java', '-Dfile.encoding=UTF-8',
               '-Xmx3g', '-cp', self.jar, self.main]
        cmd.extend(self.args)
        return cmd
