# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.

#pylint: disable=no-member, too-many-locals, too-many-branches, no-self-use, broad-except, lost-exception, too-many-nested-blocks, too-few-public-methods, invalid-name
"""
    This script converts all python tutorials into python script
    and tests whether there is any warning or error.
    After running python script, it will also convert markdown files
    to notebooks to make sure notebook execution has no error.
"""
import os
import warnings
import imp

import traceback
import nbformat
from nbconvert.preprocessors import ExecutePreprocessor

fail_dict = {}

def test_tutorial(file_path):
    """Run tutorial python script and  save any error or warning.
       If no error or warning occurs, run notebook.

    Parameters
    ----------
    file_path : str
        path of tutorial markdown file
    """
    with warnings.catch_warnings(record=True) as w:
        tutorial_name = os.path.basename(file_path)
        print file_path + '.py'
        try:
            imp.load_source('tutorial', file_path + '.py')
            if len(w) > 0:
                err_msg = "%s.py has %d warnings.\n" % (tutorial_name, len(w))
                fail_dict[tutorial_name] = err_msg
            else:
                test_tutorial_nb(file_path)
        except Exception:
            err_msg = "%s.py has error:\n%s" % (tutorial_name, traceback.format_exc())
            fail_dict[tutorial_name] = err_msg

def test_tutorial_nb(file_path):
    """Run tutorial jupyter notebook to catch any execution error.

    Parameters
    ----------
    file_path : str
        path of tutorial markdown file
    """
    tutorial_name = os.path.basename(file_path)
    notebook = nbformat.read(file_path + '.ipynb', as_version=4)
    eprocessor = ExecutePreprocessor(timeout=1800)
    try:
        eprocessor.preprocess(notebook, {'metadata': {}})
    except Exception as err:
        err_msg = str(err)
        fail_dict[tutorial_name] = err_msg
    finally:
        output_nb = open("output.txt", mode='w')
        nbformat.write(notebook, output_nb)
        output_nb.close()
        output_nb = open("output.txt", mode='r')
        for line in output_nb:
            if "Warning:" in line:
                fail_dict[tutorial_name] = "%s has warning." % (tutorial_name)
                return


if __name__ == "__main__":
    tutorial_dir = '../../docs/_build/html/tutorials/'
    with open('test_tutorial_config.txt') as config_file:
        tutorial_list = []
        for line in config_file:
            tutorial_list.append(line.lstrip().rstrip())
            file_dir = tutorial_dir + line.lstrip().rstrip()
            test_tutorial_nb(file_dir)

        fail_num = len(fail_dict)
        success_num = len(tutorial_list) - fail_num
        print "Test Summary Start"
        print "%d tutorials tested:" % (len(tutorial_list))
        for tutorial in tutorial_list:
            print tutorial
        print "\n%d tests failed:" % (fail_num)
        for tutorial, msg in fail_dict.items():
            print tutorial + ":"
            print msg
        print "Test Summary End"
        print "Stats start"
        print "[Passed: %d of %d]" % (success_num, len(tutorial_list))
        print "Stats end"

