#!/usr/bin/env python
#
#  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.
#
# Script which generates markdown formatted list of contributors. It generates
# this list by parsing the "CHANGES" file.
#
# Usage:
#
# 1. Generate a list of contributors with tickets for all versions:
#
# ./contrib/generate_contributor_list.py --changes-path=CHANGES.rst \
#                                         --include-tickets
#
# 2. Generate a list of contributors for a release without tickets
#
# ./contrib/generate_contributor_list.py --changes-path=CHANGES.rst \
#                                        --versions=0.13.0
# 3. Generate a list of contributors with tickets for multiple versions
#
# ./contrib/generate_contributor_list.py --changes-path=CHANGES.rst \
#                                         --include-tickets
#                                         --versions 0.11.0 0.12.0

from __future__ import with_statement

import re
import argparse
from collections import defaultdict

JIRA_URL = 'https://issues.apache.org/jira/browse/LIBCLOUD-%s'
GITHUB_URL = 'https://github.com/apache/libcloud/pull/%s'


def parse_changes_file(file_path, versions=None):
    """
    Parse CHANGES file and return a dictionary with contributors.

    Dictionary maps contributor name to the JIRA tickets or Github pull
    requests the user has worked on.
    """
    # Maps contributor name to a list of JIRA tickets
    contributors_map = defaultdict(set)

    in_entry = False
    active_version = None
    active_tickets = []

    with open(file_path, 'r') as fp:
        for line in fp:
            line = line.strip()

            match = re.search(r'Changes with Apache Libcloud '
                              '(\d+\.\d+\.\d+(-\w+)?).*?$', line)

            if match:
                active_version = match.groups()[0]

            if versions and active_version not in versions:
                continue

            if line.startswith('-') or line.startswith('*)'):
                in_entry = True
                active_tickets = []

            if in_entry and line == '':
                in_entry = False

            if in_entry:
                match = re.search(r'\((.+?)\)$', line)

                if match:
                    active_tickets = match.groups()[0]
                    active_tickets = active_tickets.split(', ')
                    active_tickets = [ticket for ticket in active_tickets if
                                      ticket.startswith('LIBCLOUD-') or
                                      ticket.startswith('GITHUB-')]

                match = re.search(r'^\[(.+?)\]$', line)

                if match:
                    contributors = match.groups()[0]
                    contributors = contributors.split(',')
                    contributors = [name.strip() for name in contributors]

                    for name in contributors:
                        name = name.title()
                        contributors_map[name].update(set(active_tickets))

    return contributors_map


def convert_to_markdown(contributors_map, include_tickets=False):

    # Contributors are sorted in ascending lexiographical order based on their
    # last name
    def compare(item1, item2):
        lastname1 = item1.split(' ')[-1].lower()
        lastname2 = item2.split(' ')[-1].lower()
        return cmp(lastname1, lastname2)

    names = contributors_map.keys()
    names = sorted(names, cmp=compare)

    result = []
    for name in names:
        tickets = contributors_map[name]

        tickets_string = []

        for ticket in tickets:
            if '-' not in ticket:
                # Invalid ticket number
                continue

            number = ticket.split('-')[1]

            if ticket.startswith('LIBCLOUD-'):
                url = JIRA_URL % (number)
            elif ticket.startswith('GITHUB-') or ticket.startswith('GH-'):
                url = GITHUB_URL % (number)

            values = {'ticket': ticket, 'url': url}
            tickets_string.append('[%(ticket)s](%(url)s)' % values)

        tickets_string = ', '.join(tickets_string)

        if include_tickets:
            line = '* %(name)s: %(tickets)s' % {'name': name,
                                                'tickets': tickets_string}
        else:
            line = '* %(name)s' % {'name': name}

        result.append(line.strip())

    result = '\n'.join(result)
    return result

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Assemble provider logos '
                                                 ' in a single image')
    parser.add_argument('--changes-path', action='store', required=True,
                        help='Path to the changes file')
    parser.add_argument('--versions', action='store', nargs='+',
                        type=str,
                        help='Only return contributors for the provided '
                             'versions')
    parser.add_argument('--include-tickets', action='store_true',
                        default=False,
                        help='Include ticket numbers')
    args = parser.parse_args()

    contributors_map = parse_changes_file(file_path=args.changes_path,
                                          versions=args.versions)
    markdown = convert_to_markdown(contributors_map=contributors_map,
                                   include_tickets=args.include_tickets)

    print(markdown)
