#!/usr/bin/env python3
# coding: utf-8

# Copyright (C) 1994-2021 Altair Engineering, Inc.
# For more information, contact Altair at www.altair.com.
#
# This file is part of both the OpenPBS software ("OpenPBS")
# and the PBS Professional ("PBS Pro") software.
#
# Open Source License Information:
#
# OpenPBS is free software. You can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# OpenPBS 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Commercial License Information:
#
# PBS Pro is commercially licensed software that shares a common core with
# the OpenPBS software.  For a copy of the commercial license terms and
# conditions, go to: (http://www.pbspro.com/agreement.html) or contact the
# Altair Legal Department.
#
# Altair's dual-license business model allows companies, individuals, and
# organizations to create proprietary derivative works of OpenPBS and
# distribute them - whether embedded or bundled with other software -
# under a commercial license agreement.
#
# Use of Altair's trademarks, including but not limited to "PBS™",
# "OpenPBS®", "PBS Professional®", and "PBS Pro™" and Altair's logos is
# subject to Altair's trademark licensing policies.


import os
import sys
import getopt
import logging
import logging.config
import errno

import ptl
from ptl.utils.pbs_cliutils import CliUtils
from ptl.utils.pbs_covutils import LcovUtils
from ptl.lib.pbs_testlib import PtlConfig


# trap SIGINT and SIGPIPE
def trap_exceptions(etype, value, tb):
    sys.excepthook = sys.__excepthook__
    if issubclass(etype, IOError) and value.errno == errno.EPIPE:
        pass
    else:
        sys.__excepthook__(etype, value, tb)


sys.excepthook = trap_exceptions


def usage():
    msg = []
    msg += ['Usage: ' + os.path.basename(sys.argv[0]) + ' [OPTION]\n\n']
    msg += ['    code coverage tools\n\n']
    msg += ['-c: capture coverage\n']
    msg += ['-d <path>: path to directory that contains coverage data\n']
    msg += ['-i: initialize coverage\n']
    msg += ['-o <path>: path to output directory\n']
    msg += ['-m <f1,f2>: merge comma-separated coverage files\n']
    msg += ['-r <path>: path to file to remove coverage patterns from\n']
    msg += ['-z: reset coverage counters\n']
    msg += ['--exclude=<p1,p2>: comma-separated pattern of files to exclude\n']
    msg += ['--summarize: summarize coverage analysis\n']
    msg += ['--html: Generate HTML from coverage analysis\n']
    msg += ['--no-source: don\'t include PBS source in coverage analysis']
    msg += [' (Must be used with --html)\n']
    msg += ['--baseurl=<url>: use <url> as baseurl in html report']
    msg += [' (Must be used with --html)\n']
    msg += [' Default source will be in coverage analysis\n']
    msg += ['--version: print version number and exit\n']

    print("".join(msg))


if __name__ == '__main__':

    if len(sys.argv) < 2:
        usage()
        sys.exit(1)

    data_dir = None
    capture = None
    initialize = None
    merge = None
    reset = None
    remove = None
    out = None
    html_nosrc = False
    html = False
    html_baseurl = None
    exclude = ['"*work/gSOAP/*"', '"*/pbs/doc/*"', 'lex.yy.c',
               'pbs_ifl_wrap.c', 'usr/include/*', 'unsupported/*']

    summarize = None
    lvl = logging.INFO
    logconf = None

    lopts = ["version", "exclude=", "summarize", 'no-source', 'html']
    lopts += ['baseurl=']

    try:
        opts, args = getopt.getopt(sys.argv[1:], "ciszd:mo:l:rh", lopts)
    except Exception:
        usage()
        sys.exit(1)

    for o, val in opts:
        if o == '-d':
            data_dir = CliUtils.expand_abs_path(val)
        elif o == '-c':
            capture = True
        elif o == '-o':
            out = CliUtils.expand_abs_path(val)
        elif o == '-i':
            initialize = True
        elif o == '-l':
            lvl = CliUtils.get_logging_level(val)
        elif o == '-m':
            merge = val
        elif o == '-l':
            lvl = CliUtils().get_logging_level(val)
        elif o == '-r':
            remove = CliUtils.expand_abs_path(val)
        elif o == '-z':
            reset = True
        elif o == '-h':
            usage()
            sys.exit(0)
        elif o == '--exclude':
            exclude = val.split(',')
        elif o == '--log-conf':
            logconf = val
        elif o in ('-s', '--summarize'):
            summarize = True
        elif o == '--html':
            html = True
        elif o in '--no-source':
            html_nosrc = False
        elif o in '--baseurl':
            html_baseurl = val
        elif o == '--version':
            print(ptl.__version__)
            sys.exit(0)
        else:
            sys.stderr.write("Unrecognized option")
            usage()
            sys.exit(1)

    PtlConfig()

    if logconf:
        logging.config.fileConfig(logconf)
    else:
        logging.basicConfig(level=lvl)

    if html_nosrc and not html:
        logging.error('--no-source must be used with --html')
        sys.exit(1)

    if html_baseurl and not html:
        logging.error('--baseurl must be used with --html')
        sys.exit(1)

    cu = LcovUtils(cov_out=out, data_dir=data_dir, html_nosrc=html_nosrc,
                   html_baseurl=html_baseurl)

    if reset:
        cu.zero_coverage()
    if initialize:
        cu.initialize_coverage()
    if capture:
        cu.capture_coverage()
    if merge is not None:
        for m in merge.split(','):
            cu.add_trace(m)
        cu.merge_coverage_traces(exclude=exclude)
    if html:
        cu.generate_html()
        if html_baseurl:
            cu.change_baseurl()
    if summarize:
        cu.summarize_coverage()
