#!/usr/bin/python3
#
# Copyright (C) 2012-2013 Vasudev Kamath <kamathvasudev@gmail.com>
#               2011-2012 Muneeb Shaikh <iammuneeb@gmail.com>
#               2011-2012 Shravan Aras <123.shravan@gmail.com>
#
# License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.

import os
import re
import argparse

__version__ = 0.3
##########################################################################
#                                                                        #
# Variables                                                              #
#                                                                        #
##########################################################################

required_files = ["control", "copyright", "changelog", "source", "compat",
                  "rules", "format"]

DEFAULT_MAINTAINER = \
        "Debian Fonts Task Force <pkg-fonts-devel@lists.alioth.debian.org>"

UPLOADERS = (os.environ.get('DEBFULLNAME') +
             " <" + os.environ.get('DEBEMAIL') + ">")\
    if 'DEBEMAIL' in os.environ else "#Please fill in your name and email"

PACKAGE = ""

version_string = '''
dh_makefont - prepare Debian packaging for fonts, version {}

Copyright (C)
 2012-2013 Vasudev Kamath <kamathvasudev@gmail.com>
 2011-2012 Muneeb Shaikh <iammuneeb@gmail.com>
 2011-2012 Shravan Aras <123.shravan@gmail.com>
'''.format(__version__)

GENERATES_TTF = False
GENERATES_OTF = False

font_reg_exp = re.compile("((.)*\.ttf|sfd|otf)")  # RE to check
font_sfd_regx = re.compile("((.)*\.sfd)")         # RE check font source file
generate_function = re.compile("Generate\(.*\)")

font_source = False

watch = '''
version=3
#please put upstream url for watch expression
'''


# This section of code parses the command line arguments.
arguments = argparse.ArgumentParser(
    prog='dh_makefont',
    description='dh_makefont',
    formatter_class=argparse.RawTextHelpFormatter,
    epilog='Font package helper')
arguments.add_argument('-c', '--copyright',
                       help='''use <type> of license in copyright file
                            (apache|artistic|bsd|gpl|gpl2|gpl3|lgpl|lgpl2|
                             lgpl3|x11)''')
arguments.add_argument('-p', '--package',
                       help='''force package name to be <name>
                            if name_version is given this will set version
                            number of package bypassing the directory
                            checking.''')
arguments.add_argument('--maint',
                       help='''Override default *Maintainer* which is
                             Debian Fonts Task Force
                             <pkg-fonts-devel@lists.alioth.debian.org>''')
arguments.add_argument('foldername',
                       help='Extracted folder containing fonts')

arguments.add_argument('-u', '--upstream',
                       help='''Provide an upstream URL. If this value is provided
                               it will be substituted in control and copyright
                               file''')

arguments.add_argument('-v', '--version', action='version',
                       help='Show the version number of dh_makefont',
                       version=version_string)


###########################################################################
#                                                                         #
#  Validation functions                                                   #
#                                                                         #
###########################################################################

def check_files():
    """
    This function checks if there is either .ttf .otf or .sfd
    file in the given folder. If that file is present only then
    we will continue after all this tool is for font packaging :)

    `-return` 0 if one of the .sfd .ttf or .otf file is present
    -1 other wise
    """
    global font_source
    # We need to perform a directory traversal to find .ttf .otf or .sfd.
    # Any one will do. [We are so kind arn't we]
    for dirpath, dirnames, filenames in os.walk('.'):
        for filename in filenames:
            if font_reg_exp.search(filename):
                if font_sfd_regx.search(filename):
                    font_source = True
                return 0
        return -1  # No need to go into sub directories
    return -1


def check_generatepe(filepath):
    global GENERATES_TTF, GENERATES_OTF
    with open(filepath) as fd:
        content = fd.read()
        if generate_function.search(content):
            # We did find Generate function
            for function in generate_function.findall(content):
                if function.find('.ttf') != -1:
                    GENERATES_TTF = True
                    break
                elif function.find('.otf') != -1:
                    GENERATES_OTF = True
                    break


###########################################################################
#                                                                         #
# Functions which edit the files inside debian/ folder of package         #
#                                                                         #
###########################################################################

