//
//  DZKeyboardLayoutProxyView.swift
//
//  Created by Davide De Franceschi on 25/02/2015.
//

import UIKit

final class DZKeyboardLayoutProxyView: UIView {
	private var keyboardObserver: NSObjectProtocol?
	@IBOutlet weak var delegate: DZKeyboardLayoutProxyViewDelegate?
	
	override init(frame: CGRect) {
		super.init(frame: frame)
		commonInit()
	}
	required init?(coder aDecoder: NSCoder) {
		super.init(coder: aDecoder)
		commonInit()
	}
	private func commonInit() {
		translatesAutoresizingMaskIntoConstraints = true
		startObservingKeyboardNotifications()
	}
	override func awakeFromNib() {
		super.awakeFromNib()
		frame = CGRect(x: 0, y: superview!.bounds.height, width: superview!.bounds.width, height: 0)
		backgroundColor = .clearColor()
		opaque = false
		alpha = 0
		hidden = true
	}
	deinit {
		stopObservingKeyboardNotifications()
	}
}

private let changeKeyboardAnimateLayoutDuration: NSTimeInterval = 0.2
extension DZKeyboardLayoutProxyView {
	private func startObservingKeyboardNotifications() {
		keyboardObserver = NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification, object: nil, queue: nil) { [weak self] notification in
			guard
				let sself = self,
				let notificationInfo = notification.userInfo
			else { return }
			
			let startFrame = (notificationInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
			let endFrame = (notificationInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
			guard endFrame != startFrame else { return }
			
			let animationCurveOptions = UIViewAnimationOptions(rawValue: (notificationInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).unsignedLongValue)
			let notificationAnimationDuration = (notificationInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue as NSTimeInterval
			let animationDuration = notificationAnimationDuration > 0 ? notificationAnimationDuration : changeKeyboardAnimateLayoutDuration
			
			let newFrame = sself.superview?.convertRect(endFrame, fromView: nil) ?? .zero
			let callDelegateWillChangeFrame: () -> ()
			let callDelegateDidChangeFrame: () -> ()
			if let delegate = sself.delegate {
				callDelegateWillChangeFrame = { delegate.keyboardProxyView(sself, willChangeFrameToFrame: newFrame) }
				callDelegateDidChangeFrame = { delegate.keyboardProxyView(sself, didChangeFrameToFrame: newFrame) }
			} else {
				callDelegateWillChangeFrame = {}
				callDelegateDidChangeFrame = {}
			}
			let animationOptions = animationCurveOptions ∪ .BeginFromCurrentState
			let animations: () -> () = {
				sself.superview?.layoutIfNeeded()
				callDelegateDidChangeFrame()
			}
			let updateFrame: () -> () = { () -> () in
				callDelegateWillChangeFrame()
				sself.frame = newFrame
				UIView.animateWithDuration(animationDuration, delay: 0, options: animationOptions, animations: animations, completion: nil)
				return
			}
			dispatch_sync_main(updateFrame)
		}
	}
	private func stopObservingKeyboardNotifications() {
		if let observer = keyboardObserver {
			NSNotificationCenter.defaultCenter().removeObserver(observer)
		}
	}
}

@objc protocol DZKeyboardLayoutProxyViewDelegate: NSObjectProtocol {
	func keyboardProxyView(keyboardView: DZKeyboardLayoutProxyView, willChangeFrameToFrame frame: CGRect)
	func keyboardProxyView(keyboardView: DZKeyboardLayoutProxyView, didChangeFrameToFrame frame: CGRect)
}