# -*- coding: utf-8 -*-

#   This file is part of emesene.
#
#    Emesene 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.
#
#    emesene 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 emesene; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

VERSION = '0.1'

import CurrentSong
import sys
import gettext
import os
import socket
import urllib, urllib2


def _extract_fields(reply, fields):
    """Return a dict associating a value to each requested field from a MPD
    reply.

    Parameters:
        reply - MPD reply (string)
        fields - sequence of fields (lowercase) we'll associate a value to.
    
    Here's an example of an MPD reply:
    
        Artist: foo
        Title: bar
        Album: other
        OK
    """
    # Initialize dict values to empty strings in case they are not in
    # the MPD reply.
    ret = {}
    for field in fields:
        ret[field] = ""

    for line in reply.splitlines():
        if ":" in line:
            field, value = line.split(":", 1)
            field = field.strip().lower()
            if field in fields:
                ret[field] = value.strip()
    return ret

RETRYNUM = 1000

class Mpd( CurrentSong.CurrentSong ):
    
    customConfig = {
        'host': '127.0.0.1',
        'port': '6600',
        'password': '',
    }
    
    def __init__(self):
        CurrentSong.CurrentSong.__init__(self)
        self._socket = None
        self._retNum = 0
        
        self.song_info = {
            'artist': '',
            'title': '',
            'album': '',
        }

        dictCommandMPD = {
            'play': ( self.cmd_Play, 'Start playing',False ),
            'stop': ( self.cmd_Stop, 'Stop playing',False ),
            'pause': (self.cmd_Pause, 'Pause player',False ),
            'next': (self.cmd_Next, 'Jump to next song',False),
            'prev': (self.cmd_Prev, 'Jump to previous song',False),
            'getvol': (self.cmd_GetVolume, 'get volume',False),
            'setvol': (self.cmd_SetVolume, 'set volume <int vol>. The range of volume is 0-100',False)
        }

        self.dictCommand.update(dictCommandMPD)

    def updateConfig(self):
        if self.connected():
            self._socket.close()
            self._socket = None
        self._connect()
        for item in self.song_info.keys():
            self.song_info[item] = ""

    def tryReconnect():
        if self._retNum > RETRYNUM:
            self._retNum = 0
            self._connect()
        else:
            self._retNum += 1

    def _getSocket(self):
        if self._socket == None:
            self.tryReconnect()
        return self._socket
    
    def getStatus( self ):
        '''check if everything is OK to start the plugin
        return a tuple whith a boolean and a message
        if OK -> ( True , 'some message' )
        else -> ( False , 'error message' )'''
        
        return ( True, _('OK') )
    
    def _connect(self):
        if self.connected():
            return
        self.log('info', _('trying to connect'))
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self._socket.connect((self.customConfig.get('host', 
                '127.0.0.1'), int(self.customConfig.get('port', 6600))))
            if not self._socket.recv(128).startswith("OK"):
                raise
            if self.customConfig.get('password', ''):
                self.log('info', _('sending password'))
                self._socket.send('password ' +  self.customConfig['password'] +'\n')
                if not self._socket.recv(128).startswith("OK"):
                    self.log('error', _('wrong password'))
                    raise socket.error
        except socket.error, msg:
            self.log('error', 'can\'t connect to %s:%s' % \
                (self.customConfig.get('host', '127.0.0.1'), 
                    self.customConfig.get('port', 6600)))
            self.status = _('not running')
            self._socket.close()
            self._socket = None
        else:
            self.log('info', _('connected sucessfully'))
            self.status = 'connected'
        return 
    
    def connected(self):
        if self._socket is None:
            return False

        return True
    
    def start(self):
        self._connect()
        return True

    def check(self):
        if self.checkSongChanged():
            self.artist = self.getArtist()
            self.title = self.getTitle()
            self.album = self.getAlbum()
            return True
        return False
        
    def stop(self):
        '''Close connection'''
        if self.connected():
            self._socket.close()
        self._socket = None

    def setHost(self, host):
        self.host = host

    def setPort(self, port):
        self.port = port

    def setPassword(self, password):
        self.password = password

    def getArtist(self):
        return self.song_info["artist"]
    
    def getAlbum(self):
        return self.song_info["album"]
    
    def getTitle(self):
        return self.song_info["title"]
    
    def sendCmd(self, cmd):
        try:
            sock = self._getSocket()
            sock.send("%s\n" % cmd)
            ret = sock.recv(1024)
            # Command failed
            if ret.startswith("ACK"):
                return None
            return ret
        except:
            return None
        
    def isPlaying(self):
        status = self.sendCmd("status")
        if status is not None:
            if _extract_fields(status, ["state"])["state"] == "play":
                return True

        return False
    
    def isRunning(self):
        self._connect()
        if not self.connected():
            return False
        return True
        
    def checkSongChanged(self):
        if not self.isPlaying():
            if "".join(self.song_info.values()) != "":
                # MPD stopped playing, so empty all fields
                for item in self.song_info.keys():
                    self.song_info[item] = ""      
                return True
        else: 
            song_rpl = self.sendCmd("currentsong")
            if song_rpl is not None:
                song_info = _extract_fields(song_rpl, self.song_info.keys())
                if self.song_info != song_info:
                    self.song_info = song_info
                    return True
            
        return False

    def cmd_Pause(self,args):
        ret = self.sendCmd('pause')
        if ret != None and ret.startswith('OK'):
            return ( True, 'Player Paused' )
        return ( False, 'Error Pausing Player' )

    def cmd_Play(self,args):
        ret = self.sendCmd('play')
        if ret != None and ret.startswith('OK'):
            return ( True, 'Player start playing' )
        return ( False, 'Error on playing' )

    def cmd_Stop(self,args):
        ret = self.sendCmd('stop')
        if ret != None and ret.startswith('OK'):
            return ( True, 'Player Stopped' )
        return ( False, 'Error on Stopping Player' )
    
    def cmd_Next(self,args):
        ret = self.sendCmd('next')
        if ret != None and ret.startswith('OK'):
            return ( True, 'Next Track' )
        return ( False, 'Error jumping to next track' )

    def cmd_Prev(self,args):
        ret = self.sendCmd('prev')
        if ret != None and ret.startswith('OK'):
            return ( True, 'Previous Track' )
        return ( False, 'Error jumping to previos track' )

    def cmd_GetVolume(self,args):
        ret = self.sendCmd('status')
        if ret != None:
            try:
                volume = _extract_fields(ret,['volume'])['volume']
                return ( True, 'Volume: ' + str(volume))
            except:
                pass
        return ( False, 'Error Getting Volume' )

    def cmd_SetVolume(self,args):
        try:
            vol = int(args)
            if vol < 0 or vol > 100:
                raise
        except:
            return ( False, 'setvol needs an integer value,range 0-100' )
        
        ret = self.sendCmd('setvol ' + str(vol))
        if ret != None and ret.startswith('OK'):
            return ( True, 'Volume setted to ' + str(vol) )
        return ( False, 'Error Setting Volume' )

        
