# -*- coding: utf-8 -*-
#
# Copyright © 2013 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see winpython/__init__.py for details)

"""
WinPython diff script

Created on Tue Jan 29 11:56:54 2013
"""

from __future__ import print_function, with_statement

import os
import os.path as osp
import re
import shutil

# Local imports
from winpython import utils


CHANGELOGS_DIR = osp.join(osp.dirname(__file__), 'changelogs')
assert osp.isdir(CHANGELOGS_DIR)


class Package(object):
    # SourceForge Wiki syntax:
    PATTERN = r'\[([a-zA-Z\-\:\/\.\_0-9]*)\]\(([^\]\ ]*)\) \| ([^\|]*) \| ([^\|]*)'
    # Google Code Wiki syntax:
    PATTERN_OLD = r'\[([a-zA-Z\-\:\/\.\_0-9]*) ([^\]\ ]*)\] \| ([^\|]*) \| ([^\|]*)'

    def __init__(self):
        self.name = None
        self.version = None
        self.description = None
        self.url = None

    def __str__(self):
        text = "%s %s" % (self.name, self.version)
        text += "\r\n%s\r\nWebsite: %s" % (self.description, self.url)
        return text

    def from_text(self, text):
        try:
            self.url, self.name, self.version, self.description = \
                                    re.match(self.PATTERN_OLD, text).groups()
        except AttributeError:
            self.name, self.url, self.version, self.description = \
                                        re.match(self.PATTERN, text).groups()

    def to_wiki(self):
        return "  * [%s](%s) %s (%s)\r\n" % (self.name, self.url,
                                             self.version, self.description)

    def upgrade_wiki(self, other):
        # wheel replace '-' per '_' in package name
        assert self.name.replace('-', '_').lower() == other.name.replace('-', '_').lower()
        return "  * [%s](%s) %s → %s (%s)\r\n" % (self.name, self.url,
                                other.version, self.version, self.description)


class PackageIndex(object):
    WINPYTHON_PATTERN = r'\#\# WinPython\-*[0-9b-t]* ([0-9\.a-zA-Z]*)'
    TOOLS_LINE = '### Tools'
    PYTHON_PACKAGES_LINE = '### Python packages'
    HEADER_LINE1 = 'Name | Version | Description'
    HEADER_LINE2 = '-----|---------|------------'

    def __init__(self, version, basedir=None, flavor='', architecture=64):
        self.version = version
        self.other_packages = {}
        self.python_packages = {}
        self.flavor = flavor
        self.basedir = basedir
        self.architecture = architecture
        self.from_file(basedir)

    def from_file(self, basedir):
        #fname = osp.join(basedir, 'build%s' % self.flavor,
        fname = osp.join(CHANGELOGS_DIR,
                         'WinPython%s-%sbit-%s.md' % (self.flavor,
                         self.architecture, self.version))
        with open(fname, 'r') as fdesc:  # python3 doesn't like 'rb'
            text = fdesc.read()
        self.from_text(text)

    def from_text(self, text):
        version = re.match(self.WINPYTHON_PATTERN+self.flavor, text).groups()[0]
        assert version == self.version
        tools_flag = False
        python_flag = False
        for line in text.splitlines():
            if line:
                if line == self.TOOLS_LINE:
                    tools_flag = True
                    continue
                elif line == self.PYTHON_PACKAGES_LINE:
                    tools_flag = False
                    python_flag = True
                    continue
                elif line in (self.HEADER_LINE1, self.HEADER_LINE2):
                    continue
                if tools_flag or python_flag:
                    package = Package()
                    package.from_text(line)
                    if tools_flag:
                        self.other_packages[package.name] = package
                    else:
                        self.python_packages[package.name] = package


def diff_package_dicts(dict1_in, dict2_in):
    """Return difference between package dict1 and package dict2"""
    text = ""
    # wheel replace '-' per '_' in key
    dict1 = {} ; dict2 = {}
    for key in dict1_in:
        dict1[key.replace('-','_').lower()] = dict1_in[key]
    for key in dict2_in:
        dict2[key.replace('-','_').lower()] = dict2_in[key]

    set1, set2 = set(dict1.keys()), set(dict2.keys())
    # New packages
    new = sorted(set2 - set1)
    if new:
        text += "New packages:\r\n\r\n"
        for name in new:
            package = dict2[name]
            text += package.to_wiki()
        text += '\r\n'
    # Upgraded packages
    upgraded_list = []
    for name in sorted(set1 & set2):
        package1 = dict1[name]
        package2 = dict2[name]
        if package1.version != package2.version:
            upgraded_list.append(package2.upgrade_wiki(package1))
    if upgraded_list:
        text += "Upgraded packages:\r\n\r\n%s\r\n" % "".join(upgraded_list)
    # Removed packages
    removed = sorted(set1 - set2)
    if removed:
        text += "Removed packages:\r\n\r\n"
        for name in removed:
            package = dict1[name]
            text += package.to_wiki()
        text += '\r\n'
    return text


