$ = jQuery
context = window
logger = context.JK.logger
ASSIGNMENT = context.JK.ASSIGNMENT
VOICE_CHAT = context.JK.VOICE_CHAT
MAX_TRACKS = context.JK.MAX_TRACKS
MAX_OUTPUTS = context.JK.MAX_OUTPUTS
gearUtils = context.JK.GearUtils
AUDIO_UNIT_TYPE_ID = 0
MIDI_TRACK = context.JK.MIDI_TRACK

###

  QVariantMap scanForPlugins();
QVariantMap VSTListVsts();
void VSTClearAll();
QVariantMap VSTSetTrackAssignment(const QVariantMap vst, const QString& trackId);
QVariantMap VSTListTrackAssignments();
void VSTShowHideGui(bool show,const QString& trackId);
void VST_ScanForMidiDevices();
QVariantMap VST_GetMidiDeviceList();
bool VST_EnableMidiForTrack(const QString& trackId, bool enableMidi, int midiDeviceIndex);
QVariantMap listSearchPaths();
void addSearchPath(int typeId, QString pathToAdd);
void removeSearchPath(int typeId, QString pathToRemove);
###

@ConfigureTracksStore = Reflux.createStore(
  {
    listenables: ConfigureTracksActions

    musicPorts: {inputs: [], outputs: []}
    trackNumber: null
    editingTrack: null
    vstPluginList: {vsts: []}
    vstTrackAssignments: {vsts: []}
    attachedMidiDevices: {midiDevices: []}
    midiTrackAssignments: {tracks: []}
    scanPaths: {paths:[]}
    scanningVsts: false
    trackType: 'audio'
    hasVst: true

    init: () ->
      this.listenTo(context.AppStore, this.onAppInit)
      this.listenTo(context.MixerStore, this.onMixersChanged)
      this.listenTo(context.PlatformStore, this.onPlatformChanged)

    onAppInit: (@app) ->

    editingTrackValid: () ->
      true

    onMixersChanged: (mixers) ->
      @loadChannels()
      @loadTrackInstruments()
      @changed()

    onPlatformChanged: (platform) ->
      @platform = platform

    onReset: (loadProfile) ->
      logger.debug("ConfigureTracksStore:reset", this)
      @trackNumber = null
      @editingTrack = null

      # you have to load the current profile in order to see track info, which we need
      #if loadProfile
        #currentProfile = context.jamClient.LastUsedProfileName();
        #result = context.jamClient.FTUELoadAudioConfiguration(currentProfile);

      @loadChannels()
      @loadTrackInstruments()

      #if force || context.jamClient.hasVstAssignment()
      #  @performVstScan()

      @listVsts()
      @performMidiScan()
      @listPaths()
      @changed()


    onEnableVst: ()  ->
      logger.debug("enabling VSTs")
      context.jamClient.VSTLoad()

      setTimeout((() =>
        @listVsts()

        @changed()
      ), 250)

    onTrySave: () ->
      logger.debug("ConfigureTracksStore:trySave")
      @trySave()

    trySave: () ->

    onVstScan: () ->
     @performVstScan(true)

     @changed()

    performVstScan: (sendChanged) ->
      #@hasVst = gon.global.vst_enabled  & context.jamClient.hasVstHost()
      logger.debug("hasVst", @hasVst)
      if @hasVst
        logger.debug("vstScan starting")
        @scanningVsts = true
        @scannedBefore = true
        result = context.jamClient.VSTScan("window.ConfigureTracksStore.onVstScanComplete")

    onClearVsts: () ->
      context.jamClient.VSTClearAll()

      setTimeout((() =>
        @listVsts()

        @changed()
      ), 250)

    onManageVsts:() ->
      logger.debug("manage vst selected")
      @app.layout.showDialog('manage-vsts-dialog')

    onVstScanComplete: () ->
      # XXX must wait a long time to get track assignments after scan/
      logger.debug("vst scan complete")
      @scanningVsts = false
      setTimeout((() =>
        @listVsts()
        @changed()
      ), 100 )

    onVstChanged: () ->
      setTimeout()
      logger.debug("vst changed")

      setTimeout((() =>
        @listVsts()
        @changed()
      ), 0)

    listPaths: () ->
      @scanPaths = context.jamClient.VSTListSearchPaths()

    # this comes from the JUCE library behavior
    vstTypeId: () ->
      if @platform.isWindows
        logger.debug("vstTypeId is windows")
        0
      else
        logger.debug("vstTypeId is not-windows")
        1

    onAddSearchPath: (path) ->
      logger.debug("VSTAddSearchPath: " + path)
      context.jamClient.VSTAddSearchPath(@vstTypeId(), path)
      @listPaths()
      @changed()

    onRemoveSearchPath: (path) ->
      logger.debug("VSTRemoveSearchPath: " + path)
      context.jamClient.VSTRemoveSearchPath(@vstTypeId(), path)
      @listPaths()
      @changed()

    onSelectVSTDirectory:() ->
      context.jamClient.ShowSelectVSTScanDialog("window.ConfigureTracksStore.onVSTPathSelected")

    onVSTPathSelected: (result) ->
      success = result.success
      path = result.vstPath

      if success
        logger.debug("vst path selected!", path)
        @onAddSearchPath(path)
      else
        logger.debug("nothing selected")

    listVsts: () ->

      @vstPluginList = context.jamClient.VSTListVsts()
      @vstTrackAssignments = context.jamClient.VSTListTrackAssignments()


    onMidiScan: () ->
      @performMidiScan()
      @changed()

    performMidiScan: () ->

      if !@hasVst
        logger.debug("performMidiScan skipped due to no VST")
        return
      context.jamClient.VST_ScanForMidiDevices();
      @attachedMidiDevices = context.jamClient.VST_GetMidiDeviceList();

    # trackNumber is 0-based, and optional
    onShowVstSettings: (trackNumber) ->
      if !@hasVst
        logger.debug("onShowVstSettings skipped due to no VST")
        return

      if !trackNumber?
        trackNumber = @trackNumber - 1 if @trackNumber?

      logger.debug("show VST GUI", trackNumber)

      context.jamClient.VSTShowHideGui(true, trackNumber) if trackNumber?


    findMidiTrack: () ->
      midi = null
      for assignment in @trackAssignments.inputs.assigned
        if assignment.assignment == MIDI_TRACK
          midi = assignment
          break
      midi

    removeMidiTrack: () ->
      removeIndex = -1
      for assignment, i in @trackAssignments.inputs.assigned
        if assignment.assignment == MIDI_TRACK
          # remove this
          removeIndex = i
          break

      if removeIndex > -1
        @trackAssignments.inputs.assigned.splice(removeIndex, 1)

    defaultTrackInstrument: (trackNumber) ->
      clientInstrument = context.jamClient.TrackGetInstrument(trackNumber)
      if clientInstrument == 0
        logger.debug("defaulting midi instrument for assignment #{trackNumber}")
        # ensure that we always have an instrument set (50 = electric guitar
        context.jamClient.TrackSetInstrument(trackNumber, 50)
        clientInstrument = 50

      context.JK.client_to_server_instrument_map[clientInstrument];
    # the backend does not have a consistent way of tracking assigned inputs for midi.
    # let's make it seem consistent
    injectMidiToTrackAssignments: () ->
      if @vstTrackAssignments?
        for vst in @vstTrackAssignments.vsts
          if vst.track == MIDI_TRACK - 1
            if vst.midiDeviceIndex > -1

              # first see if midi is already there
              midi = @findMidiTrack()

              if !midi?
                instrument = @defaultTrackInstrument(MIDI_TRACK)

                midi = [{assignment: MIDI_TRACK}]
                midi.instrument_id = instrument?.server_id
                midi.assignment = MIDI_TRACK
                @trackAssignments.inputs.assigned.push(midi)
            else
              @removeMidiTrack()

    changed: () ->

      @injectMidiToTrackAssignments()

      @editingTrack = []
      @editingTrack.assignment = @trackNumber

      if @trackNumber?

        for inputsForTrack in @trackAssignments.inputs.assigned
          if inputsForTrack.assignment == @trackNumber
            @editingTrack = inputsForTrack
            break


      # slap on vst, if any, from list of vst assignments
      for vst in @vstTrackAssignments.vsts
        if vst.track == @editingTrack.assignment - 1
          @editingTrack.vst = vst
          @editingTrack.midiDeviceIndex = vst.midiDeviceIndex
          break

        for inputsForTrack in @trackAssignments.inputs.assigned
          if vst.track == inputsForTrack.assignment - 1
            inputsForTrack.vst = vst

      if @editingTrack.vst?
        logger.debug("current track has a VST assigned:" + @editingTrack.vst.file)


      unscanned = !@scannedBefore && @vstPluginList.vsts.length <= 1

      @item = {
        unscanned: unscanned,
        musicPorts: @musicPorts,
        trackAssignments: @trackAssignments,
        trackNumber: @trackNumber,
        editingTrack: @editingTrack,
        vstPluginList: @vstPluginList,
        vstTrackAssignments: @vstTrackAssignments,
        attachedMidiDevices: @attachedMidiDevices,
        nextTrackNumber: @nextTrackNumber,
        newTrack: @newTrack,
        midiTrackAssignments: @midiTrackAssignments,
        scanningVsts: @scanningVsts,
        trackType: @trackType,
        scanPaths: @scanPaths
      }

      @trigger(@item)

    loadChannels: (forceInputsToUnassign, inputChannelFilter) ->
      # inputChannelFilter is an optional argument that is used by the Gear Wizard.
      # basically, if an input channel isn't in there, it's not going to be displayed
      @musicPorts = context.jamClient.FTUEGetChannels()

      # let's populate this bad boy
      @trackAssignments = {inputs: {unassigned: [], assigned: [], chat: []}, outputs: {unassigned: [], assigned: []}}

      nextTrackNumber = 0

      for input in @musicPorts.inputs
        if input.assignment == ASSIGNMENT.UNASSIGNED
          @trackAssignments.inputs.unassigned.push(input)
        else if input.assignment == ASSIGNMENT.CHAT
          @trackAssignments.inputs.chat.push(input)
        else
          nextTrackNumber = input.assignment if input.assignment > nextTrackNumber

          # make sure this assignment isn't already preset (you can have multiple inputs per 'track slot')
          found = false
          for assigned in @trackAssignments.inputs.assigned
            if assigned.assignment == input.assignment
              assigned.push(input)
              found = true

          if !found
            initial = [input]
            initial.assignment = input.assignment # store the assignment on the array itself, so we don't have to check inside the array for an input's assignment (which will all be the same)
            @trackAssignments.inputs.assigned.push(initial)
      for output in @musicPorts.outputs
        if output.assignment == ASSIGNMENT.OUTPUT
          @trackAssignments.outputs.assigned.push(output)
        else
          @trackAssignments.outputs.unassigned.push(output)

      @nextTrackNumber = nextTrackNumber + 1


    loadTrackInstruments: (forceInputsToUnassign) ->
      for inputsForTrack in @trackAssignments.inputs.assigned

        clientInstrument = context.jamClient.TrackGetInstrument(inputsForTrack.assignment)

        if clientInstrument == 0
          logger.debug("defaulting track instrument for assignment #{@trackNumber}")
          # ensure that we always have an instrument set (50 = electric guitar
          context.jamClient.TrackSetInstrument(inputsForTrack.assignment, 50)
          clientInstrument = 50

        instrument = context.JK.client_to_server_instrument_map[clientInstrument];

        inputsForTrack.instrument_id = instrument?.server_id


    onAssociateInputsWithTrack: (inputId1, inputId2) ->
      return unless @trackNumber?

      for inputs in @editingTrack
        context.jamClient.TrackSetAssignment(inputs.id, true, ASSIGNMENT.UNASSIGNED)

      if inputId1?
        logger.debug("setting input1 #{inputId1} to #{@trackNumber}")
        context.jamClient.TrackSetAssignment(inputId1, true, @trackNumber)

      if inputId2?
        logger.debug("setting input2 #{inputId2} to #{@trackNumber}")
        context.jamClient.TrackSetAssignment(inputId2, true, @trackNumber)

      result = context.jamClient.TrackSaveAssignments();

      if(!result || result.length == 0)

      else
        context.JK.Banner.showAlert('Unable to save assignments. ' + result);

    onAssociateInstrumentWithTrack: (instrumentId) ->
      return unless @trackNumber?

      logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", @trackNumber, instrumentId)

      clientInstrumentId = null
      if instrumentId != null && instrumentId != ''
        clientInstrumentId = context.JK.instrument_id_to_instrument[instrumentId].client_id
      else
        clientInstrumentId = 0

      context.jamClient.TrackSetInstrument(@trackNumber, clientInstrumentId)

      if @trackNumber == MIDI_TRACK
        logger.debug("checking midi track for track instrument synchronization")
        # keep artificial midi track in sync
        midi = @findMidiTrack()
        if midi?
          logger.debug("synced midi track with #{instrumentId}")
          midi.instrument_id = instrumentId


      if(!result || result.length == 0)

      else
        context.JK.Banner.showAlert('Unable to save assignments. ' + result);


      result = context.jamClient.TrackSaveAssignments()

      if(!result || result.length == 0)

      else
        context.JK.Banner.showAlert('Unable to save assignments. ' + result);

    onAssociateVSTWithTrack: (vst) ->

      if !@hasVst
        logger.debug("onAssociateVSTWithTrack skipped due to no VST")
        return

      if vst?
        logger.debug("associating track:#{@trackNumber - 1} with VST:#{vst.file}")

        found = null
        for knownVst in @vstPluginList.vsts
          if knownVst.file == vst.file
            found = knownVst
            break
        if found?
          context.jamClient.VSTSetTrackAssignment(found, @trackNumber - 1)
        else
          logger.error("unable to locate vst for #{vst}")
      else
        logger.debug("unassociated track:#{@trackNumber} with VST")
        # no way to unset VST assignment yet

      setTimeout((() => (
        @listVsts()

        @changed()
      )), 250)

    onCancelEdit: () ->
      if @newTrack
        for input in @editingTrack
          context.jamClient.TrackSetAssignment(input.id, true, ASSIGNMENT.UNASSIGNED)
          result = context.jamClient.TrackSaveAssignments()
          if(!result || result.length == 0)

          else
            context.JK.Banner.showAlert('Unable to save assignments. ' + result);
      else
        logger.error("unable to process cancel for an existing track")

    onDeleteTrack: (assignment) ->
      logger.debug("deleting track with assignment #{assignment}")
      if assignment != MIDI_TRACK
        track = null
        for inputsForTrack in @trackAssignments.inputs.assigned
          if inputsForTrack.assignment == assignment
            track = inputsForTrack
            break

        if track?
          for input in inputsForTrack
            context.jamClient.TrackSetAssignment(input.id, true, ASSIGNMENT.UNASSIGNED)
            result = context.jamClient.TrackSaveAssignments()

            if(!result || result.length == 0)

            else
              context.JK.Banner.showAlert('Unable to save assignments. ' + result);
        else
          logger.error("unable to find track to delete")
      else
        logger.debug("deleting midi track")
        @onAssociateMIDIWithTrack(null)
        @removeMidiTrack()
        @changed()

    onShowAddNewTrack: (type) ->

      # check if we have what we need... namely, free ports

      if type == 'audio'
        if @trackAssignments.inputs.unassigned.length == 0
          context.JK.Banner.showAlert('You have no more unassigned input ports.<br/><br/>You can free some up by editing an AUDIO track.')
          return
        @openLiveTrackDialog(@nextTrackNumber)
      else
        if @findMidiTrack()?
          context.JK.Banner.showAlert('You have only one MIDI input.')
          return
        @openLiveTrackDialog(MIDI_TRACK)

    onShowEditTrack: (trackNumber) ->
      @openLiveTrackDialog(trackNumber)

    openLiveTrackDialog: (trackNumber) ->
      @trackNumber = trackNumber
      logger.debug("opening live track dialog for track #{trackNumber}", @trackAssignments.inputs.assigned)

      @newTrack = true
      for inputsForTrack in @trackAssignments.inputs.assigned
        logger.debug("inputsForTrack.assignment @trackNumber", inputsForTrack.assignment, @trackNumber )
        if inputsForTrack.assignment == @trackNumber
          @newTrack = false
          break

      if @trackNumber == MIDI_TRACK
        @trackType = 'midi'
      else
        @trackType = 'audio'

      if @newTrack
        assignment = context.jamClient.TrackGetInstrument(@trackNumber)

        if assignment == 0
          logger.debug("defaulting track instrument for assignment #{@trackNumber}")
          # ensure that we always have an instrument set (50 = electric guitar
          context.jamClient.TrackSetInstrument(@trackNumber, 50)

      #@performVstScan()
      @performMidiScan()

      @changed()

      @app.layout.showDialog('configure-live-tracks-dialog')

    onDesiredTrackType: (trackType) ->
      @trackType = trackType

      if @trackType == 'midi'
        @trackNumber = MIDI_TRACK
      @changed()

    onUpdateOutputs: (outputId1, outputId2) ->

      context.jamClient.TrackSetAssignment(outputId1, true, ASSIGNMENT.OUTPUT);
      context.jamClient.TrackSetAssignment(outputId2, true, ASSIGNMENT.OUTPUT);

      result = context.jamClient.TrackSaveAssignments();

      if(!result || result.length == 0)

      else
        context.JK.Banner.showAlert('Unable to save assignments. ' + result);

    onShowEditOutputs: () ->
      @app.layout.showDialog('configure-outputs-dialog')

    onAssociateMIDIWithTrack: (midiInterface) ->

      @trackNumber = MIDI_TRACK

      if !midiInterface? || midiInterface == ''
        logger.debug("disabling midiInterface:#{midiInterface}, track:#{@trackNumber - 1}")
        context.jamClient.VST_EnableMidiForTrack(@trackNumber - 1, false, 0)
      else
        logger.debug("enabling midiInterface:#{midiInterface}, track:#{@trackNumber - 1}")
        context.jamClient.VST_EnableMidiForTrack(@trackNumber - 1, true, midiInterface)

      setTimeout((() => (
        @listVsts()

        @changed()
      )), 250)

  }
)