def getSoundStatus(statusName):
    if statusName == "Playing":
        return SoundStatus.Playing
    elif statusName == "Paused":
        return SoundStatus.Paused
    elif statusName == "Stopped":
        return SoundStatus.Stopped

class DynamuseUi(DialogUi):
    def __init__(self):
        width = 600
        height = 400
        DialogUi.__init__(self, 'dynamuse', PixelRect(0, 0, width, height))
        #Register UI callbacks
        self.view.register('populate', self.onPopulate)
        self.view.register('new', self.onNew)
        self.view.register('save', self.onSave)
        self.view.register('load', self.onLoad)
        self.view.register('play', self.onPlay)
        self.view.register('stop', self.onStop)
        self.view.register('selectSample', self.onSelectSample)
        self.view.register('preview', self.onPreviewSample)
        self.view.register('solo', self.onSoloSample)
        self.view.register('mute', self.onMuteSample)

        #
        self.view.register('barChanged', self.onBarChanged)
        self.view.register('addTrigger', self.onAddTrigger)
        self.view.register('addCondition', self.onAddCondition)
        self.view.register('removeSample', self.onRemoveSample)
        self.view.register('removeTrigger', self.onRemoveTrigger)
        self.view.register('removeCondition', self.onRemoveCondition)
        self.view.register('sampleNameChanged', self.onSampleNameChanged)
        self.view.register('playsChanged', self.onTriggerPlaysChanged)
        self.view.register('restartChanged', self.onTriggerRestartChanged)
        self.view.register('fadeInChanged', self.onTriggerFadeInChanged)
        self.view.register('typeChanged', self.onConditionTypeChanged)
        self.view.register('compareChanged', self.onConditionCompareChanged)
        self.view.register('statusChanged', self.onConditionStatusChanged)
        self.view.register('sampleChanged', self.onConditionSampleChanged)
        self.view.register('lowerChanged', self.onConditionLowerChanged)
        self.view.register('upperChanged', self.onConditionUpperChanged)
        self.view.register('setIntensity', self.onSetIntensity)
        self.view.register('setDaytime', self.onSetDaytime)

        self.load('html/dynamuse.html')
        self.view.show()
        game.gui.focusView(self.view)

        self.track = None
        self.chooser = None

    def update(self, frameTime):
        if self.track:
            self.track.update(frameTime)

    def onPopulate(self, view, args):
        commands = []
        for status in ['Playing', 'Paused', 'Stopped']:
            commands.append("App.statuses.pushObject(App.Comparison.create({text: '%s'}));" % (status,))

        for compare in ['<', '>', '<=', '>=', '==', '!=']:
            commands.append("App.comparisons.pushObject(App.Comparison.create({text: '%s'}));" % (compare,))

        for name in sorted([condition.name for condition in AudioCondition.conditions.values()]):
            commands.append("App.conditions.pushObject(App.ConditionType.create({name:'%s'}));" % (name,))

        view.execute(commands)

    def onNew(self, view, args):
        self.selectFile(['.cdf'], shouldCreate=True)

    def onLoad(self, view, args):
        self.selectFile(['.cdf'])

    def onSave(self, view, args):
        self.track.write()

    def onPlay(self, view, args):
        #Stop any tracks that are being previewed
        for sample in self.track.samples:
            if sample.music.getStatus() is SoundStatus.Playing:
                sample.music.stop()
                sample.music.setLoop(False)
        self.track.play()

    def onStop(self, view, args):
        self.track.stop()

    def onPreviewSample(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        if sample.music.getStatus() is SoundStatus.Stopped:
            sample.music.setLoop(True)
            sample.music.setVolume(100)
            sample.music.play()
        else:
            sample.music.stop()
            sample.music.setLoop(False)

    def onSoloSample(self, view, args):
        self.track.setSampleSolo(args[1].toString(), args[2].toBoolean())

    def onMuteSample(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.setMute(args[2].toBoolean(), self.track.hasSolo)

    def onBarChanged(self, view, args):
        self.track.setBar(args[1].toInteger())

    def onAddTrigger(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers.append(AudioTrigger())

    def onAddCondition(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions.append(AudioCondition.create(args[3].toString()))

    def onRemoveSample(self, view, args):
        sampleName = args[1].toString()
        del self.track.state.samples[sampleName]
        for index, sample in enumerate(self.track.samples):
            if sampleName == sample.name:
                del self.track.samples[index]
                break

    def onRemoveTrigger(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        triggerId = args[2].toInteger()
        if sample.trigger == sample.triggers[triggerId]:
            sample.stop()
        del sample.triggers[triggerId]

    def onRemoveCondition(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        trigger = sample.triggers[args[2].toInteger()]
        del trigger.conditions[args[3].toInteger()]

    def onSampleNameChanged(self, view, args):
        previousName = args[1].toString()
        name = args[2].toString()
        for sample in self.track.samples:
            if previousName == sample.name:
                sample.name = name
                del self.track.state.samples[previousName]
                self.track.state.samples[name] = sample

    def onTriggerPlaysChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].plays = args[3].toInteger()

    def onTriggerRestartChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].restart = args[3].toBoolean()

    def onTriggerFadeInChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].fadeIn = args[3].toInteger()

    def onConditionTypeChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        trigger = sample.triggers[args[2].toInteger()]
        conditionIndex = args[3].toInteger()
        del trigger.conditions[conditionIndex]
        conditionType = args[4].toString()
        Log.trace("Changing condition type to {}".format(conditionType))
        trigger.conditions.insert(conditionIndex, AudioCondition.create(conditionType))

    def onConditionCompareChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions[args[3].toInteger()].compare = args[4].toString()

    def onConditionStatusChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions[args[3].toInteger()].status = getSoundStatus(args[4].toString())

    def onConditionSampleChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions[args[3].toInteger()].sample = args[4].toString()

    def onConditionLowerChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions[args[3].toInteger()].value.value[0] = args[4].toInteger()

    def onConditionUpperChanged(self, view, args):
        sample = self.track.state.samples[args[1].toString()]
        sample.triggers[args[2].toInteger()].conditions[args[3].toInteger()].value.value[1] = args[4].toInteger()

    def onSetIntensity(self, view, args):
        if self.track:
            self.track.state.intensity = args[1].toInteger()

    def onSetDaytime(self, view, args):
        if self.track:
            self.track.state.daytime = args[1].toInteger()

    def onSelectSample(self, view, args):
        self.selectedSample = args[1].toString()
        self.selectFile(['.wav', '.ogg'], args[2].toBoolean())

    def selectFile(self, fileTypes, shouldCreate=False):
        if not self.chooser:
            self.chooser = FileChooserUi(self, fileTypes)
            self.shouldCreate = shouldCreate

    def chooseFile(self, filePath):
        self.chooser = None
        if not filePath:
            return
        filePath = filePath.replace('\\', '/')
        if filePath.endswith('.cdf'):
            if self.shouldCreate:
                if os.path.exists(filePath):
                    Log.info("Not creating a new track because file already exists.")
                    return
                self.track = AudioTrack(filePath)
                self.track.name = "Track"
                self.track.write()
            else:
                self.track = AudioTrack(filePath)
                self.track.read()
            self.loadTrack()
        else:
            #Must be a sample file
            commands = []
            if self.shouldCreate:
                #Create the new Sample and add it to the track
                sample = AudioSample()
                sample.name = self.selectedSample
                sample.setPath(filePath)
                self.track.addSample(sample)
                #Add the commands to push to the frontend
                commands.append('var sample = App.Sample.create({{name: "{}", path: "{}"}});'.format(self.selectedSample, filePath))
                commands.append('App.dynamuse.track.samples.pushObject(sample);')
            else:
                #Update the filepath for the sample
                self.track.state.samples[self.selectedSample].setPath(filePath)
                commands.append('App.dynamuse.selectSample(sample);')
                #Add commands to update frontend
                commands.append('var sample = App.dynamuse.track.samples.findProperty("name", "{}");'.format(self.selectedSample))
                commands.append('sample.set("path", "{}");'.format(filePath))
            self.view.execute(commands)
        game.gui.focusView(self.view)

    def loadTrack(self):
        commands = []
        commands.append('App.set("dynamuse", App.Dynamuse.create());')
        commands.append('App.dynamuse.set("track", App.Track.create({{name: "{}", path: "{}"}}));'.format(self.track.name, self.track.path))
        commands.append('App.dynamuse.track.set("bar", {});'.format(self.track.barTime))
        for sample in self.track.samples:
            commands.append('App.dynamuse.track.samples.pushObject(App.Sample.create({{name: "{}", path: "{}"}}));'.format(sample.name, sample.path))
        for sample in self.track.samples:
            commands.append('var sample = App.dynamuse.track.samples.findProperty("name", "{}");'.format(sample.name))
            commands.append('App.dynamuse.set("sample", sample);')
            for trigger in sample.triggers:
                commands.append('var trigger = App.Trigger.create();')
                commands.append('App.dynamuse.set("trigger", trigger);')
                commands.append('trigger.plays = {};'.format(trigger.plays))
                commands.append('trigger.forced = {};'.format(boolStr(trigger.forceRestart)))
                commands.append('trigger.fadeIn = {};'.format(trigger.fadeIn))
                for condition in trigger.conditions:
                    commands.append('var condition = App.Condition.create({{type: App.conditions.findProperty("name", "{}")}});'.format(condition.name))
                    if hasattr(condition, 'value'):
                        commands.append('condition.lower = {};'.format(condition.value.value[0]))
                        commands.append('condition.upper = {};'.format(condition.value.value[1]))
                    if hasattr(condition, 'compare'):
                        commands.append('condition.compare = "{}";'.format(condition.compare))
                    if hasattr(condition, 'sample'):
                        commands.append('condition.sample = App.dynamuse.track.samples.findProperty("name", "{}");'.format(condition.sample))
                    commands.append("condition.get('comparisionOptions');")
                    commands.append('trigger.conditions.pushObject(condition);')
                commands.append('sample.triggers.pushObject(trigger);')
        commands.append('App.dynamuse.set("sample", null);')
        commands.append('App.dynamuse.set("trigger", null);')
        self.view.execute(commands)
