# Copyright (C) 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import json


class ProcessJsonData(object):

    def __init__(self, current_result_json_dict, old_failing_results_list, old_full_results_list):
        self._current_result_json_dict = current_result_json_dict
        self._old_failing_results_list = old_failing_results_list
        self._old_full_results_list = old_full_results_list
        self._final_result = []

    def _get_test_result(self, test_result_data):
        actual = test_result_data['actual']
        expected = test_result_data['expected']
        if actual == 'SKIP':
            return actual
        if actual == expected:
            return 'HASSTDERR' if test_result_data.get('has_stderr') == 'true' else 'PASS'
        else:
            return actual

    def _recurse_json_object(self, json_object, key_list):
        for key in key_list:
            try:
                json_object = json_object[key]
            except KeyError:
                return 'NOTFOUND'
        return self._get_test_result(json_object)

    def _process_previous_json_results(self, key_list):
        row = []
        length = len(self._old_failing_results_list)
        for index in range(0, length):
            result = self._recurse_json_object(self._old_failing_results_list[index]['tests'], key_list)
            if result == 'NOTFOUND':
                result = self._recurse_json_object(self._old_full_results_list[index]['tests'], key_list)
            row.append(result)
        return row

    def _add_archived_result(self, json_object, result):
        json_object['archived_results'] = result

    def _process_json_object(self, json_object, keyList):
        for key, subdict in json_object.iteritems():
            if isinstance(subdict, dict):
                self._process_json_object(subdict, keyList + [key])
            else:
                row = [self._get_test_result(json_object)]
                row += self._process_previous_json_results(keyList)
                json_object.clear()
                self._add_archived_result(json_object, row)
                return

    def generate_archived_result(self):
        for key in self._current_result_json_dict['tests']:
            self._process_json_object(self._current_result_json_dict['tests'][key], [key])
        return self._current_result_json_dict


class DashBoardGenerator(object):

    def __init__(self, port):
        self._port = port
        self._filesystem = port.host.filesystem
        self._results_directory = self._port.results_directory()
        self._results_directory_path = self._filesystem.dirname(self._results_directory)
        self._current_result_json_dict = {}
        self._old_failing_results_list = []
        self._old_full_results_list = []
        self._final_result = []

    def _add_individual_result_links(self, results_directories):
        archived_results_file_list = [(file + '/results.html') for file in results_directories]
        archived_results_file_list.insert(0, 'results.html')
        self._current_result_json_dict['result_links'] = archived_results_file_list

    def _copy_dashboard_html(self):
        dashboard_file = self._filesystem.join(self._results_directory, 'dashboard.html')
        dashboard_html_file_path = self._filesystem.join(
            self._port.layout_tests_dir(), 'fast/harness/archived-results-dashboard.html')
        if not self._filesystem.exists(dashboard_file):
            if self._filesystem.exists(dashboard_html_file_path):
                self._filesystem.copyfile(dashboard_html_file_path, dashboard_file)

    def _initialize(self):
        file_list = self._filesystem.listdir(self._results_directory_path)
        results_directories = []
        for dir in file_list:
            full_dir_path = self._filesystem.join(self._results_directory_path, dir)
            if self._filesystem.isdir(full_dir_path):
                if self._results_directory in full_dir_path:
                    results_directories.append(full_dir_path)
        results_directories.sort(reverse=True, key=lambda x: self._filesystem.mtime(x))
        current_failing_results_json_file = self._filesystem.join(results_directories[0], 'failing_results.json')
        input_json_string = self._filesystem.read_text_file(current_failing_results_json_file)
        input_json_string = input_json_string[12:-2]   # Remove preceding string ADD_RESULTS( and ); at the end
        self._current_result_json_dict['tests'] = json.loads(input_json_string)['tests']
        results_directories = results_directories[1:]

        # To add hyperlink to individual results.html
        self._add_individual_result_links(results_directories)

        # Load the remaining stale layout test results Json's to create the dashboard
        for json_file in results_directories:
            failing_json_file_path = self._filesystem.join(json_file, 'failing_results.json')
            full_json_file_path = self._filesystem.join(json_file, 'full_results.json')
            json_string = self._filesystem.read_text_file(failing_json_file_path)
            json_string = json_string[12:-2]   # Remove preceding string ADD_RESULTS( and ); at the end
            self._old_failing_results_list.append(json.loads(json_string))
            json_string_full_result = self._filesystem.read_text_file(full_json_file_path)
            self._old_full_results_list.append(json.loads(json_string_full_result))
        self._copy_dashboard_html()

    def generate(self):
        self._initialize()

        # There must be at least one archived result to be processed
        if self._current_result_json_dict:
            process_json_data = ProcessJsonData(self._current_result_json_dict,
                                                self._old_failing_results_list, self._old_full_results_list)
            self._final_result = process_json_data.generate_archived_result()
            final_json = json.dumps(self._final_result)
            final_json = 'ADD_RESULTS(' + final_json + ');'
            archived_results_file_path = self._filesystem.join(self._results_directory, 'archived_results.json')
            self._filesystem.write_text_file(archived_results_file_path, final_json)
