#!/usr/bin/python3 -s
# -*- coding: utf-8 -*-
#
# Copyright 2015 Simone Campagna
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

__author__ = "Simone Campagna"

import argparse
import collections
import functools
import glob
import logging
import os
import shutil
import sys


def show_error(logger, trace, error_message):
    if trace:
        logger.exception(error_message)
    else:
        err_type, err_value, traceback = sys.exc_info()
        logger.exception("{}: {}: {}".format(error_message, err_type.__name__, err_value))


def docs_function(src, rfc, logger, trace=False, ignore=None):
    missing_rfcfiles = []
    useless_rfcfiles = []
    rfcfiles = []
    src = os.path.realpath(os.path.abspath(src))
    dsrc = os.path.dirname(src)
    rfc = os.path.realpath(os.path.abspath(rfc))
    for dirpath, dirnames, filenames in os.walk(src):
        if '__pycache__' in dirnames:
            dirnames.remove('__pycache__')
        dirnames_rem = []
        for dirname in dirnames:
            if not os.path.exists(os.path.join(dirpath, dirname, '__init__.py')):
                dirnames_rem.append(dirname)
            elif ignore is not None and dirname in ignore(dirpath, os.listdir(dirpath)):
                dirnames_rem.append(dirname)

        for dirname in dirnames_rem:
            dirnames.remove(dirname)
        filenames_rem = []
        for filename in filenames:
            if ignore is not None and filename in ignore(dirpath, os.listdir(dirpath)):
                continue
            fileroot, fileext = os.path.splitext(filename)
            if fileext in {'.py'}:
                if fileroot == '__init__':
                    filepath = dirpath
                else:
                    filepath = os.path.join(dirpath, fileroot)
                rfcfilerel = os.path.relpath(filepath, dsrc) + '.rst'
                rfcfile = os.path.join(rfc, '.'.join(rfcfilerel.split(os.path.sep)))
                if os.path.isfile(rfcfile):
                    logger.info("file {!r} found".format(rfcfile))
                else:
                    logger.error("file {!r} *NOT* found".format(rfcfile))
                    missing_rfcfiles.append((os.path.join(dirpath, filename), rfcfile))
                rfcfiles.append(rfcfile)

    s_rfcfiles = set(rfcfiles)
    for rfcfile in glob.glob(os.path.join(rfc, "*.rst")):
        rfcfile = os.path.normpath(os.path.realpath(os.path.abspath(rfcfile)))
        if not rfcfile in s_rfcfiles:
            logger.error("file {!r} found but not needed".format(rfcfile))
            useless_rfcfiles.append(rfcfile)
    return len(missing_rfcfiles) + len(useless_rfcfiles)
    

def main():
    default_verbose_level = 1
    parser = argparse.ArgumentParser(
        description="""\
Check docs""")

    parser.add_argument('source',
                        metavar='S',
                        type=str,
                        help='source path')

    parser.add_argument('reference',
                        metavar='S',
                        type=str,
                        help='reference path')

    parser.add_argument('--ignore', '-i',
                        dest='ignore_patterns',
                        action='append',
                        default=[],
                        help='add ignore patterns')

    parser.add_argument('--trace', '-t',
                        default=False,
                        action='store_true',
                        help='show errors traceback')

    parser.add_argument('--quiet', '-q',
                        dest='verbose_level',
                        default=default_verbose_level,
                        action='store_const',
                        const=0,
                        help='disable logging')

    parser.add_argument('--verbose', '-v',
                        dest='verbose_level',
                        default=default_verbose_level,
                        help='increase verbose level')

    args = parser.parse_args()

    if args.verbose_level == 0:
        log_level = logging.WARNING
    elif args.verbose_level == 1:
        log_level = logging.INFO
    else:
        log_level = logging.DEBUG


    logger = logging.getLogger('copy')
    handler = logging.StreamHandler()
    handler.setLevel(log_level)
    logger.addHandler(handler)
    logger.setLevel(log_level)

    ignore = shutil.ignore_patterns(*args.ignore_patterns)
    trace = args.trace

    source = os.path.abspath(args.source)
    reference = os.path.abspath(args.reference)
    if not os.path.exists(source):
        logger.error("source {!r} does not exists".format(source))
    elif not os.path.isdir(source):
        logger.error("source {!r} is not a directory".format(source))
    else:
        function = functools.partial(docs_function, logger=logger, ignore=ignore, trace=trace)

    returncode = function(source, reference)

    sys.exit(returncode)

if __name__ == "__main__":
    main()

