Controller    = window.require 'spine/controller'

# Creates a 'overlay' type popup and wraps it in a friendly API
#
# The popup is created only when it is needed (right before showing)
#
# The creation of the popup suffers from some lag because of the cost of
# iframe creation and resource loading
# To reduce the lag, you can call preload() preemptively to create
# the popup in the background
# Avoid preloading multiple popups at the same time, as this will block
# browser rendering
#
# The Widget's CSS (from stylus) is copied into the popup's stylesheet
# upon creation (handled automatically by UI.popup)
#
# @example How to create an overlay and add elements and bind events
# 	class PhotoOverlayWidget extends Widget
# 		className: 'widget photo-overlay-widget'
# 		events:
# 			'click .image': '_onImageClick'
#
# 		overlayEvents:
# 			'click .close':   '_onCloseClick'
# 			'click .image':   '_rotate'
# 			'overlay-hidden': '_onOverlayHidden'
# 			'overlay-shown':  '_onOverlayShown'
#
# 		constructor: ->
# 			@overlay = new Overlay { parent: @, events: @overlayEvents }
# 			@ic = new ImageController item: {image:'http://placehold.it/100x200'}
#
# 			@overlay.append @closeButton = $('<div class="close">close nao!!</div>')
# 			@overlay.append @ic
#
# 			super
#
# @example How to do a fade in / fade out animation
# 	# Overlay.show/hide are asynchronous but instant (changes display prop on the iframe)
# 	# To show the overlay with a fade in you must:
# 	#	first hide the overlay.el
# 	# 	then make the popup iframe visible using show()
# 	# 	then animate the overlay.el opacity after show() is done (the promise is resolved)
# 	_onImageClick: (ev) ->
# 		@overlay.el.css { opacity: 0 }
# 		@overlay.show().then =>
# 			@overlay.el.animate { opacity: 1 }, 300
#
# 	# To hide the overlay using a fade out you must:
# 	# 	first animate the opacity to 0
# 	#	then hide() the overlay after the animation is done
# 	_onCloseClick: (ev) =>
# 		@overlay.el.animate { opacity: 0 }, 300, => @overlay.hide()
#
# @example How to style the contents of the popup
# 	changeSkin: (skin, options) =>
# 		@el.css('background-color', skin.backgroundcolor)
#
# 		overlayStyle = ".overlay { background-color: #{ skin.overlayBackgroundColor } }"
# 		overlayStyle += ".image { position:absolute; top: 50%; left: 50%; border-width: #{ skin.strokeThickness }px}"
#
# 		@overlay.style(overlayStyle)
class Overlay extends Controller
	className: 'overlay'

	# Construct a new Overlay
	#
	# @param [Object] options
	# @option options [Object] events an object containing the events to be delegated
	# @option options [Controller] parent the Controller that will handle the events
	constructor: (options = {}) ->
		throw new Error('The parent option is missing!') unless options.parent
		throw new Error('The events option is missing!') unless options.events

		super

	# override spine controller delegateEvents to delegate to the @parent controller
	delegateEvents: (events = @events) ->
		@eventsDelegated = true
		for key, method of events
			if @parent[method]
				match      = key.match(@eventSplitter)
				eventName  = match[1]
				selector   = match[2]
				method = do (method) => =>
					@parent[method] arguments...
					true
			if selector is ''
				@el.bind(eventName, method )
			else
				@el.on(eventName, selector, method)

	# Append a jquery element or a Controller inside the popup
	append: (el) ->
		el = el.el if el.el
		@el.append el

	# Force the creation of the popup to reduce the lag before showing
	# @return [Promise]
	preload: -> @_createPopup()

	# Convenience method to toggle the visibility of the popup
	# @return [Promise]
	toggle: -> @_createPopup().then => if @popup.visible then @_hide() else @_show()

	# Makes the popup appear
	# @return [Promise]
	show: -> @_createPopup().then @_show

	# Makes the popup hide
	# @return [Promise]
	hide: -> @_createPopup().then @_hide

	# Replace the popup's stylesheet
	# @param [String] style the css string to replace the popup stylesheet with
	style: (style) ->
		@styleCache = style if style

		return unless @popup
		@popup.style @styleCache

	# Standard Controller release method that also releases the popup
	release: ->
		super
		@eventsDelegated = false
		@popupPromise = null
		@popup.release()
		@

	_show: => @popup.show().then => @el.trigger 'overlay-shown'

	_hide: => @popup.hide().then => @el.trigger 'overlay-hidden'

	_createPopup: ->
		return @popupPromise if @popupPromise
		@popupPromise = Blogvio.UI.popup.new
				type: 'overlay'
			.then (@popup) =>
				@style()
				@popup.append(@el)
				@delegateEvents() unless @eventsDelegated
			.fail (err) ->
				console.error err.stack


module.exports = Overlay