def update_control_file(args):
    """
    This function updates the control file which is generated by dh_make
    1. Section is set to fonts
    2. Priority optional
    3. if Maintainer is not overridden by --maint DEFAULT_MAINTAINER
       else use value given by user with --maint
    4. Uploaders is added using DEBEMAIL and DEBFULLNAME environment
       variable
    5. Build-Depends will have fontforge dependency as a comment in
       case upstream provides .sfd, user can uncomment it.
    6. Architecture is changed to all
    7. shlibs depends is removed from Depends

    All remaining are kept as is and finally written back to control file
    """
    control_content = ""
    with open('control', "rb") as fd:
        contents = fd.read().split('\n')
        for line in contents:
            if line.startswith('Maintainer:'):
                if args.maint:
                    control_content += "Maintainer: "+args.maint
                else:
                    control_content += "Maintainer: " + DEFAULT_MAINTAINER
                    control_content += "\nUploaders: "+UPLOADERS
            elif line.startswith('Build-Depends:'):
                if font_source:
                    control_content += line + ", fontforge"
                else:
                    control_content += line
            elif line.startswith('Architecture:'):
                control_content += "Architecture: all"
            elif line.startswith('Section:'):
                control_content += "Section: fonts"
            elif line.startswith('Priority:'):
                control_content += "Priority: optional"
            elif line.startswith('Depends:'):
                control_content += "Depends: ${misc:Depends}"
            elif line.startswith('Homepage:') and args.upstream:
                control_content += "Homepage: " + args.upstream
            elif line.startswith('#Vcs-Git:') and not args.maint:
                control_content += '#Vcs-Git:' +\
                        'https://anonscm.debian.org/git/pkg-fonts/{}.git'.\
                        format(PACKAGE)
            elif line.startswith('#Vcs-Browser:') and not args.maint:
                control_content += "Vcs-Browser: " +\
                        'https://anonscm.debian.org/cgit/collab-maint/{}.git'.\
                        format(PACKAGE)
            else:
                control_content += line

            control_content += "\n"

    with open('control', 'wb') as fd:
        fd.write(control_content)


def update_copyright_file(args):
    """
    `args`: Command line arguments
    This function prepares copyright file in debian copyright-format 1.0.
    """
    copyright_content = ""
    with open('copyright', 'rb') as fd:
        contents = fd.read()
        contents = contents.split('\n')
        for line in contents:
            if line.startswith('Format:'):
                copyright_content += "Format: "\
                        "http://www.debian.org/doc/packaging-manuals/"\
                        "copyright-format/1.0/"
            elif line.startswith('Source:') and args.upstream:
                copyright_content += "Source: " + args.upstream
            else:
                copyright_content += line

            copyright_content += '\n'

    with open('copyright', 'wb') as fd:
        fd.write(copyright_content)


def create_install_and_links():
    """
    This function writes install file it checks for availability of
    ttf or otf file and writes a proper install file also if a font
    config .conf file is available creates a links file to do proper
    linking
    """
    global PACKAGE
    install = ""
    install_dir = PACKAGE.split('fonts-')[1]

    for dirpath, dirnames, filenames in os.walk('..'):
        if dirnames != 'debian':
            for filename in filenames:
                if filename.endswith('.ttf'):
                    install += "./{} usr/share/fonts/truetype/{}/\n".format(
                            filename, install_dir)
                elif filename.endswith('.otf'):
                    install += "./{} usr/share/fonts/truetype/{}/\n".format(
                            filename, install_dir)
                elif filename.endswith('.sfd'):
                    if 'generate.pe' in filenames:
                        check_generatepe(os.path.join(dirpath,
                                         filenames[filenames.index(
                                             'generate.pe')]))
                        if GENERATES_TTF:
                            install += "./{} usr/share/fonts/truetype/{}/\n".\
                                    format(filename.replace('sfd', 'ttf'),
                                           install_dir)
                        elif GENERATES_OTF:
                            install += "./{} usr/share/fonts/opentype/{}/\n".\
                                    format(filename.replace('sfd', 'otf'),
                                           install_dir)
                        else:
                            print("\n*Unable to determine if source generates"\
                                    "TTF or OTF file.\n\Please manually edit"\
                                    "the debian/install file*")
                    else:
                        print("\n*Unable to determine if source generates"\
                                "TTF or OTF file.\nPlease manually edit"\
                                "the debian/install file*")

                elif filename.endswith('.conf'):
                    install += "./{} etc/fonts/conf.avail".format(filename)
                    print("\nFound a fontconfig configuration file."\
                          "Added it to debian/install")
                    with open('links', 'w') as fd:
                        fd.write('etc/fonts/conf.avail/'+filename +
                                 ' etc/fonts/conf.d/'+filename)
                        print("\nI've symlinked conf file in etc/fonts/conf.d"\
                              ".\nPlease update fontconfig priority"\
                              "appropriately")

    with open('install', 'w') as fd:
        fd.write(install)


