#!/usr/bin/env python
############################################################################
# WebControl script for Amarok
# (c) 2005 Jonas Drewsen <kde@xspect.dk>
# (c) 2006 Peter C. Ndikuwera <pndiku@gmail.com>
#
# Depends on: Python 3, PyTQt
#
############################################################################
# Based on
# PyTQt template script for Amarok
# (c) 2005 Mark Kretschmann <markey@web.de>
#
############################################################################
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
############################################################################

import configparser
import os
import sys
import socket
import signal
import threading
from time import sleep

import Globals
from Playlist import Playlist
import RequestHandler
import http.server
from WebPublisher import *

import time

# necessary for <= python2.2 that cannot handle "infds" in var
import string

try:
    from PyTQt.tqt import *
except:
    os.popen( "kdialog --sorry 'PyTQt (TQt bindings for Python) is required for this script.'" )
    raise


# Replace with real name
debug_prefix = "[WebControl Script]"


class ConfigDialog( TQDialog ):
    """ Configuration widget """

    def __init__( self ):
        TQDialog.__init__( self )
        self.setWFlags( TQt.WDestructiveClose )
        self.setCaption( "WebControl - Amarok" )

        self.config = configparser.ConfigParser()

        allowControl = RequestHandler.AmarokStatus.allowControl
        publish = RequestHandler.AmarokStatus.publish
        try:
            config = configparser.ConfigParser()
            config.read( "webcontrolrc" )
            allowControl = "True" in config.get( "General", "allowcontrol" )
            publish = "True" in config.get( "General", "publish" )
        except:
            pass

        self.lay = TQHBoxLayout( self )

        self.vbox = TQVBox( self )
        self.lay.addWidget( self.vbox )

        self.hbox1 = TQHBox( self.vbox )

        self.allowControl = TQCheckBox( TQString("Allow control"), self.hbox1 )
        self.allowControl.setChecked(allowControl)

        self.hbox1 = TQHBox( self.vbox )

        self.publish = TQCheckBox( TQString("Publish"), self.hbox1 )
        self.publish.setChecked(publish)

        self.hbox = TQHBox( self.vbox )

        self.ok = TQPushButton( self.hbox )
        self.ok.setText( "Ok" )

        self.cancel = TQPushButton( self.hbox )
        self.cancel.setText( "Cancel" )
        self.cancel.setDefault( True )

        self.connect( self.ok,     SIGNAL( "clicked()" ), self.save )
        self.connect( self.cancel, SIGNAL( "clicked()" ), self, SLOT( "reject()" ) )

        self.adjustSize()

    def save( self ):
        """ Saves configuration to file """

        self.file = file( "webcontrolrc", 'w' )

        self.config = configparser.ConfigParser()
        self.config.add_section( "General" )
        self.config.set( "General", "allowcontrol", self.allowControl.isChecked() )
        self.config.set( "General", "publish", self.publish.isChecked() )        
        self.config.write( self.file )
        self.file.close()
        debug( "Saved config" )
        self.accept()


class Notification( TQCustomEvent ):
    __super_init = TQCustomEvent.__init__
    def __init__( self, str ):
        self.__super_init(TQCustomEvent.User + 1)
        self.eventStr = str

class WebControl( TQApplication ):
    """ The main application, also sets up the TQt event loop """

    def __init__( self, args ):
        TQApplication.__init__( self, args )
        debug( "Started." )

        self.readSettings()

        self.t = threading.Thread( target = self.readStdin )
        self.t.start()

        RequestHandler.PLIST = Playlist()

        p_incr = 0

        while p_incr < 10:
            try:
                p_i=p_incr+Globals.PORT
                self.srv = http.server.HTTPServer(('',p_i),RequestHandler.RequestHandler)
                publisher.port = p_i
                break
            except socket.error:
                p_incr+=1

        self.zeroconfPublishing()
        self.snsrv = TQSocketNotifier(self.srv.fileno(), TQSocketNotifier.Read)
        self.snsrv.connect( self.snsrv, SIGNAL('activated(int)'), self.readSocket )

    def readSocket( self ):
        # Got a read event on the HTTP server socket.
        self.srv.handle_request()

    def readSettings( self ):
        """ Reads settings from configuration file """
        config = configparser.ConfigParser()
        config.read( "webcontrolrc" )

        try:
            RequestHandler.AmarokStatus.allowControl = "True" in config.get( "General", "allowcontrol" )
            RequestHandler.AmarokStatus.publish = "True" in config.get( "General", "publish" )
        except:
            debug( "No config file found, using defaults." )


    def postConfigure( self ):
        self.readSettings()
        self.zeroconfPublishing()

    def zeroconfPublishing( self ):
        if RequestHandler.AmarokStatus.publish:
            if not publisher.active:
                threading.Thread(target = publisher.run).start()
        else:
            publisher.shutdown()

