#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (C) 2010-2013 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
# 
# PyHoca is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# PyHoca 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# import the PyHoca-GUI
import sys
import os

PROGRAM_NAME = 'PyHoca-GUI'
PROGRAM_DESC = '%s is a cross-platform (Windows, MacOS X, Linux) graphical X2Go client.' % PROGRAM_NAME
for line in file(os.path.join('pyhoca', 'wxgui', '__init__.py')).readlines():
    if (line.startswith('__VERSION__')):
        exec(line.strip())
PROGRAM_VERSION = __VERSION__
PROGRAM_ICON = "pixmaps/pyhoca_x2go-logo-ubuntu.ico"
LICENSE = 'AGPLv3+'
AUTHOR = 'Mike Gabriel, Dick Kniep'
URL = 'http://www.x2go.org'
LIBRARY_ZIP = r"lib\shardlib.zip"

from setuptools import setup, find_packages
from distutils.core import setup, Command
import platform

base = None
executables = []
if platform.system() == 'Windows':
    default_win32exe_freezer = 'bbfreeze'
    NSIS_COMPILE = os.path.join(os.environ['ProgramFiles'], 'NSIS', 'makensis.exe')
    if 'build_with_py2exe' in (sys.argv[1], 'build_with_{freezer}'.format(freezer=default_win32exe_freezer)):
        from py2exe.build_exe import py2exe
        Freezer = object
    elif 'build_with_bbfreeze' in (sys.argv[1], 'build_with_{freezer}'.format(freezer=default_win32exe_freezer)):
        from bbfreeze import Freezer
        py2exe = object
    else:
        py2exe = object
        Freezer = object
    import os, os.path
    import subprocess
    sys.path.append(os.path.normpath('../pyhoca-contrib/mswin/ms-vc-runtime'))

elif platform.system() == 'Linux':
    from DistUtilsExtra.command import *
    py2exe = object
    Freezer = object

from glob import glob
import shutil

from nsis_template import NSIS_SCRIPT_TEMPLATE

#
# to build .exe file, run on Windows:
# ,,python setup.py py2exe''
#
# to update i18n .mo files (and merge .pot file into .po files) run on Linux:
# ,,python setup.py build_i18n -m''

cmd_class = {}
data_files = []

def datafilelist(installbase, sourcebase):
    datafileList = []
    for root, subFolders, files in os.walk(sourcebase):
        fileList = []
        for f in files:
            fileList.append(os.path.join(root, f))
        datafileList.append((root.replace(sourcebase, installbase), fileList))
    return datafileList


class NSISScript(object):

    def __init__(self, program_name, program_desc, program_version, dist_dir, icon_loc):
        self.program_name = program_name
        self.program_desc =  program_desc
        self.program_version = program_version
        self.dist_dir = dist_dir
        self.icon_loc = icon_loc
        self.pathname = "setup_%s.nsi" % self.program_name

    def create(self):
        contents = NSIS_SCRIPT_TEMPLATE.format(
                    program_name = self.program_name,
                    program_version = self.program_version,
                    program_desc = self.program_desc,
                    output_dir = self.dist_dir,
                    icon_location = os.path.join(self.dist_dir, self.icon_loc))

        with open(self.pathname, "w") as outfile:
            outfile.write(contents)

    def compile(self):
        subproc = subprocess.Popen(
            # "/P5" uses realtime priority for the LZMA compression stage.
            # This can get annoying though.
            [NSIS_COMPILE, self.pathname, "/P5"], env=os.environ)
        subproc.communicate()

        retcode = subproc.returncode

        if retcode:
            raise RuntimeError("NSIS compilation return code: %d" % retcode)


class build_installer(object):

    # This class first invokes building the the exe file(s) and then creates an NSIS
    # installer
    def __init__(self, dist_dir):
        self.dist_dir = dist_dir

    def do_build_exe(self):
        # replace this method with the freezer's build_exe logic
        pass

    def run(self):

        # clean up dist_dir
        shutil.rmtree(self.dist_dir, ignore_errors=True)
        # and recreate a clean one afterwards
        os.makedirs(self.dist_dir)

        # First, build the exe file
        self.do_build_exe()

        # Create the installer, using the files py2exe has created.
        script = NSISScript(
                            PROGRAM_NAME,
                            PROGRAM_DESC,
                            PROGRAM_VERSION,
                            self.dist_dir,
                            os.path.normpath(PROGRAM_ICON)
                           )
        print "*** creating the NSIS setup script***"
        script.create()
        print "*** compiling the NSIS setup script***"
        script.compile()


class build_installer_py2exe(build_installer, py2exe):

    def __init__(self, *args, **kwargs):
        py2exe.__init__(self, *args, **kwargs)
        build_installer.__init__(self, dist_dir=self.dist_dir)

    def do_build_exe(self):

        # First, let py2exe do it's work.
        py2exe.run(self)

class build_installer_bbfreeze(build_installer, Freezer, Command):

    user_options = [
        ('dist-dir=', 'd',
         "directory to put final built distributions in (default is dist)"),

        ("excludes=", 'e',
         "comma-separated list of modules to exclude"),
        ("includes=", 'i',
         "comma-separated list of modules to include"),
    ]

    def __init__(self, *args, **kwargs):
        Command.__init__(self, *args)
        build_installer.__init__(self, dist_dir=self.dist_dir)

    def initialize_options(self):
        self.includes = []
        self.excludes = []
        self.packages = []
        self.compressed = False
        self.dist_dir = None

    def finalize_options(self):
        self.includes = fancy_split(self.includes)
        self.excludes = fancy_split(self.excludes)
        self.compressed = False
        if self.dist_dir is None:
            self.dist_dir = 'dist'
        self.dist_dir = os.path.abspath(os.path.join(os.getcwd(), self.dist_dir))
        if not os.path.exists(self.dist_dir):
            os.makedirs(self.dist_dir)

    def do_build_exe(self):
        Freezer.__init__(self, self.dist_dir,
            includes=self.includes,
            excludes=self.excludes,
        )
        self.addScript("pyhoca-gui", gui_only=True)
        Freezer.__call__(self)
        if self.distribution.has_data_files():
            print "*** copy data files ***"
            install_data = self.reinitialize_command('install_data')
            install_data.install_dir = self.dist_dir
            install_data.ensure_finalized()
            install_data.run()

