#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Smewt - A smart collection manager
# Copyright (c) 2008 Nicolas Wack <wackou@gmail.com>
#
# Smewt is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Smewt 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import sys, logging, os, os.path

MAIN_LOGGING_LEVEL = logging.INFO

# when we create a py2exe, we want to redirect the output the a file ourselves,
# otherwise it gives an error when closing the app
if sys.platform == 'win32' and os.path.exists(os.path.join(os.getcwd(), 'library.zip')):
    userdir = os.path.join(os.environ['USERPROFILE'], 'Application Data', 'Smewt')
    if not os.path.exists(userdir):
        os.makedirs(userdir)
    sys.stderr = open(os.path.join(userdir, 'smewt.log'), 'w')



import logging
import sys

GREEN_FONT = "\x1B[0;32m"
YELLOW_FONT = "\x1B[0;33m"
BLUE_FONT = "\x1B[0;34m"
RED_FONT = "\x1B[0;31m"
RESET_FONT = "\x1B[0m"


def setupLogging(colored = True):
    """Sets up a nice colored logger as the main application logger (not only smewt itself)."""

    class SimpleFormatter(logging.Formatter):
        def __init__(self):
            self.fmt = '%(levelname)-8s %(module)s:%(funcName)s -- %(message)s'
            logging.Formatter.__init__(self, self.fmt)

    class ColoredFormatter(logging.Formatter):
        def __init__(self):
            self.fmt = '%(levelname)-8s ' + BLUE_FONT + '%(module)s:%(funcName)s' + RESET_FONT + ' -- %(message)s'
            logging.Formatter.__init__(self, self.fmt)

        def format(self, record):
            result = logging.Formatter.format(self, record)
            if record.levelno in (logging.DEBUG, logging.INFO):
                return GREEN_FONT + result
            elif record.levelno == logging.WARNING:
                return YELLOW_FONT + result
            else:
                return RED_FONT + result


    ch = logging.StreamHandler()
    if colored and sys.platform != 'win32':
        ch.setFormatter(ColoredFormatter())
    else:
        ch.setFormatter(SimpleFormatter())
    logging.getLogger().addHandler(ch)


setupLogging()


logging.getLogger().setLevel(MAIN_LOGGING_LEVEL)

# we most likely never want this to be on debug mode, as it spits out way too much information
if MAIN_LOGGING_LEVEL == logging.DEBUG:
    logging.getLogger('pygoo').setLevel(logging.INFO)
    logging.getLogger('imdbpy').setLevel(logging.INFO)


from PyQt4.QtGui import QApplication, QMainWindow, QWidget, QStatusBar, QProgressBar, QHBoxLayout, QStackedWidget, QIcon, QSystemTrayIcon, QAction, QMenu, QMessageBox, QToolBar
from PyQt4.QtCore import SIGNAL, QSize, Qt, QSettings, QVariant, QPoint, QSize, QObject, QTimer
from smewt.gui import MainWidget, FeedWatchWidget, AboutDialog
from smewt.base import cache, utils
from smewt.base.utils import smewtDirectory
from os.path import join

log = logging.getLogger('smewg')
DEFAULT_WIDTH = 900
DEFAULT_HEIGHT = 600


class StatusWidget(QWidget):
    def __init__(self):
        super(QWidget,  self).__init__()

        layout = QHBoxLayout()
        layout.addStretch()

        self.progressBar = QProgressBar()

        layout.addWidget(self.progressBar)

        self.setLayout(layout)
        return

