#!/usr/bin/env python
import re
import os
from subprocess import Popen


HERE = os.path.abspath(os.path.dirname(__file__))
BASE = os.path.dirname(HERE)
OUT = os.path.join(BASE, 'build')
TMP = os.path.join(OUT, 'tmp')

GENERIC_ICON = (
    '/System/Library/CoreServices/CoreTypes.bundle/Contents/'
    'Resources/GenericDocumentIcon.icns'
)
GENERIC_VOL_ICON = (
    '/System/Library/Extensions/IOStorageFamily.kext/Contents/'
    'Resources/Removable.icns'
)

FONT = '/System/Library/Fonts/SFNSText-Bold.otf'
DOC_ICON = os.path.join(TMP, 'GenericDocumentIcon.iconset')
REMOVABLE_DISK_ICON = os.path.join(TMP, 'Removable.iconset')
APP_ICON = os.path.join(BASE, 'resources', 'Icon.iconset')
APP_ICNS = os.path.join(BASE, 'build', 'Lektor.icns')
FT_ICON = os.path.join(TMP, 'File.iconset')
FT_ICNS = os.path.join(BASE, 'build', 'File.icns')
FTP_ICON = os.path.join(TMP, 'ProjectFile.iconset')
FTP_ICNS = os.path.join(BASE, 'build', 'ProjectFile.icns')
VOL_ICON = os.path.join(TMP, 'Volume.iconset')
VOL_ICNS = os.path.join(BASE, 'build', 'Volume.icns')

for _path in TMP, FT_ICON, FTP_ICON, VOL_ICON:
    try:
        os.makedirs(_path)
    except OSError:
        pass


def find_blend_source(target_size, retina):
    size = (target_size[0] / 2, target_size[1] / 2)
    if retina:
        fn = os.path.join(APP_ICON, 'icon_%dx%d@2x.png' %
                          (size[0] / 2, size[1] / 2))
        if os.path.isfile(fn):
            return fn
    fn = os.path.join(APP_ICON, 'icon_%dx%d.png' % size)
    if os.path.isfile(fn):
        return fn

    fn = os.path.join(APP_ICON, 'icon_%dx%d.png' % target_size)
    if os.path.isfile(fn):
        return fn


Popen(['iconutil', '--convert', 'iconset',
       '--output', DOC_ICON, GENERIC_ICON]).wait()
Popen(['iconutil', '--convert', 'iconset',
       '--output', REMOVABLE_DISK_ICON, GENERIC_VOL_ICON]).wait()


def scale_coords(coords, size):
    return [
        ((a[0] * size[0], a[1] * size[1]),
         (b[0] * size[0], b[1] * size[1]))
        for a, b in coords
    ]


def make_icon(path, text=None, alpha=1.0, offset_func=None,
              resize_func=None, perspective=None, base_icon=DOC_ICON):
    if offset_func is None:
        offset_func = lambda s: (s[0] / 4, s[1] / 4)
    if resize_func is None:
        resize_func = lambda s: (s[0] / 2, s[1] / 2)
    for filename in os.listdir(base_icon):
        if not filename.endswith('.png'):
            continue
        size = tuple(map(int, re.search('(\d+)x(\d+)', filename).groups()))
        actual_size = size
        retina = False
        if '@2x' in filename:
            actual_size = tuple(x * 2 for x in size)
            retina = True

        blend_source = find_blend_source(actual_size, retina)
        if blend_source is None:
            print 'missing source for', size, retina
            continue

        offset = offset_func(actual_size)
        resize_to = resize_func(actual_size)

        commands = [
            os.path.join(base_icon, filename), '(',
            blend_source,
            '-resize', '%dx%d' % resize_to,
            '-sharpen', actual_size[1] <= 16 and '0x2' or '0x0',
            '-channel', 'A', '-evaluate', 'multiply', str(alpha),
        ]
        if perspective is not None:
            commands.extend([
                '-virtual-pixel', 'transparent',
                '+distort', 'Perspective',
                ' '.join('%s,%s %s,%s' % (tup[0] + tup[1])
                         for tup in scale_coords(perspective, resize_to)),
            ])
        commands.extend([
            '-geometry', '+%d+%d' % offset, ')',
            '-composite',
        ])

        if size[1] >= 128 and text is not None:
            text_block = (actual_size[0] / 5 * 3, actual_size[1] / 7)
            offset_text = actual_size[1] / 3
            commands.extend((
                '(',
                '-background', 'transparent',
                '-size', '%dx%d' % text_block,
                '-geometry', '+0+%d' % offset_text,
                '-gravity', 'center',
                '-font', FONT,
                '-fill', '#636363',
                'label:' + text,
                ')',
                '-composite'
            ))

        commands.append(os.path.join(path, filename))

        Popen(['convert'] + commands).wait()


make_icon(FT_ICON, 'TEXT', alpha=0.65)
make_icon(FTP_ICON, 'PROJECT')
make_icon(VOL_ICON, base_icon=REMOVABLE_DISK_ICON,
          offset_func=lambda s: (int(s[0] * 0.1), int(s[0] * 0.07)),
          resize_func=lambda s: (int(s[0] * 0.8), int(s[0] * 0.8)),
          perspective=[((0.0, 0.0), (0.2, 0.3)),
                       ((1.0, 0.0), (0.8, 0.3)),
                       ((0.0, 1.0), (0.0, 1.0)),
                       ((1.0, 1.0), (1.0, 1.0))])

Popen(['iconutil', '--convert', 'icns',
       '--output', FT_ICNS, FT_ICON]).wait()
Popen(['iconutil', '--convert', 'icns',
       '--output', FTP_ICNS, FTP_ICON]).wait()
Popen(['iconutil', '--convert', 'icns',
       '--output', APP_ICNS, APP_ICON]).wait()
Popen(['iconutil', '--convert', 'icns',
       '--output', VOL_ICNS, VOL_ICON]).wait()