def fancy_split(str, sep=","):
    # a split which also strips whitespace from the items
    # passing a list or tuple will return it unchanged
    if str is None:
        return []
    if hasattr(str, "split"):
        return [item.strip() for item in str.split(sep)]
    return str


if platform.system() == 'Windows':

    dll_data_files = [("Microsoft.VC90.CRT", glob(r'..\\pyhoca-contrib\\mswin\\ms-vc-runtime\\*.*'))]
    nxproxy_files = [("nxproxy", glob(r'..\\pyhoca-contrib\\mswin\\nxproxy-mswin\\nxproxy-3.5.0.12\\*.*'))]
    pulseaudio_files = [("pulseaudio", glob(r'..\\pyhoca-contrib\\mswin\\pulseaudio-mswin\\pulseaudio-1.1\\*.*'))]
    xserver_files = datafilelist('vcxsrv', r'..\\pyhoca-contrib\\mswin\\vcxsrv-mswin\\vcxsrv-1.14.2.0')

    icon_files = datafilelist('icons\\PyHoca', r'icons\\PyHoca')
    img_files = [("img", glob(r'img\\*.*'))]
    i18n_files = datafilelist('mo', r'build\\mo')

    data_files.extend([ ('icons', ["pixmaps\\pyhoca-gui.ico"]), ] +
                      dll_data_files +
                      icon_files +
                      img_files +
                      nxproxy_files +
                      pulseaudio_files +
                      xserver_files +
                      i18n_files
    )

    cmd_class.update(
        {
            "build_with_py2exe": build_installer_py2exe,
            "build_with_bbfreeze": build_installer_bbfreeze,
        }
    )
    cmd_class.update({ 'build_exe': cmd_class['build_with_{freezer}'.format(freezer=default_win32exe_freezer)] })

elif platform.system() == 'Linux':
    cmd_class.update(
        {
            "build" : build_extra.build_extra,
            "build_i18n" :  build_i18n.build_i18n,
            "clean": clean_i18n.clean_i18n,
        }
    )

    icon_files = datafilelist('{prefix}/share/icons/PyHoca'.format(prefix=sys.prefix), r'icons_symlinked/PyHoca')
    img_files = [("{prefix}/share/pyhoca/img".format(prefix=sys.prefix), glob('img/*.*'))]
    desktop_files = [
        ('{prefix}/share/applications'.format(prefix=sys.prefix), glob('desktop/*')),
        ('{prefix}/share/pixmaps'.format(prefix=sys.prefix), glob('pixmaps/*.svg')),
    ]
    manpage_files = [
        ('{prefix}/share/man/man1'.format(prefix=sys.prefix), glob('man/man1/*.1')),
    ]
    data_files.extend(icon_files +
                      img_files +
                      desktop_files +
                      manpage_files
    )

if platform.system() == 'Windows':
    cmd_options={
        'py2exe': {
            'includes': ['greenlet', 'gevent.core', 'gevent.ares', 'gevent._semaphore', 'gevent._util', ],
            'compressed': 1,
            'optimize': 2,
        },
        'build_with_py2exe': {
            'includes': ['greenlet', 'gevent.core', 'gevent.ares', 'gevent._semaphore', 'gevent._util', ],
            'compressed': 1,
            'optimize': 2,
        },
        'build_with_bbfreeze': {
            'includes': ['greenlet', 'gevent.core', 'gevent.ares', 'gevent._semaphore', 'gevent._util', 'gevent.resolver_thread', 'gevent.resolver_ares', 'gevent.server', 'gevent.socket', 'gevent.threadpool', 'gevent.select', 'gevent.subprocess', 'distutils.version', 'Crypto', 'Crypto.Random', 'Crypto.Hash', 'Crypto.PublicKey', 'Crypto.PublicKey.DSA', 'Crypto.PublicKey.RSA', 'Crypto.Cipher', 'Crypto.Cipher.AES', 'Crypto.Cipher.ARC4', 'Crypto.Cipher.Blowfish', 'Crypto.Cipher.DES3', 'Crypto.Util', 'getpass', 'platform', 'uuid', 'ConfigParser', 'win32process', 'win32event', 'ctypes', 'ctypes.wintypes', ],
            'excludes': ['MSVCR90.dll', 'MSVCP90.dll', ],
        }
    }
    cmd_options.update({ 'build_exe': cmd_options['build_with_{freezer}'.format(freezer=default_win32exe_freezer)] })
else:
    cmd_options={}

setup(
    name = PROGRAM_NAME,
    version = PROGRAM_VERSION,
    description = PROGRAM_DESC,
    license = LICENSE,
    author = AUTHOR,
    url = URL,
    namespace_packages = [ 'pyhoca', ],
    packages = [ 'pyhoca.wxgui', ],
    package_dir = {'': '.'},
    install_requires = [ 'setuptools', ],
    cmdclass = cmd_class,
    windows = [
        {
            "script": "pyhoca-gui",
            "icon_resources": [(0, os.path.normpath(PROGRAM_ICON))],
            "dest_base": PROGRAM_NAME,
        },
    ],
    data_files=data_files,
    zipfile = LIBRARY_ZIP,
    executables = executables,
    options=cmd_options,
)
