//
//  KeyPath.swift
//  Popsicle
//
//  Created by David Román Aguirre on 04/11/15.
//  Copyright © 2015 David Román Aguirre. All rights reserved.
//

/// `KeyPathable` defines how a value is transformed to a valid `NSObject` key path.
public protocol KeyPathable {
	func stringify() -> String
}

extension String : KeyPathable {
	public func stringify() -> String {
		return self
	}
}

extension NSLayoutAttribute: KeyPathable {
	public func stringify() -> String {

		var type = "UnknownAttribute"

		switch(self) {
		case .Left:
			type = "Left"

		case .Right:
			type = "Right"

		case .Top:
			type = "Top"

		case .Bottom:
			type = "Bottom"

		case .Leading:
			type = "Leading"

		case .Trailing:
			type = "Trailing"

		case .Width:
			type = "Width"

		case .Height:
			type = "Height"

		case .CenterX:
			type = "CenterX"

		case .CenterY:
			type = "CenterY"

		case .Baseline:
			type = "Baseline"

		case .FirstBaseline:
			type = "FirstBaseline"

		case .LeftMargin:
			type = "LeftMargin"

		case .RightMargin:
			type = "RightMargin"

		case .TopMargin:
			type = "TopMargin"

		case .BottomMargin:
			type = "BottomMargin"

		case .LeadingMargin:
			type = "LeadingMargin"

		case .TrailingMargin:
			type = "TrailingMargin"

		case .CenterXWithinMargins:
			type = "CenterXWithinMargins"

		case .CenterYWithinMargins:
			type = "CenterYWithinMargins"

		case .NotAnAttribute:
			type = "NotAnAttribute"
		}

		return "NSLayoutAttribute." + type
	}
}

/// `KeyPath` defines a `NSObject`'s key path, constrained to specific `NSObject` and `Interpolable` types for higher safety.
public struct KeyPath<T: NSObject, U: Interpolable> {
	let keyPathable: KeyPathable

	public init(keyPathable: KeyPathable) {
		self.keyPathable = keyPathable
	}
}

public let alpha                          = KeyPath<UIView, CGFloat>(keyPathable: "alpha")
public let backgroundColor                = KeyPath<UIView, UIColor>(keyPathable: "backgroundColor")
public let barTintColor                   = KeyPath<UIView, UIColor>(keyPathable: "barTintColor")
public let borderColor                    = KeyPath<CALayer, CGFloat>(keyPathable: "borderColor")
public let borderWidth                    = KeyPath<CALayer, CGFloat>(keyPathable: "borderWidth")
public let constant                       = KeyPath<NSLayoutConstraint, CGFloat>(keyPathable: "constant")
public let cornerRadius                   = KeyPath<CALayer, CGFloat>(keyPathable: "cornerRadius")
public let hidden                         = KeyPath<UIView, Bool>(keyPathable: "hidden")
public let textColor                      = KeyPath<UIView, UIColor>(keyPathable: "textColor")
public let tintColor                      = KeyPath<UIView, UIColor>(keyPathable: "tintColor")
public let transform                      = KeyPath<UIView, CGAffineTransform>(keyPathable: "transform")

public let baselineConstraint             = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Baseline)
public let firstBaselineConstraint        = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.FirstBaseline)

public let topConstraint                  = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Top)
public let leftConstraint                 = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Left)
public let rightConstraint                = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Right)
public let bottomConstraint               = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Bottom)
public let leadingConstraint              = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Leading)
public let trailingConstraint             = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Trailing)

public let leftMarginConstraint           = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.LeftMargin)
public let rightMarginConstraint          = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.RightMargin)
public let topMarginConstraint            = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.TopMargin)
public let bottomMarginConstraint         = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.BottomMargin)
public let leadingMarginConstraint        = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.LeadingMargin)
public let trailingMarginConstraint       = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.TrailingMargin)

public let centerXConstraint              = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.CenterX)
public let centerYConstraint              = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.CenterY)

public let centerXWithinMarginsConstraint = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.CenterXWithinMargins)
public let centerYWithinMarginsConstraint = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.CenterYWithinMargins)

public let widthConstraint                = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Width)
public let heightConstraint               = KeyPath<UIView, CGFloat>(keyPathable: NSLayoutAttribute.Height)

extension NSObject {
	static func filteredObjectAndKeyPath<T: NSObject, U: Interpolable>(withObject object: T, andKeyPath keyPath: KeyPath<T, U>) -> (NSObject, String) {
		if let view = object as? UIView, let superview = view.superview, let attribute = keyPath.keyPathable as? NSLayoutAttribute {
            
            let constrainedView = (attribute == .Width || attribute == .Height) ? view : superview
            
            for constraint in constrainedView.constraints where
                !constraint.isKindOfClass(NSClassFromString("NSContentSizeLayoutConstraint")!) &&
                ((constraint.firstItem as? NSObject == view && constraint.firstAttribute == attribute) ||
                    (constraint.secondItem as? NSObject == view && constraint.secondAttribute == attribute)) {
                        return (constraint, constant.keyPathable.stringify())
            }
		}

		return (object, keyPath.keyPathable.stringify())
	}
}