#!/usr/bin/env python3
'''
    %(prog)s - Free Resource Printer - (C) 2005-2018, Mike Miller
    A program to print available free resources in delicious flavors.
    License: GPLv3+.

    usage: %(prog)s [options]

    TODO:  refactoring

        - move icon decoding and uploading to pform module
        - put icons into data?
        - port ansi to newer module
'''
import os
import sys

import fr
from fr import (fmtstr, fmtval, get_units, truncstr, print_meminfo,
                print_diskinfo)
from fr.meta import version

# defaults
_debug          = False
_binary         = False
_colwidth       = 10
_extra_cols_at  = 110
_extra_cols_cap = 4
_graphwidth     = 0
_incolor        = 'auto'
_precision      = -1

out             = sys.stdout.write
NUMCOLS         = 6  # num of data columns, w/o graph


def setup():
    ''' Parse, interpret command line options, discover environment. '''
    import shutil
    from argparse import ArgumentParser
    parser = ArgumentParser(usage=__doc__.rstrip())
    parser.add_argument('-a', '--all', action='store_true',
                        help='Include unmounted devices and tmpfs mounts.')
    parser.add_argument('-b', '--binary',
                        action='store_true', dest='binary', default=_binary,
                        help='Use propeller-head binary units (2¹⁰) instead '
                        'of human/SI units (10³).')
    parser.add_argument('-d', '--debug',
                        action='store_true', dest='debug', default=_debug,
                        help='Turns on verbose debugging output.')
    parser.add_argument('-l', '--local', action='store_true',
                        help='Include only local filesystems.')
    parser.add_argument('-p', '--precision', type=int, default=_precision,
                        metavar='#', help='Set number of dec. places shown.')
    parser.add_argument('-r', '--relative', action='store_true',
                        help='Use logarithmic relative disk graph sizes.')

    unit_choices = ('b', 'k', 'm', 'g', 't')
    parser.add_argument('-u', '--unit', default='m', choices=unit_choices,
                        metavar='U', help='Selects unit size: b, k, m, g, t')
    parser.add_argument('-w', '--width', type=int, metavar='#',
                        default=_graphwidth,
                        help='Set the width of the resource graphs.')

    toggle_choices = ('auto', 'on', 'off')
    parser.add_argument('--color', dest='incolor', metavar='...',
                        default=_incolor, choices=toggle_choices,
                        help='Color: (%s)' % ', '.join(toggle_choices))
    parser.add_argument('--version', action='version', version=version)

    opts = parser.parse_args()

    # discover environment
    # get_terminal_size(), must be done before colorama to avoid crash
    opts.termcols, _ = shutil.get_terminal_size((80, 20))  # fallback
    isatty = hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno())

    plat = sys.platform[:3]
    if plat == 'lin':
        import fr.linux as pform
    elif plat == 'win':
        import fr.windows as pform
    elif plat == 'dar':
        import fr.darwin as pform
    pform.debug = opts.debug  # to handle debug output
    opts.pform = pform

    # expand colwidth if room, one column extra per ten over threshold
    opts.colwidth = _colwidth
    extrawidth = opts.termcols - _extra_cols_at
    if extrawidth > 0:
        opts.colwidth += min(extrawidth // 10, _extra_cols_cap)  # cap at

    if opts.debug:
        print('termcols:', opts.termcols, '_colwidth:', _colwidth)
        print('_extra_cols_at:', _extra_cols_at)
        print('extrawidth:', extrawidth)
        print('opts.colwidth:', opts.colwidth)

    # determine whether to use color
    opts.hicolor = None
    if opts.incolor == 'auto':
        if isatty:
            if 'NO_COLOR' in os.environ:
                opts.incolor = False
            elif pform.coloravail:
                opts.incolor = True
                opts.hicolor = pform.hicolor
            else:
                opts.incolor = False
        else:
            opts.incolor = False
    elif opts.incolor == 'on':
        if pform.coloravail:
            opts.incolor = True
            opts.hicolor = pform.hicolor
        else:
            raise pform.ColorNotAvail()
    else:
        opts.incolor = False

    return opts


def main(opts):
    ''' Let's get it on... '''
    longestpth = opts.colwidth + 1     # extra space
    widelayout = opts.termcols > 89

    fr.load_config(opts)
    pform = opts.pform

    opts.outunit, unitstr = get_units(opts.unit, binary=opts.binary)
    if opts.debug:
        print('opts:', opts)    # or will get clobbered by set

    out_fmt = fmtval(opts.outunit, precision=0, spacing=False, trunc=False,
                     end='')
    out(f'\nFree Resources in Blocks of 1 {unitstr} ({out_fmt} bytes)')

    # get memory info
    meminfo = pform.get_meminfo(opts)
    if not meminfo:
        print(f'\nError: Could not read memory info @ {pform.memfname}.')
        sys.exit(os.EX_IOERR)

    # get disk info
    diskinfo = pform.get_diskinfo(opts, local_only=opts.local,
                                  show_all=opts.all)
    if not diskinfo:
        print('\nError: Could not read disk information.')
        sys.exit(os.EX_IOERR)

    print() # after possible diskinfo warning
    # figure out graph width
    for disk in diskinfo:
        pathlen = len(disk.mntp)
        if pathlen > longestpth:
            longestpth = pathlen

    # cap longest path
    maxpath = opts.colwidth * 2
    longestpth = min(longestpth, maxpath)

    if not opts.width:
        # automatic width - figure out how much space is taken already
        #         cols - mntpath, + space each col, path col, graph padding
        taken = ((NUMCOLS - 1) * (opts.colwidth + 1)) + longestpth + 4
        if widelayout:
            opts.width = opts.termcols - taken
        else:
            opts.width = 58

    # Headers
    out('\n' +
        fmtstr('DEVICE', align='<') +
        fmtstr('VOLUME', align='<')
    )
    for header in ['CAPACITY', 'USED', 'FREE']:
        out(fmtstr(header))

    if widelayout:
        if ' ' in pform.col_lblw:   # figure expanding label (on posix)
            lbl = list(pform.col_lblw)
            while len(lbl) < opts.colwidth:
                lbl.insert(5, ' ')
            lbl = ''.join(lbl)
        else:
            lbl = pform.col_lblw    # windows
        out(' ' * (opts.width + 1) + fmtstr(lbl))
    else:
        out(' ' + fmtstr(pform.col_lbls))

    print()
    print_meminfo(meminfo, widelayout, opts.incolor)
    print_diskinfo(diskinfo, widelayout, opts.incolor)

    return os.EX_OK


if __name__ == '__main__':
    sys.exit(main(setup()))
