#!/usr/bin/env python
import sys
import os
import thread
#we will need to parse xml
from xml.dom import minidom
#we need to get files from the interpipes
import urllib
#import wx
try:
    import wx
    import wx.media #we need this one for the media control
except:
    #we failed to import wx
    print "This application requires the wxPython library version > 2.8"
    sys.exit()


#the GUI is unresponsive when downloading, download using a thread
"""actually this doesn't fix the problem. TODO: learn about threading"""
class downloadThread():
    def __init__(self,window,url,file):
        #file is the file to download
        #callback is the function we are going to send info to
        self.file = file
        self.url = url
        self.window = window
        self.thread = thread
    
    def Run(self):
        self.thread.start_new_thread(self.start(),())
    
    def stop(self):
        print "kill the thread"
        self.thread.exit()
    
    def start(self):
        urllib.urlretrieve(self.url,self.file, self.dl_status )
        #if we get here, we are finished
        self.window.dl_finished()
        return 1
    
    def dl_status(self,block_count,block_size,total_size):
        #create an event with the data we've gotten and pass it on
        p = int(block_count*block_size*100/total_size)
        self.window.dl_status(p)
    
class settings():
    def __init__(self):
        #create a dict to hold our settings
        self.variables={}
        #where is the default feed?
        rss_url = "http://www.lugradio.org/episodes.ogg.rss"
        """the settings file is ~/.ltlr/settings
        if the file doesn't exist, we need to create it now
        """        
        settingsFile = "settings"
        assetDir = os.path.expanduser("~/.ltlr")
        self.settings = assetDir+"/"+settingsFile
        if(os.path.isfile(self.settings) ):
            #read the settings
            try:
                file = open(self.settings)
                file_content = file.read()
                lines = file_content.splitlines()
                for line in lines:
                    try:
                        assets = line.split("=")
                        key = assets[0].strip()
                        val = assets[1].strip()
                        print key+"="+val
                        self.variables[key] = val
                    except:
                        pass
            except:
                print "no config file to read"

        else:
            #create the folder if it doesn't exist
            if(os.path.isdir(assetDir)==False):
                print "creating "+assetDir
                os.mkdir(assetDir)
            #create the file
            print "creating "+settingsFile
            writableFile = open(self.settings,"w+")
            writableFile.close()
            #set the rss_url
            self.set_setting("rss_url",rss_url)
            self.set_setting("asset_dir",assetDir)
    #eventually, we'll need to get a setting
    def get_setting(self,key):
        if(key in self.variables):
            return self.variables[key]
        else:
            #the default return value is a string 0
            return "0"
        
    #we will need to set a setting
    def set_setting(self,key,value):
        self.variables[key]=value
        #write the settings to file
        writableFile = open(self.settings,"w+")
        for key in self.variables:
            string =key+"="+self.variables[key]+"\n"
            writableFile.write(string)
        writableFile.close()
    
