#!/usr/bin/python -u
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2012-2013 Bastian Kleineidam
#
# 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.
"""
Check HTML pages for broken links. This is the commandline nagios plugin.
Run this file without options to see how it's done.
"""

import sys
import os
import socket
import argparse
import pprint
# installs _() and _n() gettext functions into global namespace
import linkcheck
# override argparse gettext method with the one from linkcheck.init_i18n()
#argparse._ = _
# now import the rest of the linkchecker gang
from linkcheck.cmdline import print_version, print_usage, aggregate_url, LCArgumentParser
from linkcheck import log, LOG_CMDLINE, strformat
import linkcheck.checker
import linkcheck.configuration
import linkcheck.fileutil
import linkcheck.logger
import linkcheck.ansicolor
from linkcheck.director import console, check_urls, get_aggregate

Retval = _(r"""RETURN VALUE
0 - everything checked ok without errors or warnings
1 - URL check warnings were found
2 - URL check errors were found
3 - internal or config error
""")

Examples = _(r"""EXAMPLES
  linkchecker-nagios -v www.example.org
""")

Epilog = u"\n".join((Retval, Examples))


# instantiate option parser and configure options
class ArgumentParser(LCArgumentParser):
    """Custom argument parser for error reporting."""

    def error(self, message):
        """Print error and exit with error code 3."""
        self.print_usage(sys.stderr)
        self.exit(3, _('%s: error: %s\n') % (self.prog, message))

argparser = ArgumentParser(
  epilog=Epilog,
  formatter_class=argparse.RawDescriptionHelpFormatter
)

# build a config object for this check session
config = linkcheck.configuration.Configuration()
# default recursion level is 1
config['recursionlevel'] = 1

# Standard options
group = argparser.add_argument_group(_("Standard nagios options"))
group.add_argument("-v", "--verbose", action="count", default=0,
  help=_("""Increase verbosity. This option can be given multiple times."""))
group.add_argument("-V", "--version", action="store_true",
                 help=_("""Print version and exit."""))
group.add_argument("-t", "--timeout", type=int, dest="timeout", metavar="NUMBER",
                 help=_(
"""Set the timeout for connection attempts in seconds. The default
timeout is %d seconds.""") % config["timeout"])

# Checking options
group = argparser.add_argument_group(_("Checking options"))
group.add_argument("-f", "--config", dest="configfile", metavar="FILENAME",
                 help=_(
"""Use FILENAME as configuration file. Per default LinkChecker uses
~/.linkchecker/linkcheckerrc (under Windows
%HOMEPATH%\\.linkchecker\\linkcheckerrc)."""))

argparser.add_argument("url", nargs='+', metavar="FILE_OR_URL")

# read and parse command line options and arguments
args = argparser.parse_args()

if args.version is not None:
    print_version()
if args.timeout is not None:
    if args.timeout > 0:
        config["timeout"] = args.timeout
    else:
        print_usage(_("Illegal argument %(arg)r for option %(option)s") % \
                    {"arg": args.timeout, "option": "'--timeout'"},
                    exit_code=3)
socket.setdefaulttimeout(config["timeout"])
if args.verbose >= 3:
    debug = ['all']
else:
    debug = None
# initialize logging
config.init_logging(console.StatusLogger(), debug=debug)
log.debug(LOG_CMDLINE, _("Python %(version)s on %(platform)s") % \
   {"version": sys.version, "platform": sys.platform})
# read configuration files
try:
    files = []
    if args.configfile:
        path = linkcheck.configuration.normpath(args.configfile)
        if os.path.isfile(path):
            files.append(path)
        else:
            log.warn(LOG_CMDLINE, _("Unreadable config file: %r"), args.configfile)
            sys.exit(3)
    config.read(files=files)
except linkcheck.LinkCheckerError, msg:
    # config error
    print_usage(str(msg), exit_code=3)
linkcheck.drop_privileges()


socket.setdefaulttimeout(config["timeout"])
if args.verbose < 0:
    config['logger'] = config.logger_new('none')
else:
    config["verbose"] = True
    config["warnings"] = True
    if args.verbose >= 2:
        config["complete"] = True

# check missing passwords
for entry in config["authentication"]:
    if entry["password"] is None:
        pattern = entry["pattern"].pattern
        log.warn(LOG_CMDLINE, _("missing password for pattern %(pattern)s") % dict(pattern=pattern))
        sys.exit(3)
# sanitize the configuration
config.sanitize()

log.debug(LOG_CMDLINE, "configuration: %s",
          pprint.pformat(sorted(config.items())))
# prepare checking queue
aggregate = get_aggregate(config)
# add urls to queue
for url in args.url:
    aggregate_url(aggregate, strformat.stripurl(url), err_exit_code=3)

# finally, start checking
check_urls(aggregate)

stats = config['logger'].stats
# on internal errors, exit with status 3
if stats.internal_errors:
    sys.exit(3)
# on errors, exit with status 2
if stats.errors:
    sys.exit(2)
# on warnings, exit with status 1
if stats.warnings_printed and config['warnings']:
    sys.exit(1)
