#
# Common utility functions to help deal with subscriptions to the server
#

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

class SubscriptionUtils
  constructor: () ->
    @logger = context.JK.logger
    @msgFactory = context.JK.MessageFactory;
    @subscriptions = {}
    @events = context.JK.EVENTS;
    @reconnectRegistrationTimeout = null

    this.init()

  init: () =>
    # once JamKazam is fully loaded, watch for SUBSCRIPTION_MESSAGE events
    $(document).on('JAMKAZAM_READY', this.registerWithGateway)


  genKey:(type, id) =>
    type + ":" + id

  test: () =>
    this.subscribe('test', '1')
    this.subscribe('test', '2')

  reregister: () =>
    # re-register all existing watches
    @reconnectRegistrationTimeout = null

    if context.JK.dlen(@subscriptions) > 0
      bulkSubscribe = []
      types = []
      ids = []
      for key, watch of @subscriptions
        bits = key.split(':')
        type = bits[0]
        id = bits[1]
        types.push(type)
        ids.push(id)
#        bulkSubscribe.push({type: type, id:id})

      # send a special message which contains all subscriptions in one message
      msg = @msgFactory.subscribeBulk(types, ids)
      context.JK.JamServer.send(msg)

  # whenever we reconnect, set a timer to automatically re-subscribe to any outstanding subscriptions
  onConnectionUp: () =>
    #this.test()

    if @reconnectRegistrationTimeout?
      clearTimeout(@reconnectRegistrationTimeout)

    if context.JK.dlen(@subscriptions) > 0
      @reconnectRegistrationTimeout = setTimeout(this.reregister, 1000) # re-register after 1 second, to prevent excessive messaging to server

  onConnectionDown: () =>
    if @reconnectRegistrationTimeout?
      clearTimeout(@reconnectRegistrationTimeout)

  registerWithGateway: () =>

    context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SUBSCRIPTION_MESSAGE, this.onSubscriptionMessage);

    $server = context.JK.JamServer.get$Server()

    $server.on(@events.CONNECTION_UP, this.onConnectionUp)
    $server.on(@events.CONNECTION_DOWN, this.onConnectionDown)

  onSubscriptionMessage: (header, payload) =>
    key = this.genKey(payload.type, payload.id)

    watch = @subscriptions[key]

    if watch
      watch.triggerHandler(@events.SUBSCRIBE_NOTIFICATION, {type:payload.type, id: payload.id, body: JSON.parse(payload.body)})
    else
      @logger.warn("unable to find subscription for #{key}")

  # call subscribe, and use the returned object to listen for events of name context.JK.EVENTS.SUBSCRIBE_NOTIFICATION
  subscribe: (type, id) =>

    id = id.toString()
    key = this.genKey(type, id)

    @logger.debug("subscribing for any notifications for #{key}")

    watch = @subscriptions[key]

    unless watch?
      watch = $({type: type, id: id})
      @subscriptions[key] = watch

    # tell server we want messages for this entity
    msg = @msgFactory.subscribe(type, id)
    context.JK.JamServer.send(msg)

    # watch can be used to watch for events using jquery
    watch

  # TODO: this should not send a unsubscribe message to the server it's the last listener for the specific type/id combo
  unsubscribe: (type, id) =>

    id = id.toString()
    key = this.genKey(type, id)

    @logger.debug("unsubscribing for any notifications for #{key}")

    watch = @subscriptions[key]

    delete @subscriptions[key]

    # tell server we don't want any more messages for this entity
    msg = @msgFactory.unsubscribe(type, id)
    context.JK.JamServer.send(msg)

    if watch
      # unattach any events
      watch.off();


    watch


# global instance
context.JK.SubscriptionUtils = new SubscriptionUtils()