############################################################################
# Stdin-Reader Thread
############################################################################

    def readStdin( self ):
        while True:
            line = sys.stdin.readline()
            if line:
                tqApp.postEvent( self, Notification(line) )
            else:
                break

############################################################################
# Notification Handling
############################################################################

    def customEvent( self, notification ):
        """ Handles the notifications """

        eventStr = TQString(notification.eventStr)
        debug( "Received notification: " + str( eventStr ) )

        if eventStr.contains( "configure" ):
            self.configure()

        elif eventStr.contains( "exit" ):
            cleanup(None,None)

        elif eventStr.contains( "engineStateChange: play" ):
            self.engineStatePlay()

        elif eventStr.contains( "engineStateChange: idle" ):
            self.engineStateIdle()

        elif eventStr.contains( "engineStateChange: pause" ):
            self.engineStatePause()

        elif eventStr.contains( "engineStateChange: empty" ):
            self.engineStatePause()

        elif eventStr.contains( "trackChange" ):
            self.trackChange()

        else:
            debug( "Unknown notification: " + str(eventStr) + " -> ignoring")

# Notification callbacks. Implement these functions to react to specific notification
# events from Amarok:

    def configure( self ):
        debug( "configuration" )

        self.dia = ConfigDialog()
        self.dia.show()
        self.connect( self.dia, SIGNAL( "destroyed()" ), self.postConfigure )

    def engineStatePlay( self ):
        """ Called when Engine state changes to Play """
        RequestHandler.AmarokStatus.dcop_trackcurrenttime = Globals.PlayerDcop("trackCurrentTime")
        RequestHandler.AmarokStatus.dcop_trackcurrenttime.result()
        RequestHandler.AmarokStatus.dcop_tracktotaltime = Globals.PlayerDcop("trackTotalTime")
        RequestHandler.AmarokStatus.dcop_tracktotaltime.result()
        RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EnginePlay

    def engineStateIdle( self ):
        """ Called when Engine state changes to Idle """
        RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EngineIdle

    def engineStatePause( self ):
        """ Called when Engine state changes to Pause """
        RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EnginePause

    def engineStateEmpty( self ):
        """ Called when Engine state changes to Empty """
        RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EngineEmpty

    def trackChange( self ):
        """ Called when a new track starts """
        RequestHandler.AmarokStatus.dcop_trackcurrentindex = Globals.PlaylistDcop("getActiveIndex")
        RequestHandler.AmarokStatus.dcop_trackcurrentindex.result()
        RequestHandler.AmarokStatus.dcop_trackcurrenttime = Globals.PlayerDcop("trackCurrentTime")
        RequestHandler.AmarokStatus.dcop_trackcurrenttime.result()
        RequestHandler.AmarokStatus.dcop_tracktotaltime = Globals.PlayerDcop("trackTotalTime")
        RequestHandler.AmarokStatus.dcop_tracktotaltime.result()



############################################################################

def debug( message ):
    """ Prints debug message to stdout """

    print(debug_prefix + " " + message)

def cleanup(sig,frame):
        publisher.shutdown()
        os._exit(0)


def guithread():
        app = WebControl( sys.argv )
        app.exec_loop()

if __name__ == "__main__":
        Globals.EXEC_PATH = os.path.abspath(sys.path[0])
        gui = threading.Thread(target=guithread)
        gui.start()
        signal.signal(signal.SIGTERM,cleanup)
# just wait quietly for the end
        while 1: sleep(120)
