#!/usr/bin/env python3
# Part of TotalDepth: Petrophysical data processing and presentation.
# Copyright (C) 2011-2021 Paul Ross
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Paul Ross: apaulross@gmail.com
"""
Created on 10 Nov 2010

@author: p2ross
"""
import logging
import sys
import time
import typing

from TotalDepth.LIS import lis_cmn_cmd_opts
from TotalDepth.LIS.core import PhysRec
from TotalDepth.common import cmn_cmd_opts
from TotalDepth.util import Histogram


__author__  = 'Paul Ross'
__date__    = '2010-08-02'
__version__ = '0.1.0'
__rights__  = 'Copyright (c) 2010-2020 Paul Ross'


# How much of the logical data to display
LEN_TRUNCATE = 32


def scan_file(file_path, verbose, keepGoing, pad_modulo, pad_non_null, dump_tell_list, theS=sys.stdout):
    try:
        myPrh = PhysRec.PhysRecRead(file_path, file_path, keepGoing, pad_modulo, pad_non_null)
    except PhysRec.ExceptionPhysRec as err:
        print('Can not open file, error: %s' % str(err))
        return
    # Now other stuff generated by this loop
    theS.write('Offset        Length  Type  Logical Data\n')
    myLdSigma = bytes()
    myOffs = myPrh.tellLr()
    # Histogram of lengths and types
    myHistLen = Histogram.Histogram()
    myHistTyp = Histogram.Histogram()
    for myLd, isLdStart in myPrh.genLd():
        if isLdStart:
            if len(myLdSigma) == 0:
                # First time through the loop then don't write anything
                pass
            else:
                # This is not the first time through the loop
                # so write out the trailing LogicalData length
                lrType = -1
                if len(myLdSigma) > 0:
                    lrType = myLdSigma[0]
                    myHistLen.add(len(myLdSigma))
                    myHistTyp.add(lrType)
                theS.write('0x{:08X}  {:8d}  {:4d}'.format(myOffs, len(myLdSigma), lrType))
                if myOffs not in dump_tell_list \
                and not verbose and len(myLdSigma) > LEN_TRUNCATE:
                    theS.write('  {!r:s}...\n'.format(myLdSigma[0:LEN_TRUNCATE]))
                else:
                    theS.write('  {!r:s}\n'.format(myLdSigma))
                myLdSigma = bytes() 
                myOffs = myPrh.tellLr()
        myLdSigma += myLd
    if len(myLdSigma) > 0:
        theS.write('0x{:08X}  {:8d}  {:4d}'.format(myOffs, len(myLdSigma), lrType))
        if myOffs not in dump_tell_list \
        and not verbose and len(myLdSigma) > LEN_TRUNCATE:
            theS.write('  {!r:s}...\n'.format(myLdSigma[0:LEN_TRUNCATE]))
        else:
            theS.write('  {:s}\n'.format(myLdSigma))
    theS.write('Histogram of Logical Data lengths:\n')
    theS.write(myHistLen.strRep(100, valTitle='Bytes', inclCount=True))
    theS.write('\n')
    theS.write('Histogram of Logical Record types:\n')
    theS.write(myHistTyp.strRep(100, inclCount=True))
    theS.write('\n')
    

def ret_int_dump_list(arg_string: str) -> typing.List[int]:
    """Splits a string and returns a list of integers from hex/dec."""
    r: typing.List[int] = []
    for w in arg_string.split():
        try:
            if w.startswith('0x'):
                r.append(int(w[2:], 16))
            else:
                r.append(int(w))
        except (TypeError, ValueError) as err:
            logging.error('Can not understand integer {:s}: {:s}'.format(w, err))
    return r


def main():
    usage = """usage: %prog [options] file
Scans a LIS79 file and dumps logical record data."""
    print('Cmd: %s' % ' '.join(sys.argv))
    arg_parser = cmn_cmd_opts.path_in(usage, prog='TotalDepth.LIS.ScanPhysRec', version='%(prog)s ' + __version__)
    lis_cmn_cmd_opts.add_physical_record_padding_options(arg_parser)
    cmn_cmd_opts.add_log_level(arg_parser, level=20)
    arg_parser.add_argument(
            "-d", "--dump",
            type=str,
            dest="dump",
            default='',
            help="Dump complete data at these integer positions (ws separated, hex/dec). [default: %(default)s]"
    )
    args = arg_parser.parse_args()
    print(args)
    # Initialise logging etc.
    cmn_cmd_opts.set_log_level(args)
    # Your code here
    clkStart = time.perf_counter()
    scan_file(args.path_in, args.verbose, args.keepGoing, args.pad_modulo, args.pad_non_null, ret_int_dump_list(args.dump))
    clkExec = time.perf_counter() - clkStart
    print('CPU time = %8.3f (S)' % clkExec)
    print('Bye, bye!')
    return 0

if __name__ == '__main__':
    #multiprocessing.freeze_support()
    sys.exit(main())

    
    
    