import objc
from Foundation import *
from AppKit import *
from PyObjCTools import NibClassBuilder, AppHelper

from song import parse

NibClassBuilder.extractClasses("MainMenu")

def strs(p):
    return [str(i) for i in p]

numbers = (
    "zero",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten" )

# class defined in Metro.nib
class Metro(NibClassBuilder.AutoBaseClass):

    # the actual base class is NSObject

    def init(self):
        self = super(Metro, self).init()
        self.setCurrentSong_(None)
        self.setBeatsPerMinute_(90)
        self.setCurrentMeasure_("(No song loaded)")
        self.setCurrentBeats_("(No song loaded)")
        self.setCurrentChord_("")
        self.setCurrentLyrics_("(No song loaded)")
        self.speechSynthesizer = NSSpeechSynthesizer.alloc().init()
        self.speechSynthesizer.setDelegate_(self)
        self.display = []
        return self

    # Actions from nib file:
    def loadSong_(self, sender):
        panel = NSOpenPanel.openPanel()
        panel.setAllowsMultipleSelection_(False)
        panel.setCanChooseDirectories_(False)
        if panel.runModalForTypes_(None) == NSCancelButton:
            return

        # Parse the file:
        try:
            ftext = open(panel.filenames()[0]).read()
            song = parse(ftext)
        except ParseError, e:
            return
        except IOError, e:
            return

        self.setCurrentSong_(song)
        self.setCurrentMeasure_("0")
        self.setCurrentBeats_("")
        self.setCurrentChord_("")
        self.setCurrentLyrics_("")
        
    def startStopSong_(self, sender):
        if self.display:
            self.display = []
            return
        
        self.display = []
        self.song_position = 0

        # Introduce a count-in
        for i in range(1,5):
            self.display.append((0, i, 'Get Ready', ''))
        
        # Serialize out the chords we will see over the whole song:
        linecnt = 0
        for sec in self.currentSong().play_sections:
            for line in sec.lines:
                linecnt += 1
                lyric = "\n".join(line.lyrics)
                beatcnt = 0
                for chord in line.chords:
                    for i in range(chord.beats):
                        beatcnt += 1
                        self.display.append(
                            (linecnt, beatcnt, chord.name, lyric))

        # Start the first beat
        self.beat_(self)

    #
    def beat_(self, sender):
        if not self.display:
            self.setCurrentMeasure_("0")
            self.setCurrentBeats_("")
            self.setCurrentChord_("")
            self.setCurrentLyrics_("")
            return

        linecnt, beatcnt, chordname, lyric = self.display[0]
        if beatcnt < len(numbers):
            self.speechSynthesizer.startSpeakingString_(numbers[beatcnt])
        self.display = self.display[1:]
        self.setCurrentMeasure_(linecnt)
        self.setCurrentBeats_(" . ".join(strs(range(1,beatcnt+1))))
        self.setCurrentChord_(chordname)
        self.setCurrentLyrics_(lyric)

        delay = (4.0 / self.currentSong().timing_unit) * self.beat_interval
        self.performSelector_withObject_afterDelay_(
            "beat:", self, delay)

    # Key-value observing:
    @objc.accessor
    def currentSong(self):
        return self.a_current_song
    @objc.accessor
    def setCurrentSong_(self, song):
        self.a_current_song = song
    @objc.accessor
    def beatsPerMinute(self):
        return self.a_beatsPerMinute
    @objc.accessor
    def setBeatsPerMinute_(self, bpm):
        self.a_beatsPerMinute = float(bpm)
        self.beat_interval = 60.0 / self.beatsPerMinute()
    @objc.accessor
    def currentMeasure(self):
        return self.a_currentMeasure
    @objc.accessor
    def setCurrentMeasure_(self, val):
        self.a_currentMeasure = val
    @objc.accessor
    def currentBeats(self):
        return self.a_currentBeats
    @objc.accessor
    def setCurrentBeats_(self, val):
        self.a_currentBeats = val
    @objc.accessor
    def currentChord(self):
        return self.a_currentChord
    @objc.accessor
    def setCurrentChord_(self, val):
        self.a_currentChord = val
    @objc.accessor
    def currentLyrics(self):
        return self.a_currentLyrics
    @objc.accessor
    def setCurrentLyrics_(self, val):
        self.a_currentLyrics = val

if __name__ == "__main__":
    AppHelper.runEventLoop()
