# @file
#  Split a file into two pieces at the request offset.
#
#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
#
#  SPDX-License-Identifier: BSD-2-Clause-Patent
#
##

# Import Modules
#
import argparse
import os
import io
import shutil
import logging
import sys
import tempfile

parser = argparse.ArgumentParser(description='''
SplitFile creates two Binary files either in the same directory as the current working directory or in the specified directory.
''')
parser.add_argument("-f", "--filename", dest="inputfile",
                    required=True, help="The input file to split tool.")
parser.add_argument("-s", "--split", dest="position",
                    required=True, help="The number of bytes in the first file. The valid format are HEX, Decimal and Decimal[KMG].")
parser.add_argument("-p", "--prefix",  dest="output",
                    help="The output folder.")
parser.add_argument("-o", "--firstfile",  help="The first file name")
parser.add_argument("-t", "--secondfile",  help="The second file name")
parser.add_argument("--version", action="version", version='%(prog)s Version 2.0',
                    help="Print debug information.")

group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true",
                   help="Print debug information.")
group.add_argument("-q", "--quiet", action="store_true",
                   help="Disable all messages except fatal errors")

SizeDict = {
    "K": 1024,
    "M": 1024*1024,
    "G": 1024*1024*1024
}


def GetPositionValue(position):
    '''
    Parse the string of the argument position and return a decimal number.
    The valid position formats are
    1. HEX
    e.g. 0x1000 or 0X1000
    2. Decimal
    e.g. 100
    3. Decimal[KMG]
    e.g. 100K or 100M or 100G or 100k or 100m or 100g
    '''
    logger = logging.getLogger('Split')
    PosVal = 0
    header = position[:2].upper()
    tailer = position[-1].upper()

    try:
        if tailer in SizeDict:
            PosVal = int(position[:-1]) * SizeDict[tailer]
        else:
            if header == "0X":
                PosVal = int(position, 16)
            else:
                PosVal = int(position)
    except Exception as e:
        logger.error(
            "The parameter %s format is incorrect. The valid format is HEX, Decimal and Decimal[KMG]." % position)
        raise(e)

    return PosVal


def getFileSize(filename):
    '''
    Read the input file and return the file size.
    '''
    logger = logging.getLogger('Split')
    length = 0
    try:
        with open(filename, "rb") as fin:
            fin.seek(0, io.SEEK_END)
            length = fin.tell()
    except Exception as e:
        logger.error("Access file failed: %s", filename)
        raise(e)

    return length

def getoutputfileabs(inputfile, prefix, outputfile,index):
    inputfile = os.path.abspath(inputfile)
    if outputfile is None:
        if prefix is None:
            outputfileabs = os.path.join(os.path.dirname(inputfile), "{}{}".format(os.path.basename(inputfile),index))
        else:
            if os.path.isabs(prefix):
                outputfileabs = os.path.join(prefix, "{}{}".format(os.path.basename(inputfile),index))
            else:
                outputfileabs = os.path.join(os.getcwd(), prefix, "{}{}".format(os.path.basename(inputfile),index))
    elif not os.path.isabs(outputfile):
        if prefix is None:
            outputfileabs = os.path.join(os.getcwd(), outputfile)
        else:
            if os.path.isabs(prefix):
                outputfileabs = os.path.join(prefix, outputfile)
            else:
                outputfileabs = os.path.join(os.getcwd(), prefix, outputfile)
    else:
        outputfileabs = outputfile
    return outputfileabs

def splitFile(inputfile, position, outputdir=None, outputfile1=None, outputfile2=None):
    '''
    Split the inputfile into outputfile1 and outputfile2 from the position.
    '''
    logger = logging.getLogger('Split')

    if not os.path.exists(inputfile):
        logger.error("File Not Found: %s" % inputfile)
        raise(Exception)

    if outputfile1 and outputfile2 and outputfile1 == outputfile2:
        logger.error(
            "The firstfile and the secondfile can't be the same: %s" % outputfile1)
        raise(Exception)

    # Create dir for the output files
    try:

        outputfile1 = getoutputfileabs(inputfile, outputdir, outputfile1,1)
        outputfolder = os.path.dirname(outputfile1)
        if not os.path.exists(outputfolder):
            os.makedirs(outputfolder)

        outputfile2 = getoutputfileabs(inputfile, outputdir, outputfile2,2)
        outputfolder = os.path.dirname(outputfile2)
        if not os.path.exists(outputfolder):
            os.makedirs(outputfolder)

    except Exception as e:
        logger.error("Can't make dir: %s" % outputfolder)
        raise(e)

    if position <= 0:
        if outputfile2 != os.path.abspath(inputfile):
            shutil.copyfile(os.path.abspath(inputfile), outputfile2)
        with open(outputfile1, "wb") as fout:
            fout.write(b'')
    else:
        inputfilesize = getFileSize(inputfile)
        if position >= inputfilesize:
            if outputfile1 != os.path.abspath(inputfile):
                shutil.copyfile(os.path.abspath(inputfile), outputfile1)
            with open(outputfile2, "wb") as fout:
                fout.write(b'')
        else:
            try:
                tempdir = tempfile.mkdtemp()
                tempfile1 = os.path.join(tempdir, "file1.bin")
                tempfile2 = os.path.join(tempdir, "file2.bin")
                with open(inputfile, "rb") as fin:
                    content1 = fin.read(position)
                    with open(tempfile1, "wb") as fout1:
                        fout1.write(content1)

                    content2 = fin.read(inputfilesize - position)
                    with open(tempfile2, "wb") as fout2:
                        fout2.write(content2)
                shutil.copyfile(tempfile1, outputfile1)
                shutil.copyfile(tempfile2, outputfile2)
            except Exception as e:
                logger.error("Split file failed")
                raise(e)
            finally:
                if os.path.exists(tempdir):
                    shutil.rmtree(tempdir)


def main():
    args = parser.parse_args()
    status = 0

    logger = logging.getLogger('Split')
    if args.quiet:
        logger.setLevel(logging.CRITICAL)
    if args.verbose:
        logger.setLevel(logging.DEBUG)

    lh = logging.StreamHandler(sys.stdout)
    lf = logging.Formatter("%(levelname)-8s: %(message)s")
    lh.setFormatter(lf)
    logger.addHandler(lh)

    try:
        position = GetPositionValue(args.position)
        splitFile(args.inputfile, position, args.output,
                  args.firstfile, args.secondfile)
    except Exception as e:
        status = 1

    return status


if __name__ == "__main__":
    exit(main())
