$ = jQuery
context = window
logger = context.JK.logger
rest = context.JK.Rest()
EVENTS = context.JK.EVENTS

JamTrackPlayerActions = @JamTrackPlayerActions
BrowserMediaStore = @BrowserMediaStore
BrowserMediaActions = @BrowserMediaActions

@JamTrackPlayerStore = Reflux.createStore(
  {
    listenables: JamTrackPlayerActions
    jamTrack: null
    previous: null
    requestedSearch: null
    requestedFilter: null
    subscriptions: {}
    enqueuedMixdowns: {}
    childWindow: null
    watchedMixdowns: {}

    init: ->
      # Register with the app store to get @app
      this.listenTo(context.AppStore, this.onAppInit)
      this.listenTo(context.BrowserMediaStore, this.onBrowserMediaChanged)
      @browserMediaState = {}
    onAppInit: (app) ->
      @app = app

    onBrowserMediaChanged: (browserMediaState) ->
      @browserMediaState = browserMediaState

      @changed()

    getState: () ->
      @state

    onOpened: (jamTrack, popup=true) ->
      @jamTrack = jamTrack

      @changed()

    onOpen: (jamTrack, popup=true) ->


      if jamTrack.id == @jamTrack?.id && @childWindow?
        logger.info("JamTrackPlayerStore: request to open already-opened JamTrack; ignoring")
        return

      @enqueuedMixdowns = {}
      @jamTrack = jamTrack

      sampleRate = 48
      @sampleRate = if sampleRate == 48 then 48 else 44


      if popup
        if @childWindow?
          @childWindow.close()

        logger.debug("opening JamTrackPlayer window")
        @childWindow = window.open(@createPopupUrl(jamTrack), 'Media Controls', 'scrollbars=yes,toolbar=no,status=no,height=667,width=450')

      @changed()

    createPopupUrl: (jamTrack) ->
      "/popups/jamtrack-player/" + jamTrack.id

    onWindowUnloaded: () ->
      BrowserMediaActions.stop()
      @childWindow = null

    pickMyPackage: () ->

      return unless @jamTrack?

      for mixdown in @jamTrack.mixdowns

        myPackage = null
        for mixdown_package in mixdown.packages
          if mixdown_package.file_type == 'mp3' && mixdown_package.encrypt_type == null && mixdown_package.sample_rate == @sampleRate
            myPackage = mixdown_package
            break

        mixdown.myPackage = myPackage

    subscriptionKey: (mixdown_package) ->
      "mixdown-#{mixdown_package.id}"

    subscribe: (mixdown_package) ->
      key = @subscriptionKey(mixdown_package)

      if !@watchedMixdowns[key]?
        # we need to register
        context.JK.SubscriptionUtils.subscribe('mixdown', mixdown_package.id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onMixdownSubscriptionEvent)
        @watchedMixdowns[key] = {type:'mixdown', id: mixdown_package.id}

    unsubscribe: (mixdown_package) ->
      key = @subscriptionKey(mixdown_package)
      if @watchedMixdowns[key]?
        context.JK.SubscriptionUtils.unsubscribe('mixdown', mixdown_package.id)
        delete @watchedMixdowns[key]

    manageWatchedMixdowns: () ->

      if @jamTrack?
        for mixdown in @jamTrack.mixdowns
          if mixdown.myPackage
            if mixdown.myPackage.signing_state == 'SIGNED'
              @unsubscribe(mixdown.myPackage)
            else
              @subscribe(mixdown.myPackage)

      else
        for key, subscription of @watchedMixdowns
          logger.debug("unsubscribing bulk", key, subscription)
          context.JK.SubscriptionUtils.unsubscribe(subscription.type, subscription.id)

        # we cleared them all out; clear out storage
        @watchedMixdowns = {}

    onMixdownSubscriptionEvent: (e, data) ->
      logger.debug("JamTrackStore: subscription notification received: type:" + data.type, data)

      return unless @jamTrack?

      mixdown_package_id = data.id

      for mixdown in @jamTrack.mixdowns
        for mixdown_package in mixdown.packages
          if mixdown_package.id == mixdown_package_id
            mixdown_package.signing_state = data.body.signing_state
            mixdown_package.packaging_steps = data.body.packaging_steps
            mixdown_package.current_packaging_step = data.body.current_packaging_step
            logger.debug("updated package with subscription notification event")

            if mixdown_package.signing_state == 'SIGNING_TIMEOUT' || mixdown_package.signing_state == 'QUEUED_TIMEOUT' || mixdown_package.signing_state == 'QUIET_TIMEOUT' || mixdown_package.signing_state == 'ERROR'
              @reportError(mixdown)

            @changed()
            break

    # this drives the state engine required to get a Mixdown from 'available on the server' to
    manageMixdownSynchronization: () ->


      if @jamTrack
        @jamTrack.activeMixdown = null
        @jamTrack.activeStem = null

      # let's see if we have a mixdown active?

      #if !@jamTrack?.last_mixdown_id?
      #  logger.debug("JamTrackStore: no mixdown active")

      for mixdown in @jamTrack.mixdowns
        if mixdown.id == @jamTrack.last_mixdown_id
          @jamTrack.activeMixdown = mixdown
          #logger.debug("JamTrackStore: mixdown active:", mixdown)
          break

      for stem in @jamTrack.tracks
        if stem.id == @jamTrack.last_stem_id
          @jamTrack.activeStem = stem
          break

      # let's check and see if we've asked the BrowserMediaStore to load this particular file or not

      if @jamTrack?.activeStem

        if @browserMediaState?.id != @jamTrack.activeStem.id
          new window.Fingerprint2().get((result, components) => (
            BrowserMediaActions.load(@jamTrack.activeStem.id, [window.location.protocol + '//' + window.location.host + "/api/jamtracks/#{@jamTrack.id}/stems/#{@jamTrack.activeStem.id}/download.mp3?file_type=mp3&mark=#{result}"], 'jamtrack_web_player')
          ))
          @jamTrack.activeStem.client_state = 'downloading'
        else
          if @browserMediaState.loaded
            @jamTrack.activeStem.client_state = 'ready'
          else if @browserMediaState.load_error
            @jamTrack.activeStem.client_state = 'download_fail'
          else
            @jamTrack.activeStem.client_state = 'downloading'


      else if @jamTrack?.activeMixdown

        # if we don't have this on the server yet, don't engage the rest of this logic...
        return if @jamTrack.activeMixdown?.myPackage?.signing_state != 'SIGNED'

        activePackage = @jamTrack.activeMixdown.myPackage

        if activePackage?
          if @browserMediaState?.id != activePackage.id
            new window.Fingerprint2().get((result, components) => (
              BrowserMediaActions.load(activePackage.id, [window.location.protocol + '//' + window.location.host + "/api/mixdowns/#{@jamTrack.activeMixdown.id}/download.mp3?file_type=mp3&sample_rate=48&mark=#{result}"], 'jamtrack_web_player')
            ))
            @jamTrack.activeMixdown.client_state = 'downloading'
          else
            if @browserMediaState.loaded
              @jamTrack.activeMixdown.client_state = 'ready'
            else if @browserMediaState.load_error
              @jamTrack.activeMixdown.client_state = 'download_fail'
            else
              @jamTrack.activeMixdown.client_state = 'downloading'

      else if @jamTrack?

        masterTrack = null
        for jamTrackTrack in @jamTrack.tracks
          if jamTrackTrack.track_type == 'Master'
            masterTrack = jamTrackTrack
            break

        if @browserMediaState?.id != @jamTrack.id
          BrowserMediaActions.load(@jamTrack.id, [masterTrack.preview_mp3_url], 'jamtrack_web_player')
          @jamTrack.client_state = 'downloading'
        else
          if @browserMediaState.loaded
            @jamTrack.client_state = 'ready'
          else if @browserMediaState.load_error
            @jamTrack.client_state = 'download_fail'
          else
            @jamTrack.client_state = 'downloading'
      else
        logger.error("unknown condition when processing manageMixdownSynchronization")


    changed: () ->

      @pickMyPackage()
      @manageWatchedMixdowns()
      @manageMixdownSynchronization()

      @state = {
        jamTrack: @jamTrack,
        opened: @previous == null && @jamTrack != null,
        closed: @previous != null && @jamTrack == null,
        fullTrackActivated: @previousMixdown != null && @jamTrack?.activeMixdown == null}
      @previous = @jamTrack
      @previousMixdown = @jamTrack?.activeMixdown
      this.trigger(@state)

    onCreateMixdown: (mixdown, done, fail) ->

      #volumeSettings = context.jamClient.GetJamTrackSettings();

      #track_settings = []

      #for track in volumeSettings.tracks
      #  track_settings.push({id: track.id, pan: track.pan, vol: track.vol_l, mute: track.mute})

      #mixdown.settings.tracks = track_settings

      logger.debug("creating mixdown", mixdown)

      rest.createMixdown(mixdown)
      .done((created) =>

        @addMixdown(created)

        logger.debug("created mixdown", created)

        @onEnqueueMixdown({id: created.id}, done, fail)
      )
      .fail((jqxhr) =>
        fail(jqxhr)
      )


    onEditMixdown: (mixdown) ->
      logger.debug("editing mixdown", mixdown)

      rest.editMixdown(mixdown)
      .done((updatedMixdown) =>
        logger.debug("edited mixdown")
        @updateMixdown(updatedMixdown)
      ).fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Edit Custom Mix', text: 'The server was unable to edit this mix.'})
      )

    onDeleteMixdown: (mixdown) ->
      logger.debug("deleting mixdown", mixdown)

      rest.deleteMixdown(mixdown)
      .done(() =>
        logger.debug("deleted mixdown")

        @deleteMixdown(mixdown)
      )
      .fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Deleted Custom Mix', text: 'The server was unable to delete this mix.'})
      )

    stopPlaying: () ->
      alert("stop playing")

    onOpenMixdown: (mixdown) ->
      if @browserMediaState.loading
        logger.warn("can not activate mixdown while browser media is loading")
        return

      logger.debug("opening mixdown", mixdown)

      # check if it's already available in the backend or not
      rest.markMixdownActive({id: @jamTrack.id, mixdown_id: mixdown.id})
      .done((edited) =>
        logger.debug("marked mixdown as active")
        @jamTrack = edited

        BrowserMediaActions.stop()

        @changed()
      )
      .fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
      )

    onOpenStem: (stem_id) ->
      if @browserMediaState.loading
        logger.warn("can not activate stem while browser media is loading")
        return

      logger.debug("opening stem", stem_id)

      # check if it's already available in the backend or not
      rest.markMixdownActive({id: @jamTrack.id, mixdown_id: null, stem_id: stem_id})
      .done((edited) =>
        logger.debug("marked stem as active")
        @jamTrack = edited

        BrowserMediaActions.stop()

        @changed()
      )
      .fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
      )

    onActivateNoMixdown: (jamTrack) ->

      if @browserMediaState.loading
        logger.warn("can not activate JamTrack while browser media is loading")
        return

      logger.debug("activating no mixdown")

      rest.markMixdownActive({id: @jamTrack.id, mixdown_id: null})
      .done((edited) =>
        logger.debug("marked JamTrack as active")

        @jamTrack = edited
        @changed()
      )
      .fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
      )


    onCloseMixdown: (mixdown) ->
      logger.debug("closing mixdown", mixdown)

    onEnqueueMixdown: (mixdown, done, fail) ->
      logger.debug("enqueuing mixdown", mixdown)

      package_settings = {file_type: 'mp3', encrypt_type: null, sample_rate: @sampleRate}
      package_settings.id = mixdown.id

      rest.enqueueMixdown(package_settings)
      .done((enqueued) =>

        @enqueuedMixdowns[mixdown.id] = {}

        logger.debug("enqueued mixdown package", package_settings)
        @addOrUpdatePackage(enqueued)
        done(enqueued) if done
      )
      .fail((jqxhr) =>
        @app.layout.notify({title:'Unable to Create Custom Mix', text: 'Click the error icon to retry.'})
        fail(jqxhr) if fail?
      )

    onDownloadMixdown: (mixdown) ->
      logger.debug("download mixdown", mixdown)

    onRefreshMixdown: (mixdown) ->
      logger.debug("refresh mixdown", mixdown)

    addMixdown: (mixdown) ->
      if @jamTrack?
        logger.debug("adding mixdown to JamTrackStore", mixdown)
        @jamTrack.mixdowns.splice(0, 0, mixdown)
        @changed()
      else
        logger.warn("no jamtrack to add mixdown to in JamTrackStore", mixdown)

    deleteMixdown: (mixdown) ->
      if @jamTrack?
        logger.debug("deleting mixdown from JamTrackStore", mixdown)
        index = null
        for matchMixdown, i in @jamTrack.mixdowns
          if mixdown.id == matchMixdown.id
            index = i
        if index?
          @jamTrack.mixdowns.splice(index, 1)

          if @jamTrack.activeMixdown?.id == mixdown.id
            @onActivateNoMixdown(@jamTrack)

          @changed()
        else
          logger.warn("unable to find mixdown to delete in JamTrackStore", mixdown)
      else
        logger.warn("no jamtrack to delete mixdown for in JamTrackStore", mixdown)

    updateMixdown: (mixdown) ->
      if @jamTrack?
        logger.debug("editing mixdown from JamTrackStore", mixdown)
        index = null
        for matchMixdown, i in @jamTrack.mixdowns
          if mixdown.id == matchMixdown.id
            index = i
        if index?
          @jamTrack.mixdowns[index] = mixdown

          @changed()
        else
          logger.warn("unable to find mixdown to edit in JamTrackStore", mixdown)
      else
        logger.warn("no jamtrack to edit mixdown for in JamTrackStore", mixdown)

    addOrUpdatePackage: (mixdown_package) ->
      if @jamTrack?
        added = false
        index = null
        for mixdown in @jamTrack.mixdowns
          existing = false
          if mixdown_package.jam_track_mixdown_id == mixdown.id
            for possiblePackage, i in mixdown.packages
              if possiblePackage.id == mixdown_package.id
                existing = true
                index = i
                break

            if existing
              mixdown.packages[index] = mixdown_package
              logger.debug("replacing mixdown package in JamTrackStore", mixdown_package)
            else
              mixdown.packages.splice(0, 0, mixdown_package)
              logger.debug("adding mixdown package in JamTrackStore")

            added = true
            @changed()
            break

        if !added
          logger.debug("couldn't find the mixdown associated with package in JamTrackStore", mixdown_package)
      else
        logger.warn("no mixdown to add package to in JamTrackStore", mixdown_package)



    reportError: (mixdown) ->

      enqueued = @enqueuedMixdowns[mixdown?.id]

      # don't double-report
      if !enqueued? || enqueued.marked
        return

      enqueued.marked = true
      data = {
        value: 1,
        user_id: context.JK.currentUserId,
        user_name: context.JK.currentUserName,
        result: "signing state: #{mixdown.myPackage?.signing_state}, client state: #{mixdown.client_state}",
        mixdown: mixdown.id,
        package: mixdown.myPackage?.id
        detail: mixdown.myPackage?.error_reason
      }
      rest.createAlert("Mixdown Sync failed for #{context.JK.currentUserName}", data)

      context.stats.write('web.mixdown.error', data)
  }
)