class SmewtGui(QMainWindow):

    def __init__(self):
        super(SmewtGui, self).__init__()
        self.setWindowTitle('Smewg - An Ordinary Smewt Gui')

        self.readWindowSettings()

        self.icon = QIcon(smewtDirectory('smewt', 'icons', 'smewt.svg'))
        self.setWindowIcon(self.icon)

        self.createWidgets()
        self.createActions()

        # create menubar
        mainMenu = self.menuBar().addMenu('Main')
        mainMenu.addAction(self.clearCacheAction)
        mainMenu.addSeparator()
        mainMenu.addAction(self.quitAction)

        importMenu = self.menuBar().addMenu('Collection')
        importMenu.addAction(self.selectMoviesFoldersAction)
        importMenu.addAction(self.selectSeriesFoldersAction)
        importMenu.addSeparator()
        importMenu.addAction(self.updateCollectionAction)
        importMenu.addAction(self.rescanCollectionAction)

        helpMenu = self.menuBar().addMenu('Help')
        helpMenu.addAction(self.aboutAction)
        helpMenu.addAction(self.aboutQtAction)

        # create toolbar
        navigationToolBar = QToolBar('Navigation')
        navigationToolBar.addAction(self.backAction)
        navigationToolBar.addAction(self.fwdAction)
        navigationToolBar.addAction(self.refreshAction)
        navigationToolBar.addAction(self.homeAction)
        navigationToolBar.addSeparator()
        navigationToolBar.addAction(self.zoomOutAction)
        navigationToolBar.addAction(self.zoomInAction)
        navigationToolBar.addSeparator()
        navigationToolBar.addAction(self.fullScreenAction)
        navigationToolBar.setIconSize(QSize(32,32))
        navigationToolBar.setObjectName('navigationToolBar')
        self.addToolBar(navigationToolBar)
        self.createTrayIcon()

        # tmp
        self.connect(self.mainWidget, SIGNAL('feedwatcher'),
                     self.showFeedWatcher)

        # first-run wizard
        settings = QSettings()
        configured = settings.value('configured').toBool()

        if not configured:
            settings.setValue('configured', True)
        else:
            # only start the update of the collections once our GUI is fully setup
            # do not rescan as it would be too long and we might delete some files that
            # are on an unaccessible network share or an external HDD
            QTimer.singleShot(2000, self.reloadCacheAndUpdateCollections)


    def showFeedWatcher(self):
        self.tabWidget.setCurrentIndex(1)

    def showSpeedDial(self):
        self.tabWidget.setCurrentIndex(0)
        self.mainWidget.speedDial()

    def createWidgets(self):
        self.mainWidget = MainWidget()
        self.feedWatchWidget = FeedWatchWidget()

        self.tabWidget = QStackedWidget()
        self.tabWidget.addWidget(self.mainWidget)
        self.tabWidget.addWidget(self.feedWatchWidget)

        self.setCentralWidget(self.tabWidget)

        self.statusWidget = StatusWidget()
        self.statusBar().addPermanentWidget(self.statusWidget)


        self.mainWidget.smewtd.taskManager.progressChanged.connect(self.progressChanged)

    def createActions(self):
        self.clearCacheAction = QAction('Clear internet cache', self)
        self.connect(self.clearCacheAction, SIGNAL('triggered()'),
                     self.clearCache)

        self.quitAction = QAction('Quit', self)
        self.connect(self.quitAction, SIGNAL('triggered()'),
                     self.quit)

        self.minimizeAction = QAction('Minimize', self)
        self.connect(self.minimizeAction, SIGNAL('triggered()'),
                     self.hide)

        self.restoreAction = QAction('Restore', self)
        self.connect(self.restoreAction, SIGNAL('triggered()'),
                     self.showNormal)

        self.aboutAction = QAction('About', self)
        self.connect(self.aboutAction, SIGNAL('triggered()'),
                     self.about)

        self.aboutQtAction = QAction('About Qt', self)
        self.connect(self.aboutQtAction, SIGNAL('triggered()'),
                     self.aboutQt)


        # navigation bar
        self.backAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'go-previous.png')), 'Back', self)
        self.backAction.setStatusTip('Go back')
        self.connect(self.backAction, SIGNAL('triggered()'),
                     self.mainWidget.back)

        self.fwdAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'go-next.png')), 'Forward', self)
        self.fwdAction.setStatusTip('Go forward')
        self.connect(self.fwdAction, SIGNAL('triggered()'),
                     self.mainWidget.forward)

        self.refreshAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'view-refresh.png')), 'Refresh', self)
        self.refreshAction.setStatusTip('Refresh the main view')
        self.connect(self.refreshAction, SIGNAL('triggered()'),
                     self.mainWidget.refreshCollectionView)

        self.homeAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'go-home.png')), 'Home (Speed Dial)', self)
        self.homeAction.setStatusTip('Return to speed dial')
        self.connect(self.homeAction, SIGNAL('triggered()'),
                     self.showSpeedDial)


        self.zoomInAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'zoom-in.png')), 'Zoom in', self)
        self.zoomInAction.setStatusTip('Make the text larger')
        self.connect(self.zoomInAction, SIGNAL('triggered()'),
                     self.mainWidget.zoomIn)

        self.zoomOutAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'zoom-out.png')), 'Zoom out', self)
        self.zoomOutAction.setStatusTip('Make the text smaller')
        self.connect(self.zoomOutAction, SIGNAL('triggered()'),
                     self.mainWidget.zoomOut)

        self.fullScreenAction = QAction(QIcon(smewtDirectory('smewt', 'icons', 'view-fullscreen.png')), 'Full Screen', self)
        self.fullScreenAction.setStatusTip('Toggle fullscreen mode')
        self.fullScreenAction.setCheckable(True)
        self.connect(self.fullScreenAction, SIGNAL('triggered()'),
                     self.toggleFullScreen)

        # import actions

        self.selectMoviesFoldersAction = QAction('Select movies folders', self)
        self.selectMoviesFoldersAction.setStatusTip('Select the folders containing movies')
        self.connect(self.selectMoviesFoldersAction,  SIGNAL('triggered()'),
                     self.mainWidget.selectMoviesFolders)

        self.selectSeriesFoldersAction = QAction('Select series folders', self)
        self.selectSeriesFoldersAction.setStatusTip('Select the folders containing series')
        self.connect(self.selectSeriesFoldersAction,  SIGNAL('triggered()'),
                     self.mainWidget.selectSeriesFolders)

        self.updateCollectionAction = QAction('Update collection', self)
        self.updateCollectionAction.setStatusTip('Update the collection')
        self.connect(self.updateCollectionAction,  SIGNAL('triggered()'),
                     self.mainWidget.updateCollection)

        self.rescanCollectionAction = QAction('Rescan collection', self)
        self.rescanCollectionAction.setStatusTip('Rescan the collection')
        self.connect(self.rescanCollectionAction,  SIGNAL('triggered()'),
                     self.mainWidget.rescanCollection)

        # for single app to bring up the window we need a signal that can go through threads
        self.connect(self, SIGNAL('bringUp()'),
                     self.bringUpWindow)

    def bringUpWindow(self):
        self.setVisible(True)
        self.setWindowState(sgui.windowState() & ~Qt.WindowMinimized);
        self.show()
        self.raise_()
        self.activateWindow()


    def toggleFullScreen(self):
        flag = Qt.WindowFullScreen if self.fullScreenAction.isChecked() else ~Qt.WindowFullScreen
        self.setWindowState(self.windowState() ^ Qt.WindowFullScreen  )

    def reloadCacheAndUpdateCollections(self):
        # do this now instead of at the very beginning so that our GUI can be setup faster
        cache.load(utils.smewtUserPath(smewt.APP_NAME + '.cache'))
        self.mainWidget.smewtd.updateCollections()

    def clearCache(self):
        cache.clear()
        cacheFile = utils.smewtUserPath(smewt.APP_NAME + '.cache')
        log.info('Deleting cache file: %s' % cacheFile)
        os.remove(cacheFile)

    def quit(self):
        log.info('SmewtGui quitting...')
        self.writeWindowSettings()
        self.mainWidget.quit()

        # save cache
        cache.save(utils.smewtUserPath(smewt.APP_NAME + '.cache'))

        log.info('Quitting application...')
        QApplication.instance().quit()

    def readWindowSettings(self):
        settings = QSettings()
        pos = settings.value("MainWindow/pos", QVariant(QPoint((QApplication.desktop().width()-DEFAULT_WIDTH)/2, (QApplication.desktop().width()-DEFAULT_HEIGHT)/2))).toPoint()
        size = settings.value("MainWindow/size", QVariant(QSize(DEFAULT_WIDTH, DEFAULT_HEIGHT))).toSize()
        self.resize(size)
        self.move(pos)

        self.restoreState(settings.value("MainWindow/windowstate").toByteArray())

    def writeWindowSettings(self):
        settings = QSettings()
        settings.setValue("MainWindow/pos", QVariant(self.pos()))
        settings.setValue("MainWindow/size", QVariant(self.size()))

        settings.setValue("MainWindow/windowstate", QVariant(self.saveState()))


    def createTrayIcon(self):
        trayMenu = QMenu(self)
        trayMenu.addAction(self.minimizeAction)
        trayMenu.addAction(self.restoreAction)
        trayMenu.addSeparator()
        trayMenu.addAction(self.quitAction)

        self.trayIcon = QSystemTrayIcon(self.icon, self)
        self.trayIcon.setContextMenu(trayMenu)
        self.trayIcon.setVisible(True)

        self.connect(self.trayIcon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'),
                     self.iconActivated)

    def setVisible(self, visible):
        self.minimizeAction.setEnabled(visible)
        self.restoreAction.setEnabled(not visible)
        QMainWindow.setVisible(self, visible)


    def iconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger or reason == QSystemTrayIcon.DoubleClick:
            if self.isVisible():
                self.setVisible(False)
            else:
                self.setVisible(True)

    def closeEvent(self, event):
        self.writeWindowSettings()
        self.hide()
        event.ignore()

    def progressChanged(self,  tagged,  total):
        from threading import current_thread
        log.debug('Received signal in thread %d' % current_thread().ident)

        if total == 0:
            log.debug('Resetting progress bar')
            self.statusWidget.progressBar.reset()
        else:
            log.debug('Setting progress bar to %d/%d' % (tagged, total))
            self.statusWidget.progressBar.setMaximum(total)
            self.statusWidget.progressBar.setValue(tagged)


    def about(self):
        AboutDialog().exec_()

    def aboutQt(self):
        QMessageBox.aboutQt(self)


if __name__ == '__main__':
    import smewt
    app = QApplication(sys.argv)
    app.setOrganizationName(smewt.ORG_NAME)
    app.setOrganizationDomain('smewt.com')
    app.setApplicationName(smewt.APP_NAME)

    sgui = SmewtGui()

    def cb():
        sgui.emit(SIGNAL('bringUp()'))

    from smewt.base import singleapplication
    singleapplication.PORT = smewt.SINGLE_APP_PORT
    singleapplication.CALLBACK = cb
    sapp = singleapplication.SingleApplicationWatcher()


    sgui.show()
    app.exec_()

    log.info('Exiting')
    sys.exit() # why is this necessary when running from eric?
