#!/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 '
                              r'(\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 (lastname1 > lastname2) - (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)
