

Activateable 	 = window.require 'spine/controller/activateable'
Tabs             = window.require 'spine/controller/tabs'
ContentModel     = window.require 'core/models/content'
CompositionModel = window.require 'core/models/composition'

Tab 			= require './tab'

Browser 		= require '../../browser/controller'
DirectInput 	= require './input'

Notificator     = require '../notification-controller'

UploadBrowser = require './browser/upload'

Container = require('Core/services/container/instance').default

class Content extends Tabs
  className			: 'content-browser'
  tabContainerClass 	: 'content-browser-tabs'
  containerClass 		: 'content-browser-container'

  title 				: 'Content'
  nextTitle   		: 'Edit Content'
  tabRenderer 		: Tab

  @include Activateable
  interval : 0

  events:
    'editor:browser:active' : '_onBrowserState'
    'editor:browser:auth'   : '_onBrowserState'

  constructor:->
    @browsers = {}
    super

    @el.prepend (@notificator = new Notificator).el
    Container.Content.events.error @showError
    @$bind 'error', (ev, message) => @showError(message)

  children: (filter = -> true) ->
    browser for _, browser of @browsers when filter(browser)

  setPremium: (@premium) ->

  activate: =>
    Activateable.activate.apply @, arguments
    @children((i)->i.isActive())?[0]?.auth?()
    # @children((i)->i.isActive())?[0]?.refresh?()
    @$trigger 'viewChange', 'content'
    @

  deactivate: =>
    Activateable.deactivate.apply @, arguments
    @children((i) -> i.isActive())[0]?.refreshChildren?()

  for: (@composition) ->
    @initialize()
    @

  initialize: () =>
    return console.warn 'No composition set' unless @composition

    @children((i) -> i.release())
    @stopListening()

    @meta = @composition.contentMeta()
    @browserOptions = @meta.browser?.options


    @addBrowser UploadBrowser

    sources = @meta.browser?.sources
    # console.log("content editor:", sources);
    if sources
      delete sources.websearch
      delete sources.blogvio
      delete sources.dropbox
      delete sources.flickr
      delete sources["google-drive"]

    @legacyAddBrowser source, key for key, source of sources

    if @meta.input
      @append @input = new DirectInput {control:@meta.input, @composition}
      @browsers['input'] = @input
      @listenTo @input, 'canAdd', @contentCanAdd

    @listenTo ContentModel, 'destroy', @onItemDestroy
    @listenTo ContentModel, 'update', @_onItemUpdate
    @listenTo ContentModel, 'create', @_onItemCreate
    @listenTo ContentModel, 'change', => @el.toggleClass 'has-reached-max', @composition.maxContentReached()

    @children()[0].active()

    @trigger 'initialized'

  addBrowser: (Browser) =>
    return unless Browser.isCompatible @browserOptions?.types
    browser = new Browser { filetypes: @browserOptions?.types }

    browser.on 'toggle', ({file, options}) =>
      # HACK do not try to toggle the item after upload if the widget already has max content
      return if options?.afterUpload and Container.Content.maxContentReached(@composition)
      try
        Container.Content.toggleItem(
          @composition,
          Browser.name,
          file.id,
          file.url,
          # TODO: add file prop to content attr map to meta?
          { title: file.name } if @meta.attributes.title
        )
      catch e
        console.warn e

    browser.on 'clearContent', =>
      Container.Content.clearContent(@composition, Browser.name)

    browser.observe 'selected', (selected) -> browser.tab.count selected.length

    updateSelected = =>
      contentItems = Container.Content.getItemsByService(Browser.name)
      selected = contentItems.map (item) -> item.metadata.id
      browser.set({ selected })

    Container.Content.events.change updateSelected
    updateSelected()

    @append @browsers[Browser.name] = browser

  ###
  # @deprecated
  # TODO: replace with addBrowser calls
  # TODO: refactor all browsers to get the service from the service container
  ###
  legacyAddBrowser: (service, serviceName) =>
    Service = window.require service.module or 'editor/content/service/default'
    content = @composition.getContent().filter((i)->i.metadata?.service is serviceName).map((i)->i.metadata)
    Browser = window.require service.browser or Service.browser

    @browsers[serviceName] = browser = new Browser
      content: content
      title:   serviceName
      Service: Service
      options: $.extend {}, @browserOptions, service.options or {}

    @listenTo browser, 'add', @contentAdd
    @listenTo browser, 'remove', @contentRemove
    @listenTo browser, 'update', @contentUpdate
    @listenTo browser, 'canAdd', @contentCanAdd
    @append browser

  focusBrowser: (browser) =>
    (@browsers[browser] or {'links': @input}[browser])?.active()

  ###
  # @deprecated
  # TODO: use Content service
  ###
  contentCanAdd: (callback, just_checking) =>
    if @premium
      @_premiumContentCanAdd(callback, just_checking)
    else
      @_freeContentCanAdd(callback, just_checking)

  ###
  # @deprecated
  ###
  _premiumContentCanAdd: (callback, just_checking) =>
    return callback.call @ unless @composition.maxContentReached()
    @showError 'max', true unless just_checking

  ###
  # @deprecated
  ###
  _freeContentCanAdd: (callback, just_checking) =>
    max = @composition.contentMeta().options.free_user_limit
    return callback.call @ unless @composition.maxContentReached(max)
    @showError 'maxFree', true unless just_checking

  ###
  # @deprecated
  # TODO: use Content service
  ###
  contentAdd: (item) =>
    props= {}
    props[attr] = item[attr] for attr, opts of @meta.attributes when item[attr]?
    props.metadata = item
    props.composition_id = @composition.id

    props[@meta.browser.options.attribute] = item.url
    (new ContentModel(props)).save()

  ###
  Event Handler for browser `remove` event

  Destroy the ContentModel associated with a removed item
  @deprecated
  TODO: use Content service
  ###
  contentRemove: (item) =>
    @stopListening ContentModel, 'destroy', @onItemDestroy
    removedContent = ContentModel.all().filter((i) =>
      i.metadata is item and i.composition_id is @composition.id
    )
    removedContent[0]?.destroy()
    @listenTo ContentModel, 'destroy', @onItemDestroy

    @showError('min', true) unless @composition.hasEnoughContent()

  ###
  Event Handler for browser `update` event

  Update the ContentModel associated with an updated item
  @deprecated
  TODO: use Content service
  ###
  contentUpdate: (item, attribute, value) =>
    content = ContentModel.all().filter((i) =>
      i.metadata is item
    )
    return unless content.length

    content[0].updateAttribute(attribute, value)

  ###
  Event Handler for ContentModel `destroy` event

  Deselect the item in the associated browser service
  @deprecated
  TODO: use Content service
  ###
  onItemDestroy: (item) =>
    # check if the removed Content is for the current working composition
    return unless item.composition_id is @composition.id
    # check if the Content was added with a browser service
    if (service = item.metadata?.service) and service isnt 'directinput'
      @browsers[service]?.removeEntry? item.metadata
    true

  _onItemCreate: (item) =>
    return unless item.composition_id is @composition.id
    if (service = item.metadata?.service) and service isnt 'directinput'
      @browsers[service]?.addEntry? item.metadata
    else
      @input.addEntry item
    true

  _onItemUpdate: (item) =>
    return unless item.composition_id is @composition.id
    if (service = item.metadata?.service) and service isnt 'directinput'
      @browsers[service]?.updateEntry? item, item.metadata
    true

  showError: (error, upgradeCTA = false) =>
    message = if @composition[error+'ErrorMsg'] then @composition[error+'ErrorMsg']() else error
    @notificator.notify message, {
      timeout: 10000
      onClick: (=> @$trigger 'Content:upgrade') if upgradeCTA
    }

  # TODO: see if this can be removed
  _onBrowserState: (event, options) =>
    @$trigger 'editor:content:browserState', options

  afterAdd:(child)=>
    super
    return unless child.options.pos
    @tabs.el.children(":nth-child(#{child.options.pos})").before child.tab.el

  release: ->
    @_release @
    super

module.exports = Content