def find_closer_version(version1, basedir=None, flavor='', architecture=64):
    """Find version which is the closest to `version`"""
    builddir = osp.join(basedir, 'build%s' % flavor)
    func = lambda name: re.match(r'WinPython%s-%sbit-([0-9\.]*)\.(txt|md)' %
                                (flavor, architecture), name)
    versions = [func(name).groups()[0]
                for name in os.listdir(builddir) if func(name)]
    try:
        index = versions.index(version1)
    except ValueError:
        raise ValueError("Unknown version %s" % version1)
    if index == 0:
        print("No version prior to %s" % version1)
        index += 1  # we don't want to fail on this
    return versions[index-1]


def compare_package_indexes(version2, version1=None, basedir=None, flavor='',
flavor1=None, architecture=64):
    """Compare two package index Wiki pages"""
    if version1 is None:
        version1 = find_closer_version(version2, basedir=basedir,
                                       flavor=flavor, architecture=architecture)
    flavor1 = flavor1 if flavor1 is not None else flavor    
    text = '\r\n'.join(["## History of changes for WinPython-%sbit %s" % 
                        (architecture, version2+flavor),
                        "", "The following changes were made to WinPython-%sbit"
                        " distribution since version %s." % (architecture,
                                                            version1+flavor1),
                        "", ""])
    pi1 = PackageIndex(version1, basedir=basedir, flavor=flavor1, architecture=architecture)
    pi2 = PackageIndex(version2, basedir=basedir, flavor=flavor, architecture=architecture)
    tools_text = diff_package_dicts(pi1.other_packages, pi2.other_packages)
    if tools_text:
        text += PackageIndex.TOOLS_LINE + '\r\n\r\n' + tools_text
    py_text = diff_package_dicts(pi1.python_packages, pi2.python_packages)
    if py_text:
        text += PackageIndex.PYTHON_PACKAGES_LINE + '\r\n\r\n' + py_text
    text += '* * *\r\n'
    return text


def _copy_all_changelogs(version, basedir, flavor='', architecture=64):
    basever = '.'.join(version.split('.')[:2])
    for name in os.listdir(CHANGELOGS_DIR):
        if re.match(r'WinPython%s-%sbit-%s([0-9\.]*)\.(txt|md)' %
                    (flavor, architecture, basever), name):
            shutil.copyfile(osp.join(CHANGELOGS_DIR, name),
                            osp.join(basedir, 'build%s' % flavor, name))


def write_changelog(version2, version1=None, basedir=None, flavor='',
                    release_level='', architecture=64):
    """Write changelog between version1 and version2 of WinPython"""
    _copy_all_changelogs(version2, basedir, flavor=flavor, architecture=architecture)
    print ('comparing_package_indexes', version2, basedir, flavor, architecture)
    text = compare_package_indexes(version2, version1, basedir=basedir,
                                   flavor=flavor, architecture=architecture)
    fname = osp.join(basedir, 'build%s' % flavor,
                     'WinPython%s-%sbit-%s_History.md' % (flavor, architecture,
                                                          version2))
    with open(fname, 'w', encoding='utf-8-sig') as fdesc:  # python 3 need
        fdesc.write(text)
    # Copy to winpython/changelogs
    shutil.copyfile(fname, osp.join(CHANGELOGS_DIR, osp.basename(fname)))


def test_parse_package_index_wiki(version, basedir=None, flavor='', architecture=64):
    """Parse the package index Wiki page"""
    pi = PackageIndex(version, basedir=basedir, flavor=flavor, architecture=architecture)
    utils.print_box("WinPython %s:" % pi.version)
    utils.print_box("Tools:")
    for package in pi.other_packages.values():
        print(package)
        print('')
    utils.print_box("Python packages:")
    for package in pi.python_packages.values():
        print(package)
        print('')


def test_compare(basedir, version2, version1, architecture=64):
    print(compare_package_indexes(basedir, version2, version1,
                                  architecture=architecture))


if __name__ == '__main__':
    print (compare_package_indexes('3.6.1.1', '3.6.1.0', 
           basedir='D:\Winpython\basedir36', flavor='Qt5', flavor1='Qt5', architecture=32))
    # test_parse_package_index_wiki('2.7.3.3')
    # print(compare_package_indexes('2.7.3.3', '2.7.3.1'))
    # write_changelog('2.7.4.1', '2.7.4.0')
    # write_changelog('3.3.0.0beta2', '3.3.0.0beta1')