###########################################################################
#                                                                         #
#  dh_make helper function                                                #
#                                                                         #
###########################################################################

def call_dh_make(args):
    """
    `-args`: Arguments passed to this script this is of type NameSpace
             class returned by argparse.parse_args
    `-return`: Returns 0 like all other *nix utilities on success and non
               zero value on error. Error should be documented in dh_make
               manual

   This function is a wrapper over the dh_make command
    """
    global PACKAGE

    # Stores the final argument to be passed to dh_make
    args_string = " -createorig"

    if(args.copyright):
        args_string += " -c "+args.copyright
    if(args.package):
        args_string += " -p "+args.package
        PACKAGE = args.package.split('_')[0] \
            if args.package.find('_') else args.package
    else:
        """
        If user has not supplied -p or --package option which should be
        passed to dh_make then we will do it ourselves rather than allowing
        dh_make to decide

        According to pkg-fonts policy font package should be named
        `fonts-<foundry>-something` where foundry is optional.

        1. We will check if folder name begins with fonts- if yes we will pass
           it to dh_make with -p option.
        2. If it doesn't we will create package name by appending fonts- to
           `foldername`

        Additionally foldername-version is changed to foldername_version which
        is expected by dh_make as value for -p option

        In case of any error dh_make will bark at you and not me :)
        """

        folder = ""
        if args.foldername.count('-') > 1:
            """
            If we have more than one - in foldername that means foldername is
            in format folder-name-version. So lets split on - and join first
            2 part again on - and join last part with the latter with _ in
            between

            #FIXME: Bad English?
            #FIXME: Any better way?
            """
            folder_split = args.foldername.split('-')
            folder = ('-').join(folder_split[:-1]) + '_' + folder_split[-1]
        elif args.foldername.count('-') == 1:
            """
            If there is only one - we are happy :)
            """
            folder = args.foldername.replace('-', '_')

        if not folder.startswith('fonts-'):
            args_string += " -p fonts-" + folder
            folder = 'fonts-' + folder
        else:
            args_string += " -p " + folder

        PACKAGE = folder.split('_')[0] if folder.find('_') else folder

    # Make a call to the system function.
    return os.system("dh_make"+args_string)


###########################################################################
#                                                                         #
#  Generic functions                                                      #
#                                                                         #
###########################################################################

def print_todo():
        print("""
**************************************************
       TODO for the maintainers
**************************************************

    1. Please add short and long description in debian/control file
    2. Please add appropriate lines in debian/changelog
    3. Please add DEP5 format URI in debian/copyright
    4. Please add fonts copyright in debian/copyright
    5. Check debian/install and debian/links if they exist
    6. If font is built from source make sure font name and install target is
       proper in debian/install
    8. Please check Vcs-* field and modify accordingly, if maintaining under
       pkg-fonts its preferred to leave as is.
    7. Build the package and enjoy!
""")


def main():
    """
    Main part of the script. Kept in separate function to have a good
    redability
    """
    args = arguments.parse_args()

    os.chdir(os.path.abspath(args.foldername))

    if(check_files()):
        print("I could not find .ttf, .sfd, .otf."\
              "At least one should be present.")
        exit(256)

    if(call_dh_make(args)):
        print("dh_makefont: dh_make died so I die.")
        exit(256)

    # Lets get into Debian directory and work there
    os.chdir(os.path.abspath('debian'))

    # Remove unwanted files for font package
    for dirpath, dirname, filenames in os.walk('.'):
        for filename in filenames:
            if filename not in required_files:
                os.remove(filename)

    # Write a proper watch file
    with open('watch', 'w') as fd:
        fd.write(watch)

    # Fix control file
    update_control_file(args)

    # Fix copyright ile
    update_copyright_file(args)

    # Create install and links file
    create_install_and_links()

    # We are done tell packager what he needs to check
    print_todo()


if __name__ == "__main__":
        main()
