#!/usr/bin/env python
#
#  Copyright (C) 2022, 2024
#  MIT
#
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
'''Git pre-commit hook to update the copyright year in Sherpa code files
'''
from __future__ import print_function
import datetime
import fileinput
import re
import subprocess
import sys

year = datetime.datetime.now().year
copyr = re.compile(r"(?P<comment>(#|//))\s*Copyright \(C\) (?P<years>[0-9,\s\-]+)(?P<institution>[\w\s]*)")
# Only apply this to C or Python files since sherpa does not use
# copyright statements in others files, also, do not change in extern
# directory.
ftype = re.compile(r"^((?!extern).)*(hh|cc|c|h|py)$")
changed = 0

def split_years(years: str) -> list[int]:
    '''Split a string of years into a list of integers

    This expands ranges of years, e.g. "2010-2012" becomes
    [2010, 2011, 2012]

    Parameters
    ----------
    years : str
        A comma-separated list of years, with ranges separated by a dash.
    '''
    list_years = []
    for y in years.split(','):
        if '-' in y:
            start, end = y.split('-')
            list_years.extend(range(int(start), int(end) + 1))
        else:
            list_years.append(int(y))
    return list_years


def combine_years(list_years: list[int]) -> str:
    '''Combine a list of years into a string

    This combines consecutive years into ranges, e.g. [2010, 2011, 2012]
    becomes "2010-2012".
    '''
    list_years = list(set(list_years))
    list_years.sort()
    combined = []
    start = list_years[0]
    finish = list_years[0]
    for y in list_years[1:]:
        if y == finish + 1:
            finish = y
        else:
            if start == finish:
                combined.append(str(start))
            else:
                combined.append(str(start) + '-' + str(finish))
            start = y
            finish = y

    if start == finish:
        combined.append(str(start))
    else:
        combined.append(str(start) + '-' + str(finish))

    return ', '.join(combined)


if __name__ == '__main__':

    proc = subprocess.Popen("git diff --name-only --staged",
                            shell=True, stdout=subprocess.PIPE)
    filenames = proc.stdout.read().decode().split()
    filenames = [f for f in filenames if ftype.match(f)]

    for f in filenames:
        try:
            for line in fileinput.input(files=filenames, inplace=True):
                m = copyr.match(line)
                if m:
                    list_years = split_years(m.group('years'))
                if m and year not in list_years:
                    list_years.append(year)
                    changed = 1
                    print(m.group('comment') +
                          '  Copyright (C) ' + combine_years(list_years), end='\n')
                    # sometimes group institution will be empty, because it's
                    # on the next text line. If not, move it there.
                    if m.group('institution'):
                        print(m.group('comment') +
                              '  ' + m.group('institution'), end='')
                else:
                    print(line, end='')
            # The following line would automatically commit the changes
            # but we need some more experience to check the changes by hand
            # before we activate that.
            # subprocess.Popen("git add " + f, shell=True)
        except FileNotFoundError:
            # file was removed with "git rm" so there is nothing to check here
            pass

    if changed:
        print("""Message from your pre-commit hook script:
I updated copyright statements in one or more files for you.
After doing that, I aborted the commit, so you can check yourself that
it's alright before you commit again.
Commit with ' --no-verify' option to skip this check.""", file=sys.stderr)
        sys.exit(changed)
