BindingInterfacePublic = 
	of: (object)->
		if @stage isnt 0 and @stage isnt 2
			throwErrorUnavail methodNames[0]
			
		unless checkIf.isObject(object) or checkIf.isFunction(object)
			throwErrorBadArg methodNames[0], object
		
		if checkIf.isBindingInterface(object)
			object = object.object

		if @stage is 2 # Indicates this binding is currently acting as a proxy for the another (proxied) binding
			@proxies[@proxies.length-1] = proxied = @lastProxied.of(object)
			@state.hasInitialBinding = true
			@state.hasTransform = false
			
			@_.addDep(proxied._)
			maybeUpdateDep(@_, proxied._)

		return @new(@stage+1, object)






	ofEvent: (eventName, customInMethod, customOutMethod)->
		if @stage isnt 0 or @state.hasEventName
			throwErrorUnavail methodNames[1]
		
		else if not eventName or not checkIf.isString(eventName)
			throwErrorBadArg methodNames[1], eventName

		else if isNaN parseInt(@property)
			throwWarning('badEventArg',1)

		@state.hasEventName = true
		@eventName = eventName
		@selector = @property+'#'+@eventName
		@customEventMethod = 
			'in': customInMethod
			'out': customOutMethod

		return @




















	to: (subject, specificOptions)->
		if @stage isnt 1 or @state.hasInitialBinding
			throwErrorUnavail methodNames[2]
		
		@proxies.push proxied = computeProxied(@, subject, specificOptions)
		if proxied.stage is 0
			newStage = 2
		else
			newStage = 3
			@state.hasInitialBinding = true

		return @new(newStage)




	and: (subject, specificOptions)->
		if @stage isnt 3 or not @state.hasInitialBinding or @state.hasMultiTransform
			throwErrorUnavail methodNames[3]

		@proxies.push proxied = computeProxied(@, subject, specificOptions)

		if proxied.stage is 0
			newStage = 2
		else
			newStage = 3
			@state.hasTransform = false
	
		return @new(newStage)






	toEvent: (eventName, customOutMethod, customInMethod, specificOptions)-> # Bad argument error handling will occur in .ofEvent
		if @stage isnt 1
			throwErrorUnavail methodNames[4]
		
		@proxies.push SimplyBind(0, specificOptions).ofEvent(eventName, customInMethod, customOutMethod)

		return @new(2)



	chainTo: (subject, specificOptions)->
		if @stage isnt 3
			throwErrorUnavail methodNames[5]

		return SimplyBind(@lastProxied).to(subject, specificOptions)



















	set: (newValue)->
		if @stage is 0 or @stage is 2
			throwErrorUnavail methodNames[6]
		
		@_.setValue(newValue, @placeholder)
		return @


	get: ()->
		if @stage is 0 or @stage is 2
			throwErrorUnavail methodNames[7]
		
		return if @placeholder then @_.pholderValues[@placeholder] else @_.value

	


	


	


	


	transformSelf: (transformFn)-> # Applied only to the last proxy
		if @stage isnt 1 or @stage is 1 and @_.type is 'Array'
			throwErrorUnavail methodNames[8]
		
		if not checkIf.isFunction(transformFn)
			throwWarning('fnOnly',1)
		else
			@_.selfTransform = transformFn
		
			if @_.options.updateOnBind
				currentValue = if @_.isMulti then @value[0] else @value
				@_.setValue(currentValue)
		
		return @
	

	transform: (transformFn)-> # Applied only to the last proxy
		if @stage isnt 3 or @state.hasTransform or @state.hasMultiTransform
			throwErrorUnavail methodNames[9]

		@state.hasTransform = @_.processTransform(transformFn, @proxies.slice(-1)) or false
		return @new(3)
	

	transformAll: (transformFn)-> # Applied to entrie proxies set
		if @stage isnt 3 or @state.hasTransform or @state.hasMultiTransform
			throwErrorUnavail methodNames[10]
		
		@state.hasMultiTransform = @_.processTransform(transformFn, @proxies) or false
		return @new(3)

	


	


	condition: (conditionFn)-> # Applied only to the last proxy
		if @stage isnt 3
			throwErrorUnavail methodNames[11]

		@_.processCondition(conditionFn, @proxies.slice(-1))
		return @new(3)
	

	conditionAll: (conditionFn)-> # Applied to entrie proxies set
		if @stage isnt 3
			throwErrorUnavail methodNames[12]
		
		@_.processCondition(conditionFn, @proxies)
		return @new(3)













	bothWays: (dontOrAltTransform)-> # Applied only to the last proxy
		if @stage isnt 3 or @state.hasMultiTransform
			throwErrorUnavail methodNames[13]

		proxied = @lastProxied
		proxiedBinding = proxied._.addDep(@_, true)
		originTransform = @_.transforms[proxied.ID]
		originCondition = @_.conditions[proxied.ID]

		if originTransform or dontOrAltTransform
			transformToUse = if checkIf.isFunction(dontOrAltTransform) then dontOrAltTransform else originTransform
			proxiedBinding.addTransform(@ID, transformToUse) if transformToUse and dontOrAltTransform isnt false

		if originCondition
			proxiedBinding.addCondition(@ID, originCondition)

		@_.addDep(proxied._, true)
		return @



	unBind: (bothWays)-> # Applied to all proxies
		if @stage isnt 3
			throwErrorUnavail methodNames[14]
		
		@_.removeDep(proxied._, bothWays) for proxied in @proxies
		return @










	pollEvery: (time)->
		if @stage isnt 3 or @_.type is 'Event'
			throwErrorUnavail methodNames[15]
		
		@_.addPollInterval(time)
	
		return @



	stopPolling: ()->
		if @stage isnt 3
			throwErrorUnavail methodNames[16]
	
		@_.removePollInterval()
		return @









	updateDepsOnEvent: (eventName, customMethod)->
		if @stage isnt 3
			throwErrorUnavail methodNames[17]

		@_.registerEvent(eventName, customMethod)
		return @


	removeEvent: (eventName, customMethod)->
		if @stage isnt 3
			throwErrorUnavail methodNames[18]

		@_.unRegisterEvent(eventName, customMethod)
		return @



	throttle: (delay)->
		if @stage isnt 1 and @stage isnt 3
			throwErrorUnavail methodNames[19]

		if delay and checkIf.isNumber(delay)
			@_.throttleRate = delay
	
		else if delay is false
			delete @_.throttleRate

		return @



	setOption: (optionName, newValue)->
		newOptions = "#{optionName}":newValue
		setOptionsForBinding(@_, newOptions)
		setOptionsForBinding(proxied._, newOptions) for proxied in @proxies
		
		return @



# Aliases
BindingInterfacePublic.update = BindingInterfacePublic.set
BindingInterfacePublic.twoWay = BindingInterfacePublic.bothWays
BindingInterfacePublic.pipe = BindingInterfacePublic.chainTo
methodNames = Object.keys(BindingInterfacePublic)
BindingInterface::[methodName] = BindingInterfacePublic[methodName] for methodName in methodNames
























































































# ==== Helpers =================================================================================
computeProxied = (instance, subject, specificOptions={})->
	proxied = SimplyBind(subject, specificOptions, true)
	
	if proxied.stage isnt 0
		instance._.addDep(proxied._, instance)
		maybeUpdateDep instance._, proxied._

	return proxied



maybeUpdateDep = (instance, proxied)-> # Both arguments refer to the private Binding instances
	if instance.options.updateOnBind or instance.type is 'Func'
		instance.updateDep(proxied, instance)