#define the class of our only window
class theFrame(wx.Frame):
    def __init__(self, parent, ID, title):
        #I would like some variable that will help me pay attention to my surroundings
        self.state = ""
        self.loaded_file=""
        theStyle=(wx.CAPTION|wx.MINIMIZE_BOX|wx.CLOSE_BOX)
        wx.Frame.__init__(self, parent, ID, title, style=theStyle)
        #we need a button to check for a new show
        self.theCheckButton = wx.Button(self,-1,"Update")
        #set a tooltip
        self.theCheckButton.SetToolTipString("Check for a new LUGRadio")
        # Bind method to button click
        self.Bind(wx.EVT_BUTTON,self.checkButtonClicked,self.theCheckButton)
        #we need a button to start playing the new show
        self.thePlayPauseButton = wx.Button(self,-1,"Play")
        # Bind method to button click
        self.Bind(wx.EVT_BUTTON,self.playPauseButtonClicked,self.thePlayPauseButton)
        #I want a Gauge to show me how much has been played
        self.playedGauge = wx.Gauge(self,-1,100,style=wx.GA_SMOOTH)
        #we need a horizontal sizer to hold the buttons
        hBox = wx.BoxSizer(wx.HORIZONTAL)
        #add the check button to the horizontal sizer
        hBox.Add(self.theCheckButton,0,0,0)
        #add the play button to the sizer
        hBox.Add(self.thePlayPauseButton,0,wx.LEFT, 5)
        #disable the play button by default
        self.thePlayPauseButton.Disable()
        #add the Gauge
        hBox.Add(self.playedGauge,1,wx.EXPAND | wx.LEFT,5)
        # we need a media player to handle the podcast
        self.theMediaController = wx.media.MediaCtrl(self,-1)
        #hide the media controller
        self.theMediaController.Hide()
        #we need a status bar to show info to the user
        self.theStatus = wx.StatusBar(self,-1)
        #we need a vertical sizer to hold the hbox, media player and statusbar
        vBox = wx.BoxSizer(wx.VERTICAL)
        #add the hbox0
        vBox.Add(hBox,1,wx.EXPAND|wx.ALL,5)
        #add the media controller
        vBox.Add(self.theMediaController,0,0,0)   
        #add the status bar
        vBox.Add(self.theStatus,0,0,0)
        #set the sizer for this frame to be the vBox
        self.SetSizer(vBox)
        vBox.Fit(self)
        self.Layout()
        #initialize the settings
        self.settings = settings()
        #bind the close button
        self.Bind(wx.EVT_CLOSE, self.onCloseClicked)
        #we need a timer
        self.playTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnPlayTimer,self.playTimer)
        #if the lugradio file exits, enable the play button
        dlfile =self.settings.get_setting("asset_dir")+"/"+self.settings.get_setting("audio_file")
        if os.path.exists(dlfile):
            self.thePlayPauseButton.Enable()
        
    def checkButtonClicked(self,event):
        rss_url = self.settings.get_setting("rss_url")
        self.print_to_status( "checking "+rss_url+"...")
        #read the LUGradio RSS
        result = urllib.urlopen(rss_url)
        self.print_to_status( "parsing...")
        xmlDocElement = minidom.parse(result).documentElement
        #make a list of the items
        itemlist = xmlDocElement.getElementsByTagName("item")
        #the first item is the latest show
        firstitem = itemlist[0]
        pubDateNodes = firstitem.getElementsByTagName("pubDate")
        pubDateNode = pubDateNodes[0]
        print self.getXMLNodeText(pubDateNode)
        #get the url
        enclosures = firstitem.getElementsByTagName("enclosure")
        enclosure = enclosures[0]
        audio_url = enclosure.attributes['url'].value
        audio_length = enclosure.attributes['length'].value
        self.current_release_date = self.convertDateString( self.getXMLNodeText(pubDateNode) )
        #get the file name from the audio_url
        path_bits = audio_url.split("/")
        self.audio_file_name = path_bits[-1]
        #there for the latest_file is
        self.latest_file = self.settings.get_setting("asset_dir")+"/"+self.audio_file_name
        self.dlfile = self.latest_file
        #is the current release date greater than the date recorded in the settings?
        if(str(self.current_release_date) > str( self.settings.get_setting("current_release_date") ) or os.path.exists(self.latest_file)==False  ):
            self.theCheckButton.Disable()            
            #download the new LUGRadio           
            self.print_to_status("Downloading...")
            #download asyncronously
            self.dlthread = downloadThread(self,audio_url,self.dlfile)
            self.dlthread.Run()

        else:
            self.print_to_status("You already have the latest LUGRadio")

         
    def dl_finished(self):    
        #delete the previous file
        old_audio_file = self.settings.get_setting("asset_dir")+"/"+self.settings.get_setting("audio_file")
        if os.path.exists(old_audio_file):
            os.remove(old_audio_file)
            
        #remove the .temp from the finished download
        os.rename(self.dlfile,self.latest_file)
        #update the settings to reflect the new download
        self.settings.set_setting("audio_file",self.audio_file_name)
        
        #activate the check and play buttons
        self.theCheckButton.Enable()
        
        self.thePlayPauseButton.Enable()
        self.settings.set_setting("current_release_date",self.current_release_date)
        self.print_to_status("")
        
    def playPauseButtonClicked(self,event):
        if self.state!="playing":
            self.state = "playing"
            #load the dlfile
            file =self.settings.get_setting("asset_dir")+"/"+self.settings.get_setting("audio_file")
            #if there is no file loaded, or an old file is loaded, load the latest file
            if self.theMediaController.Length()<5 : 
                if not self.theMediaController.Load(file):
                    # I copied this error message from the demo code. #TODO: read up on that shit
                    wx.MessageBox("Unable to load %s: Unsupported format?" % file,
                              "ERROR",
                              wx.ICON_ERROR | wx.OK)
                
            self.theMediaController.Play()
            range = self.theMediaController.Length() 
            print range
            self.playedGauge.SetRange(range )
            self.playTimer.Start(100)
            #change the text on the button
            self.thePlayPauseButton.SetLabel("Pause")
        else:
            self.state="pause"
            self.theMediaController.Pause()
            #stop the timer
            self.playTimer.Stop()
            #change the text on the button
            self.thePlayPauseButton.SetLabel("Play")
            
    def OnPlayTimer(self, evt):
        if self.state=="playing":
            offset = self.theMediaController.Tell()
            self.playedGauge.SetValue(offset)
            if self.playedGauge.GetRange()<5:
                range = self.theMediaController.Length() 
                print range
                self.playedGauge.SetRange(range )


        
    def print_to_status(self,string):
        #write the string to the status bar
        self.theStatus.SetStatusText(string)
    
    #get all of the text out of an minidom parsed XML node 
    def getXMLNodeText(self,startNode):
        rstring = ""
        nodelist = startNode.childNodes
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                rstring = rstring + node.data
        return rstring 
    
    # the date format is unwieldy when one needs to make comparisons, do something about it
    def convertDateString(self,string):
        #string looks like "Mon, 31 Dec 2007 00:00:00 GMT"
        items = string.split()
        day = items[1]
        month = items[2]
        year = items[3]
        months =["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
        for i in range( len(months) ):
            if month == months[i]:
                monthnum = i+1
                if monthnum<10:
                    monthnum = "0"+str(i)
                else:
                    monthnum = str(monthnum)
        if len(day)<2:
            day = "0"+day
                                
        new_string = year+monthnum+day
        return new_string
    
    #what do we do when we get a call back from urllib downloading the latest episode?
    def dl_status(self,percent):
        self.print_to_status("Downloading: "+str(percent)+"%")
      
    def onCloseClicked(self,event):
        try:
            self.dlthread.stop()
        except:
            pass
        sys.exit()
    
    
app = wx.PySimpleApp()
frame = theFrame(None, -1, "Listen To LUGRadio")
frame.Show()
app.MainLoop()
