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

import json
import os
import shutil
import sys
from glob import glob
from optparse import OptionParser


def convert_ini_files():
    from puddlestuff.constants import CONFIGDIR, SAVEDIR

    config_files = [
        'puddletag.conf', 'combos',
        'gensettings', 'menus', 'shortcuts',
        'tagpanel', 'tagsources.conf',
        'function_settings', 'user_shortcuts', 'view_all_fields',
    ]

    data_files = glob(os.path.join(SAVEDIR, 'actions/*')) + \
                 glob(os.path.join(SAVEDIR, 'masstagging/*'))

    files = [os.path.join(CONFIGDIR, fn) for fn in config_files] + data_files

    for fn in files:
        if os.path.exists(fn):
            settings_to_json(fn)


def settings_to_json(filename):
    data = open(filename, 'r').read()

    try:
        json.loads(data)
        return  # Valid json so already converted.
    except:
        pass

    try:
        config_data = json.dumps(dict(ConfigObj(filename)), indent=2)
        fo = open(filename, 'w')
        fo.write(config_data)
        fo.close()
    except:
        pass


def _migrate_action_shortcut_filenames():
    from puddlestuff.constants import ACTIONDIR
    filename = os.path.join(ACTIONDIR, 'action_shortcuts')
    if not os.path.exists(filename):
        return
    with open(filename, 'r') as fo:
        data = json.loads(fo.read())

    old_dir = os.path.join(os.getenv('HOME'), '.puddletag', 'actions')
    for key, shortcut in data.items():
        shortcut['filenames'] = [z.replace(old_dir, ACTIONDIR) for z in shortcut['filenames']]

    with open(filename, 'w') as fo:
        fo.write(json.dumps(data, indent=2))


def migrate_settings():
    from puddlestuff.constants import CONFIGDIR, SAVEDIR
    for dirpath in [CONFIGDIR, SAVEDIR]:
        if not os.path.exists(dirpath):
            os.makedirs(dirpath)

    old_dir = os.path.join(os.getenv('HOME'), '.puddletag')
    if (os.path.exists(old_dir)):
        dirnames = [
            'plugins', 'actions', 'masstagging', 'mp3tag_sources', 'translations']

        for dirname in dirnames:
            src = os.path.join(old_dir, dirname)
            dest = os.path.join(SAVEDIR, dirname)
            if os.path.exists(src) and not os.path.exists(dest):
                os.rename(src, os.path.join(SAVEDIR, dirname))

        for filename in os.listdir(old_dir):
            dest = os.path.join(CONFIGDIR, filename)
            if (not os.path.exists(dest)):
                src = os.path.join(old_dir, filename)
                shutil.move(src, dest)

        shutil.rmtree(old_dir)

    _migrate_action_shortcuts()
    convert_ini_files()
    _migrate_action_shortcut_filenames()


def _migrate_action_shortcuts():
    from puddlestuff.constants import SAVEDIR, ACTIONDIR
    from puddlestuff.puddleobjects import PuddleConfig
    filename = os.path.join(SAVEDIR, 'actions', 'action_shortcuts')

    if not os.path.exists(filename):
        return

    try:
        cparser = PuddleConfig(filename)
    except:
        # Already converted to json. Nothing to do.
        return None

    for section in sorted(cparser.sections()):
        if section.startswith('Shortcut'):
            filenames = []
            for filename in cparser.get(section, 'filenames', []):
                filenames.append(os.path.join(ACTIONDIR, os.path.basename(filename)))
            cparser.set(section, 'filenames', filenames)


def check_libs():
    """Check for required libs.

    If some not found, show/print a message.
    Exit if requirements aren't met."""
    _libs = [('mutagen', '(usually python3-mutagen or just mutagen)',
              'http://code.google.com/p/mutagen/'),
             ('configobj', '(usually python3-configobj)',
              'http://code.google.com/p/configobj/'),
             ('pyparsing', '(python3-pyparsing or python3-parsing in most distros)',
              'https://github.com/pyparsing/pyparsing/'),
             ('PyQt5', '(python3-pyqt5 usually)',
              'http://www.riverbankcomputing.co.uk/software/pyqt/intro')]

    found = True
    errors = []
    msg = "Error: The %s module wasn't found. Please check that it's installed " \
          "properly. Download it from your distro's repository" \
          " %s or directly from %s \n"
    for lib in _libs:
        try:
            __import__(lib[0])
        except ImportError:
            print((msg % lib))
            errors.append(msg % lib)
            found = False

    msg = "Error: %s module wasn't found. %s. Please check that it's " \
          "installed properly. You can download it from your distro's " \
          "repository (%s), or download directly from %s.\n"

    try:
        if not found:
            from PyQt5.QtWidgets import QApplication, QMessageBox
            app = QApplication([])
            QMessageBox.critical(None, 'puddletag', '\n'.join(errors))
    except:
        pass

    if not found:
        sys.exit(1)


def init(options, qapp):
    """Initializes things that need to be initialized.

    Parses command line options. Loads Translations. Sets fontsize."""
    from puddlestuff.logger import init_logger

    if options.version:
        # It's already printed.
        exit()

    if options.debug:
        init_logger(logging.DEBUG)
    else:
        init_logger(logging.WARN)

    load_language(qapp, options.langfile)

    if options.fontsize:
        try:
            size = int(options.fontsize)
            font = qapp.font()
            font.setPointSize(size)
            app.setFont(font)
        except IndexError:
            logging.error('No fontsize specified.')
        except ValueError:
            logging.error('Invalid fontsize specified.')


