$ = jQuery
context = window
context.JK ||= {};

context.JK.MusicianSearchFilter = class MusicianSearchFilter

  constructor: () ->
    @rest = context.JK.Rest()
    @logger = context.JK.logger
    @searchFilter = null
    @profileUtils = context.JK.ProfileUtils
    @helpBubble = context.JK.HelpBubbleHelper
    @searchResults = null
    @isSearching = false
    @pageNumber = 1
    @instrument_logo_map = context.JK.getInstrumentIconMap24()

  init: (app) =>
    @app = app
    @screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide }
    @app.bindScreen('musicians', @screenBindings)

    @screen = $('#musicians-screen')
    @resultsListContainer = @screen.find('#musician-search-filter-results-list')
    @spinner = @screen.find('.paginate-wait')

    this.registerResultsPagination()

    @screen.find('#btn-musician-search-builder').on 'click', => 
      this.showBuilder()

    @screen.find('#btn-musician-search-reset').on 'click', => 
      this.resetFilter()

  afterShow: () =>    
    @screen.find('#musician-search-filter-results').show()
    @screen.find('#musician-search-filter-builder').hide()
    this.getUserFilterResults()

  showBuilder: () =>
    @screen.find('#musician-search-filter-results').hide()
    @screen.find('#musician-search-filter-builder').show()
    @resultsListContainer.empty()

  afterHide: () =>
    @resultsListContainer.empty()

  renderSearchFilter: () => 
    $.when(this.rest.getMusicianSearchFilter()).done (sFilter) =>
      this.loadSearchFilter(sFilter)

  loadSearchFilter: (sFilter) =>
    @searchFilter = JSON.parse(sFilter)                
    args = 
      interests: @searchFilter.data_blob.interests
      skill_level: @searchFilter.data_blob.skill_level
      studio_sessions: @searchFilter.data_blob.studio_sessions
      concert_gigs: @searchFilter.data_blob.concert_gigs

    template = context.JK.fillTemplate(@screen.find('#template-musician-search-filter').html(), args)

    content_root = @screen.find('#musician-search-filter-builder')
    content_root.html template

    @screen.find('#btn-perform-musician-search').on 'click', => 
      this.performSearch()

    @screen.find('#btn-musician-search-cancel').on 'click', => 
      this.cancelFilter()

    this._populateSkill()
    this._populateStudio()
    this._populateGigs()
    this._populateInterests()
    this._populateAges()
    this._populateGenres()
    this._populateInstruments()
    this._populateSortOrder()



  _populateSelectWithKeys: (struct, selection, keys, element) =>
    element.children().remove()
    $.each keys, (idx, value) =>
      label = struct[value]
      blankOption = $ '<option value=""></option>'
      blankOption.text label
      blankOption.attr 'value', value
      blankOption.attr 'selected', '' if value == selection
      element.append(blankOption)
    context.JK.dropdown(element)

  _populateSelectIdentifier: (identifier) =>
    elem = $ '#musician-search-filter-builder select[name='+identifier+']'
    struct = gon.musician_search_meta[identifier]['map']
    keys = gon.musician_search_meta[identifier]['keys']
    this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem)

  _populateSelectWithInt: (sourceStruct, selection, element) =>
    struct = 
      '-1': 'Any'
    $.extend(struct, sourceStruct)
    this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element)

  _populateSortOrder: () =>
    this._populateSelectIdentifier('sort_order')

  _populateInterests: () =>
    this._populateSelectIdentifier('interests')

  _populateStudio: () => 
    elem = $ '#musician-search-filter-builder select[name=studio_sessions]'
    this._populateSelectWithInt(@profileUtils.studioMap, @searchFilter.data_blob.studio_sessions.toString(), elem)

  _populateGigs: () => 
    elem = $ '#musician-search-filter-builder select[name=concert_gigs]'
    this._populateSelectWithInt(@profileUtils.gigMap, @searchFilter.data_blob.concert_gigs.toString(), elem)

  _populateSkill: () =>
    elem = $ '#musician-search-filter-builder select[name=skill_level]'
    this._populateSelectWithInt(@profileUtils.skillLevelMap, @searchFilter.data_blob.skill_level.toString(), elem)

  _populateAges: () =>
    @screen.find('#search-filter-ages').empty()
    ages_map = gon.musician_search_meta['ages']['map']
    $.each gon.musician_search_meta['ages']['keys'], (index, key) =>
      ageTemplate = @screen.find('#template-search-filter-setup-ages').html()
      selected = ''
      ageLabel = ages_map[key]
      if 0 < @searchFilter.data_blob.ages.length
        key_val = key.toString()
        ageMatch = $.grep(@searchFilter.data_blob.ages, (n, i) ->
          n == key_val)
        selected = 'checked' if ageMatch.length > 0
      ageHtml = context.JK.fillTemplate(ageTemplate,
        id: key
        description: ageLabel
        checked: selected)
      @screen.find('#search-filter-ages').append ageHtml

  _populateGenres: () =>
    @screen.find('#search-filter-genres').empty()
    @rest.getGenres().done (genres) =>
      genreTemplate = @screen.find('#template-search-filter-setup-genres').html()
      selected = ''
      $.each genres, (index, genre) =>
        if 0 < @searchFilter.data_blob.genres.length 
          genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) ->
            n == genre.id) 
        else 
          genreMatch = []        
        selected = 'checked' if genreMatch.length > 0
        genreHtml = context.JK.fillTemplate(genreTemplate,
          id: genre.id
          description: genre.description
          checked: selected)
        @screen.find('#search-filter-genres').append genreHtml
  
  _populateInstruments: () =>
    @screen.find('#search-filter-instruments').empty()
    @rest.getInstruments().done (instruments) =>
      $.each instruments, (index, instrument) =>
        instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html()
        selected = ''
        proficiency = '1'
        if 0 < @searchFilter.data_blob.instruments.length
          instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) ->
            yn = inst.instrument_id == instrument.id
            proficiency = inst.proficiency_level if yn
            yn)
          selected = 'checked' if instMatch.length > 0
        instrumentHtml = context.JK.fillTemplate(instrumentTemplate,
          id: instrument.id
          description: instrument.description
          checked: selected)
        @screen.find('#search-filter-instruments').append instrumentHtml
        profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select'
        jprofsel = @screen.find(profsel)
        jprofsel.val(proficiency)
        context.JK.dropdown(jprofsel)
        return true

  _builderSelectValue: (identifier) =>
    elem = $ '#musician-search-filter-builder select[name='+identifier+']'
    elem.val()

  _builderSelectMultiValue: (identifier) =>
    vals = []
    elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked'
    if 'instruments' == identifier
      elem.each (idx) ->
        row = $(this).parent().parent()
        instrument =
          instrument_id: row.data('instrument-id')
          proficiency_level: row.find('select').val()
        vals.push instrument
    else
      elem.each (idx) ->
        vals.push $(this).val()
    vals

  willSearch: (reload) =>
    return false if @isSearching
    @isSearching = true
    if reload 
      @pageNumber = 1
      @screen.find('#musician-search-filter-spinner').show()
      @resultsListContainer.empty()
      @screen.find('#musician-search-filter-builder').hide()
      @screen.find('#musician-search-filter-results').show()
    true
  
  didSearch: (response) =>
    this.loadSearchFilter(response.filter_json)
    @searchResults = response
    @screen.find('#musician-search-filter-spinner').hide()
    this.renderMusicians()
    @screen.find('.paginate-wait').hide()
    @isSearching = false

  resetFilter: () =>
    if this.willSearch(true)
      @rest.postMusicianSearchFilter({ filter: 'reset' }).done(this.didSearch)

  cancelFilter: () =>
    this.resetFilter()

  getUserFilterResults: () =>
    if this.willSearch(true)
      @rest.getMusicianSearchFilter('results=true').done(this.didSearch)

  performSearch: () =>
    if this.willSearch(true)
      $.each gon.musician_search_meta.filter_keys.single, (index, key) =>
        @searchFilter[key] = this._builderSelectValue(key)
      $.each gon.musician_search_meta.filter_keys.multi, (index, key) =>
        @searchFilter[key] = this._builderSelectMultiValue(key)
      @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch)

  renderResultsHeader: () =>
    @screen.find('#musician-search-filter-description').html(@searchResults.description)
    if @searchResults.is_blank_filter
     @screen.find('#btn-musician-search-reset').hide()
    else
     @screen.find('#btn-musician-search-reset').show()
    
  renderMusicians: () =>
    this.renderResultsHeader() if @pageNumber == 1
    musicians = @searchResults.musicians
    len = musicians.length
    if 0 == len
      @screen.find('#musician-search-filter-results-list-blank').show()
      @screen.find('#musician-search-filter-results-list-blank').html('No results found')
      return
    else  
      @screen.find('#musician-search-filter-results-list-blank').hide()

    ii = 0
    mTemplate = @screen.find('#template-search-musician-row').html()
    aTemplate = @screen.find('#template-search-musician-action-btns').html()
    mVals = undefined
    musician = undefined
    renderings = ''
    instr_logos = undefined
    follows = undefined
    followVals = undefined
    aFollow = undefined
    myAudioLatency = @searchResults.my_audio_latency
    while ii < len
      musician = musicians[ii]
      if context.JK.currentUserId == musician.id
        ii++
        continue
      instr_logos = ''
      jj = 0
      ilen = musician['instruments'].length
      while jj < ilen
        instr_id = musician['instruments'][jj].instrument_id
        if instr_img = @instrument_logo_map[instr_id]
          instr_logos += '<img height="24" width="24" src="' + instr_img.asset + '" title="' + instr_id + '"/>'
        jj++
      actionVals = 
        profile_url: '/client#/profile/' + musician.id
        friend_class: 'button-' + (if musician['is_friend'] then 'grey' else 'orange')
        friend_caption: (if musician.is_friend then 'DIS' else '') + 'CONNECT'
        follow_class: 'button-' + (if musician['is_following'] then 'grey' else 'orange')
        follow_caption: (if musician.is_following then 'UN' else '') + 'FOLLOW'
        message_class: 'button-orange'
        message_caption: 'MESSAGE'
        button_message: 'button-orange'
      musician_actions = context.JK.fillTemplate(aTemplate, actionVals)
      latencyBadge = context._.template($("#template-account-session-latency").html(), $.extend(sessionUtils.createLatency(musician), musician), variable: 'data')
      mVals =
        avatar_url: context.JK.resolveAvatarUrl(musician.photo_url)
        profile_url: '/client#/profile/' + musician.id
        musician_name: musician.name
        musician_location: this._formatLocation(musician)
        instruments: instr_logos
        biography: musician['biography']
        follow_count: musician['follow_count']
        friend_count: musician['friend_count']
        recording_count: musician['recording_count']
        session_count: musician['session_count']
        musician_id: musician['id']
        musician_action_template: musician_actions
        latency_badge: latencyBadge
        musician_first_name: musician['first_name']
      $rendering = $(context.JK.fillTemplate(mTemplate, mVals))
      $offsetParent = @resultsListContainer.closest('.content')
      data = entity_type: 'musician'
      options = 
        positions: [
          'top'
          'bottom'
          'right'
          'left'
        ]
        offsetParent: $offsetParent
      scoreOptions = offsetParent: $offsetParent
      context.JK.helpBubble($('.follower-count', $rendering), 'follower-count', data, options);
      context.JK.helpBubble($('.friend-count', $rendering), 'friend-count', data, options);
      context.JK.helpBubble($('.recording-count', $rendering), 'recording-count', data, options);
      context.JK.helpBubble($('.session-count', $rendering), 'session-count', data, options);
      @helpBubble.scoreBreakdown $('.latency', $rendering), false, musician['full_score'], myAudioLatency, musician['audio_latency'], musician['score'], scoreOptions
      @resultsListContainer.append $rendering
      $rendering.find('.biography').dotdotdot()
      ii++

    this._bindMessageMusician()
    this._bindFriendMusician()
    this._bindFollowMusician()

    context.JK.bindHoverEvents()
    return  

  _bindMessageMusician: () =>
    objThis = this
    @screen.find('.search-m-message').on 'click', (evt) ->
      userId = $(this).parent().data('musician-id')
      objThis.app.layout.showDialog 'text-message', d1: userId


  _bindFriendMusician: () =>
    objThis = this
    @screen.find('.search-m-friend').on 'click', (evt) ->
      # if the musician is already a friend, remove the button-orange class, and prevent the link from working
      if 0 == $(this).closest('.button-orange').size()
        return false
      $(this).click (ee) ->
        ee.preventDefault()
        return
      evt.stopPropagation()
      uid = $(this).parent().data('musician-id')
      objThis.rest.sendFriendRequest objThis.app, uid, this.friendRequestCallback
  
  _bindFollowMusician: () =>
    objThis = this
    @screen.find('.search-m-follow').on 'click', (evt) ->
      # if the musician is already followed, remove the button-orange class, and prevent the link from working
      if 0 == $(this).closest('.button-orange').size()
        return false
      $(this).click (ee) ->
        ee.preventDefault()
        return
      evt.stopPropagation()
      newFollowing = {}
      newFollowing.user_id = $(this).parent().data('musician-id')
      url = '/api/users/' + context.JK.currentUserId + '/followings'
      $.ajax
        type: 'POST'
        dataType: 'json'
        contentType: 'application/json'
        url: url
        data: JSON.stringify(newFollowing)
        processData: false
        success: (response) ->
          # remove the orange look to indicate it's not selectable
          # @FIXME -- this will need to be tweaked when we allow unfollowing
          objThis.screen.find('div[data-musician-id=' + newFollowing.user_id + '] .search-m-follow').removeClass('button-orange').addClass 'button-grey'
          return
        error: objThis.app.ajaxError
  
  _formatLocation: (musician) ->
    if musician.city and musician.state
      musician.city + ', ' + musician.state
    else if musician.city
      musician.city
    else if musician.regionname
      musician.regionname
    else
      'Location Unavailable'

  friendRequestCallback: (user_id)=> 
    # TODO:

  paginate: () =>
    if @pageNumber < @searchResults.page_count && this.willSearch(false)
      @screen.find('.paginate-wait').show()
      @pageNumber += 1
      @rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch)
      return true
    false

  registerResultsPagination: () =>
    _resultsListContainer = @resultsListContainer
    _headerHeight = @screen.find('#musician-search-filter-results-header').height()
    _paginator = this.paginate

    @screen.find('.content-body-scroller').scroll ->
      if _resultsListContainer.is(':visible')
        jthis = $(this)
        wintop = jthis.scrollTop()
        winheight = jthis.innerHeight()
        docheight = jthis[0].scrollHeight - _headerHeight
        scrollTrigger = 0.98;
        if ((wintop / (docheight - winheight)) >= scrollTrigger)
          _paginator()
