# SPDX-License-Identifier: GPL-2.0+
# Copyright 2022 Google LLC
#
"""Bintool implementation for lzma_alone

lzma_alone allows compression and decompression of files, using an older version
of lzma.

Documentation is available via::

   man lzma_alone

Here is the help:

LZMA 9.22 beta : Igor Pavlov : Public domain : 2011-04-18

Usage:  LZMA <e|d> inputFile outputFile [<switches>...]
  e: encode file
  d: decode file
  b: Benchmark
<Switches>
  -a{N}:  set compression mode - [0, 1], default: 1 (max)
  -d{N}:  set dictionary size - [12, 30], default: 23 (8MB)
  -fb{N}: set number of fast bytes - [5, 273], default: 128
  -mc{N}: set number of cycles for match finder
  -lc{N}: set number of literal context bits - [0, 8], default: 3
  -lp{N}: set number of literal pos bits - [0, 4], default: 0
  -pb{N}: set number of pos bits - [0, 4], default: 2
  -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4
  -mt{N}: set number of CPU threads
  -eos:   write End Of Stream marker
  -si:    read data from stdin
  -so:    write data to stdout
"""

import re
import tempfile

from binman import bintool
from patman import tools

# pylint: disable=C0103
class Bintoollzma_alone(bintool.Bintool):
    """Compression/decompression using the LZMA algorithm

    This bintool supports running `lzma_alone` to compress and decompress data,
    as used by binman.

    It is also possible to fetch the tool, which uses `apt` to install it.

    Documentation is available via::

        man lzma_alone
    """
    def __init__(self, name):
        super().__init__(name, 'lzma_alone compression')

    def compress(self, indata):
        """Compress data with lzma_alone

        Args:
            indata (bytes): Data to compress

        Returns:
            bytes: Compressed data
        """
        with tempfile.NamedTemporaryFile(prefix='comp.tmp',
                                         dir=tools.get_output_dir()) as inf:
            tools.write_file(inf.name, indata)
            with tempfile.NamedTemporaryFile(prefix='compo.otmp',
                                             dir=tools.get_output_dir()) as outf:
                args = ['e', inf.name, outf.name, '-lc1', '-lp0', '-pb0', '-d8']
                self.run_cmd(*args, binary=True)
                return tools.read_file(outf.name)

    def decompress(self, indata):
        """Decompress data with lzma_alone

        Args:
            indata (bytes): Data to decompress

        Returns:
            bytes: Decompressed data
        """
        with tempfile.NamedTemporaryFile(prefix='decomp.tmp',
                                         dir=tools.get_output_dir()) as inf:
            tools.write_file(inf.name, indata)
            with tempfile.NamedTemporaryFile(prefix='compo.otmp',
                                             dir=tools.get_output_dir()) as outf:
                args = ['d', inf.name, outf.name]
                self.run_cmd(*args, binary=True)
                return tools.read_file(outf.name, binary=True)

    def fetch(self, method):
        """Fetch handler for lzma_alone

        This installs the lzma-alone package using the apt utility.

        Args:
            method (FETCH_...): Method to use

        Returns:
            True if the file was fetched and now installed, None if a method
            other than FETCH_BIN was requested

        Raises:
            Valuerror: Fetching could not be completed
        """
        if method != bintool.FETCH_BIN:
            return None
        return self.apt_install('lzma-alone')

    def version(self):
        """Version handler

        Returns:
            str: Version number of lzma_alone
        """
        out = self.run_cmd_result('', raise_on_error=False).stderr.strip()
        lines = out.splitlines()
        if not lines:
            return super().version()
        out = lines[0]
        # e.g. LZMA 9.22 beta : Igor Pavlov : Public domain : 2011-04-18
        m_version = re.match(r'LZMA ([^:]*).*', out)
        return m_version.group(1).strip() if m_version else out
