console = window.require 'spine/utils/console'
Model     = window.require 'spine/model'
AjaxMixin = require '../../api/mixin'

Skin    = require './skin'
Widget  = require './widget'
Content = require './content'

_loadWidget = (composition) ->
	return Widget.load(composition.widget_id).then(-> return composition)

# A composition is a collection of a skin and content for a widget
class Composition extends Model
	@extend AjaxMixin
	@configure(
		"Composition",
		'name',
		'content',
		'bulk_content',
		'skin_id',
		'widget_id'
		'width',
		'height',
		'widget_category',
		'user_id',
		'metadata'
	)

	@fetch @ajaxFetch

	constructor:(atts={})->
		console.group('Composition:constructor');
		atts.name 	 or= 'Untitled Composition'
		atts.width   or= 500
		atts.height  or= 500
		super atts

		console.groupEnd('Composition:constructor');

	opts: => @_opts or=
		min: (min = @contentMeta().options?.min)? and min or 1
		max: (max = @contentMeta().options?.max)? and max or 999

	minErrorMsg: =>
		@contentMeta().options.notification.min or 'Please add at least one item!'

	maxErrorMsg: =>
		@contentMeta().options.notification.max or 'You reached the maximum number of items!'

	maxFreeErrorMsg: =>
		'Upgrade to add more items, and get more features!'

	toJSON: ->
		result = super
		result.content = @getContent() unless result.content
		result.bulk_content = @bulkContent().toJSON?() if @contentMeta().bulkEditor
		return result

	changeID: (id) ->
		oldId = @id
		super
		Content.findAllByAttribute('composition_id', oldId).forEach (c) => c.updateAttribute 'composition_id', @id, { attribute: 'composition_id' }

	validateLength: (options = {}) ->
		valid = @hasEnoughContent()
		error = !valid and (if @maxContentReached() then 'max' else 'min')
		errorMsg = @[error+'ErrorMsg']?()

		{valid, error, errorMsg}

	getWidget: ->
		throw new Error('This composition is missing the widget_id.') unless @widget_id
		try
			return (require './widget').find(@widget_id)
		catch e
			throw new Error("The widget #{@widget_id} is not loaded")

	setWidgetId: (@widget_id) ->
		@save({ajax: false})
		@

	getSkin: ->
		try
			return Skin.find(@skin_id)
		catch e
			return false

	getContent: (filter = (c) -> !c._isDemoContent) ->
		return Content
			.findAllByAttribute('composition_id', @id)
			.filter(filter)
			.sort (a, b)-> a.order - b.order

	contentMeta: ->
		widget = @getWidget()
		return widget?.contentMeta

	bulkContent: =>
		return @_bkc if @_bkc?
		_meta = @contentMeta()
		attributes = {}
		attributes[attr] = _meta.attributes[attr] for attr in _meta.bulkEditor.attributes
		_meta = $.extend {}, _meta, {attributes}

		@bulk_content = $.extend @bulk_content or {}, {_meta, composition_id: 1}
		@_bkc = Content.refresh(@bulk_content)[0]

	###
	Test if the composition has less than maximum content
	###
	maxContentReached: (max = @opts().max) ->
		@getContent().length >= max

	hasEnoughContent: ->
		@opts().min <= @getContent().length <= @opts().max

	persist: ->
		console.log('%c PERSIST!!!', 'background-color: red; color:white')
		@_stopListen()

		if @isPersisted()
			promise = @ajax().update()
		else
			promise = @ajax().create()

		promise.then @listen

	isPersisted: ->
		return @id.slice(0, 1) isnt 'c'

	listen: =>
		@_stopListen()
		console.log('%c listen!!!', 'background-color: green; color:white')
		@listenTo Content, 'change', @_onContentChange
		@

	_stopListen: ->
		console.log('%c stoplisten!!!', 'background-color: blue; color:white')
		@stopListening Content, 'change', @_onContentChange
		@

	embed:->
		"<span>&lt;script async src=&quot;http://blogvio.com/embedder.js&quot;</span><br/> <span>data-blogvio-composition=&quot;#{@id}&quot;</span><br/> "+
		"<span>data-width=&quot;#{@width}&quot; data-height=&quot;#{@height}&quot;&gt;&lt;/script&gt;</span>"

	_metadata: (key, value, options = {}) =>
		return @metadata or= {} unless key?
		return @_metadata()[key] unless value?
		@_metadata()[key] = value
		options.attribute = 'metadata'
		@updateAttribute 'metadata', @metadata, options

	@load: (id) ->
		hasLoaded = Blogvio.Aye.defer()

		process = Blogvio.Aye.defer()
		process.promise
			.then(_loadWidget)
			.then((composition) -> composition._stopListen())
			.then((composition) -> composition.listen(); composition)
			.fail(hasLoaded.reject)
			.then(hasLoaded.resolve)

		try
			process.resolve(Composition.find(id))
		catch e
			@ajax()
				.fetch({id})
				.then((compositions) -> compositions[0])
				.then(process.resolve)
				.fail(process.reject)

		return hasLoaded.promise

	_onContentChange: (model, type, options) =>
		# return if type is 'update'
		console.group('Composition:_onContentChange');
		@updateAttribute('content', @getContent(), {ajax: false})
		console.groupEnd('Composition:_onContentChange');

Composition.bind 'destroy',(item)->
	try
		skin = Skin.find item.skin_id
		skin?.used()

module.exports = Composition