def load_language(qapp, langfile=None):
    """Loads the language file to be used by puddletag.

    app => QApplication object.
    langfile => If None, then the last option the user chose will be used.
                Should be a path to a Qt translation file (.qm)."""
    TRANSDIR = puddlestuff.constants.TRANSDIR

    global translators  # Needs to live throughout app.
    translators = []

    if langfile:
        if not langfile.endswith('.qm'):
            print(translate('Defaults', 'Invalid translation file.'))
            langargs = None
        else:
            langargs = os.path.basename(langfile), os.path.dirname(langfile)
    else:
        langargs = None

    if not langargs:
        cparser = PuddleConfig()
        lang = cparser.get('main', 'lang', 'auto')
        langs = get_languages([TRANSDIR])

        if lang != 'auto':
            if lang in langs:
                f = langs[lang]
                langargs = os.path.basename(f), os.path.dirname(f)

        if not langargs and lang != 'default':
            locale = str(QLocale.system().name())
            if locale in langs:
                f = langs[locale]
                langargs = os.path.basename(f), os.path.dirname(f)

    if langargs and langargs != 'default':
        translator = QTranslator()
        translator.load("qt_" + QLocale.system().name(),
                        QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath))
        translators.append(translator)

        if 'puddletag_' in langargs[0]:
            translator = QTranslator()
            locale = langargs[0][len('puddletag_'):-len('.qm')]
            translator.load("qt_" + locale,
                            QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath))
            print("Locale: " + locale)
            translators.append(translator)

        translator = QTranslator()
        if translator.load(*langargs):
            translators.append(translator)

    elif langargs != 'default':
        translator = QTranslator()
        translator.load("qt_" + QLocale.system().name(),
                        QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath))
        print("Locale: " + str(QLocale.system().name()))
        translators.append(translator)

    else:
        print("Loading default (ie. no) translation.")

    for t in reversed(translators):
        qapp.installTranslator(t)
    puddlestuff.constants.trans_strings()
    puddlestuff.puddleobjects.trans_imagetypes()


def parse_cmd_options():
    usage = "Usage: %prog [options] [directory path]"
    parser = OptionParser(usage=usage)

    parser.add_option("--langfile", dest="langfile",
                      default='',
                      help="Path to a translation (.qm) file.", metavar="LANGFILE")
    parser.add_option("--fontsize", type='float',
                      dest="fontsize", help="Default fontsize to use (in points).")
    parser.add_option("-d", "--debug", action="store_true",
                      dest="debug", default=False, help="Show (useless) debug messages.")
    parser.add_option("-v", "--version", action="store_true",
                      dest="version", default=False, help="Show version info and exit.")

    return parser.parse_args()


def print_info():
    """Print program info."""
    from puddlestuff import version_string, changeset
    if changeset:
        print(translate('Defaults', "puddletag Version: {}, Changeset: {}")
              .format(version_string, changeset))
    else:
        print(translate('Defaults', 'puddletag Version: {}'
              .format(version_string)))


def splashscreen():
    from PyQt5.QtGui import QFont, QPainter, QPixmap
    from PyQt5.QtWidgets import QSplashScreen
    from puddlestuff import version_string

    pixmap = QPixmap('icons:puddlelogo.png')

    # Add version
    painter = QPainter(pixmap)
    font = QFont()
    font.setPointSize(14)
    font.setBold(True)
    painter.setFont(font)
    painter.drawText(330, 115, 'v' + version_string)
    painter.end()

    return QSplashScreen(pixmap)


class StdOut(object):
    """Class to redirect stdout/in/err."""

    def __init__(self, old_write, new_write):
        """old_write should be the original sys.stdout.out
        new_write is a function is what sys.stdout.out will be replaced with.

        Text will be passed to both functions."""
        self._old_write = old_write
        self._new_write = new_write

    def write(self, text):

        self._old_write(text)
        try:
            self._new_write(text)
        except:
            pass


if __name__ == '__main__':
    check_libs()
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtCore import (pyqtRemoveInputHook, QTranslator,
                              QLibraryInfo, QLocale)
    import logging
    from configobj import ConfigObj

    pyqtRemoveInputHook()

    # Load puddletag modules.
    import puddlestuff.resource  # Needs to be first as other modules use it.
    import puddlestuff.constants

    migrate_settings()
    from puddlestuff.puddleobjects import get_icon, get_languages, PuddleConfig
    from puddlestuff.translations import translate

    # Init.
    print_info()
    app = QApplication(sys.argv)
    options, filenames = parse_cmd_options()
    init(options, app)

    # Depends on init being called first.
    from puddlestuff.puddletag import MainWin
    from puddlestuff.puddlesettings import load_gen_settings

    app.setWindowIcon(get_icon(None, "appicon.svg"))
    app.setDesktopFileName("puddletag.desktop")
    app.setOrganizationName("Puddle Inc.")
    app.setApplicationName("puddletag")

    splash = splashscreen()
    splash.show()
    app.processEvents()
    win = MainWin()
    splash.close()
    win.setVisible(True)
    app.processEvents()

    # Check if dirnames passed on command line.
    if filenames:
        for filename in filenames:
            if not os.path.exists(filename):
                print('Directory or file %s does not exist.' % filename)
                sys.exit(1)
        win.openFiles(filenames, False)
    elif load_gen_settings([('&Load last folder at startup', False)])[0][1]:
        if win._lastdir and os.path.exists(win._lastdir[0]):
            win.openDir(win._lastdir[0], False)
    app.exec_()
