#
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description: 
#

import os
import logging
import pickle
from optparse import OptionParser, OptionGroup
import cone_common
import generation_report
from cone.public import api, plugin, utils, exceptions


VERSION     = '1.0'

logger    = logging.getLogger('cone')

def main():
    parser = OptionParser(version="%%prog %s" % VERSION)
    
    parser.add_options(cone_common.COMMON_OPTIONS)
    
    group = OptionGroup(parser, 'Report options',
                        'The report function generates a report using previously generated '\
                        'intermediary report data as input.')
    
    group.add_option("-i", "--input-data",\
                        action="append",\
                        help="Defines an input file for report generation. "\
                             "If specified more than once, the data of all specified "\
                             "report data files is merged.",
                        metavar="FILE",
                        default=[])
    
    group.add_option("-d", "--input-data-dir",\
                        help="Defines a directory containing the data files to use for "\
                             "generating the report. This is an alternative to specifying "\
                             "a number of --input-data files. The order of the data files "\
                             "is determined by the generation time stamps found in the data "\
                             "files.",
                        metavar="DIR",
                        default=None)
    
    group.add_option("-r", "--report",\
                   dest="report",\
                   action="store",
                   type="string",
                   help="Specifies the report file to create."\
                        "Example -r report.html.",
                   metavar="FILE",\
                   default="report.html")
    
    group.add_option("-t", "--template",\
                   dest="template",\
                   action="store",
                   type="string",
                   help="Template used in report generation."\
                        "Example -t report_template.html.",
                   metavar="FILE",\
                   default=None)
    
    parser.add_option_group(group)
    (options, args) = parser.parse_args()
    
    cone_common.handle_common_options(options)
    
    if len(options.input_data) == 0 and not options.input_data_dir:
        parser.error("Input data must be specified with either --input-data or --input-data-dir")
    if len(options.input_data) > 0 and options.input_data_dir:
        parser.error("Both --input-data and --input-data-dir specified, use one or the other.")
    if options.input_data_dir and not os.path.isdir(options.input_data_dir):
        parser.error('Given --input-data-dir does not exist or is not a directory.')
    
    if options.input_data:
        files = options.input_data
    else:
        files = get_input_data_files(options.input_data_dir)
    
    if len(files) == 0:
        parser.error("At least one input data file must be specified.")
    
    
    class DataEntry(object):
        def __init__(self, label, data):
            self.label = label
            self.data = data
    
    # Load all data files
    data_entries = []
    for data_file in files:
        print "Loading data file '%s'" % data_file
        label = get_generation_run_label(data_file)
        data = generation_report.load_report_data(data_file)
        data_entries.append(DataEntry(label, data))
    
    # Sort by time stamp
    data_entries.sort(key=lambda entry: entry.data.generation_timestamp)
    
    # Use the first data object as the main report data
    main_entry = data_entries[0]
    
    # Merge the rest of the data objects into the main data
    if len(data_entries) > 1:
        # Update the generation_runs attribute of all implementations
        # in the main data
        for line in main_entry.data.lines:
            for impl in line.impls:
                impl.generation_runs = [main_entry.label]
         
        # Load other report data files and merge them to the main data object
        for i in xrange(len(data_entries) - 1):
            entry = data_entries[i + 1]
            print "Merging data for '%s'" % entry.label
            merge_report_data(main_entry.data, entry.data, entry.label)
 
    # Generate the report
    main_entry.data.report_filename = options.report
    generation_report.generate_report(main_entry.data, options.report, options.template)
    
    print "Generated report to '%s'" % options.report

def get_input_data_files(directory):
    files = []
    for name in os.listdir(directory):
        path = os.path.join(directory, name)
        if os.path.isfile(path):
            files.append(path)
    return files
    

def get_generation_run_label(datafile_path):
    filename = os.path.split(datafile_path)[1]
    filename_noext = os.path.splitext(filename)[0]
    return filename_noext

def get_feature(rep_data, ref):
    for feat in rep_data.lines:
        if feat.ref == ref:
            return feat
    raise RuntimeError("Feature '%s' not found in refs with impl" % ref)

def get_impl(rep_data, ref, impl_name):
    feat = get_feature(rep_data, ref)
    for impl in feat.impls:
        if impl.name == impl_name:
            return impl
    raise RuntimeError("Impl '%s' not found for feature '%s'" % (impl_name, ref))

def merge_report_data(data, data_to_merge, generation_run_label):
    impls_by_ref = {}
    for feat in data.lines:
        impls_dict = {}
        impls_by_ref[feat.ref] = impls_dict
        for impl in feat.impls:
            impls_dict[impl.name] = impl
    
    for feat in data_to_merge.lines:
        if feat.ref in impls_by_ref:
            # Feature has implementations in both report data objects
            # -------------------------------------------------------
            impls_dict = impls_by_ref[feat.ref]
            
            for impl in feat.impls:
                if impl.name in impls_dict:
                    # Same implementation in both: add the generation run to merge to the impl
                    impl = get_impl(data, feat.ref, impl.name)
                    impl.generation_runs.append(generation_run_label)
                else:
                    # Implementation only in the data to merge: add to the main data
                    impl = get_impl(data_to_merge, feat.ref, impl.name)
                    impl.generation_runs = [generation_run_label]
                    feat = get_feature(data, feat.ref)
                    feat.impls.append(impl)
                    feat.nbr_impls += 1
        else:
            # Feature has implementations only in the data to merge
            # -----------------------------------------------------
            
            # Add the feature and impls to the main data
            feat = get_feature(data_to_merge, feat.ref)
            for impl in feat.impls:
                impl.generation_runs = [generation_run_label]
            data.lines.append(feat)
            data.nbr_of_refs += 1
            
            # Remove from features with no impl in the main data
            for i, noimpl_feat in enumerate(data.ref_noimpl):
                if feat.ref == noimpl_feat.ref:
                    del data.ref_noimpl[i]
                    data.nbr_of_refs_noimpl -= 1
                    break

if __name__ == "__main__":
    main()
