     case Top(UIView?)
     case Bottom(UIView?)
     case VCenter(UIView?)
+    
+    func insetValue(layouts:[UIView: CGRect]) -> CGFloat {
+        switch self {
+        case .Parent:
+            return 0
+        case .Top(let v):
+            return v.flatMap { layouts[$0]?.origin.y } ?? 0
+        case .Bottom(let v):
+            return v.flatMap { layouts[$0].flatMap { $0.origin.y + $0.size.height }  } ?? 0
+        case .VCenter(let v):
+            return v.flatMap { layouts[$0].flatMap { $0.origin.y + $0.size.height/2 }  } ?? 0
+        }
+    }
 }
 
 public struct Viewport {

    return PutLayoutOperation<BoxHeight>(intentions: intentions)
}

//MARK: width & height
private protocol DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect
}

private struct LeftDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.origin.x = withValue
        return result
    }
}

private struct TopDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.origin.y = withValue
        return result
    }
}

private struct BottomDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.origin.y = withValue - rect.size.height
        return result
    }
}

private struct RightDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.origin.x = withValue - rect.size.width
        return result
    }
}

private struct WidthDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.size.width = withValue
        return result
    }
}

private struct HeightDirectLayoutAction : DirectLayoutAction {
    static func updateRect(rect: CGRect, withValue: CGFloat) -> CGRect {
        var result = rect
        result.size.height = withValue
        return result
    }
}

private struct DirectLayoutOperation<T:DirectLayoutAction> : LayoutOperation
{
    let view: UIView?
    let value: CGFloat
    func calculateLayouts(inout layouts: [UIView : CGRect], viewport: Viewport) {
        
        guard let view = view else {
            return
        }
        
        layouts[view] = T.updateRect(frameForView(view, layouts: &layouts), withValue: value)
    }
}

public func SetX(view: UIView?, value: CGFloat) -> LayoutOperation {
    return SetLeft(view, value: value)
}

public func SetY(view: UIView?, value: CGFloat) -> LayoutOperation {
    return SetTop(view, value: value)
}

public func SetWidth(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<WidthDirectLayoutAction>(view: view, value: value)
}

public func SetHeight(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<HeightDirectLayoutAction>(view: view, value: value)
}

public func SetLeft(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<LeftDirectLayoutAction>(view: view, value: value)
}

public func SetRight(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<RightDirectLayoutAction>(view: view, value: value)
}

public func SetTop(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<TopDirectLayoutAction>(view: view, value: value)
}

public func SetBottom(view: UIView?, value: CGFloat) -> LayoutOperation {
    return DirectLayoutOperation<BottomDirectLayoutAction>(view: view, value: value)
}

//MARK: size

public func SetSize(view: UIView?, width: CGFloat, height: CGFloat) -> LayoutOperation {
    return Combine( [
        SetWidth(view, value: width),
        SetHeight(view, value: height)
        ])
}

public func SetFrame(view: UIView?, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) -> LayoutOperation {
    return Combine( [
        SetLeft(view, value: width),
        SetTop(view, value: width),
        SetWidth(view, value: width),
        SetHeight(view, value: height)
        ])
}

//MARK: size to fit

public enum SizeToFitIntention {
    /**
     Use defined value
     */
    case Value(CGFloat)
    /**
     Use max value to fully fit content
     */
    case Max
    /**
     Use current frame value to fit content in it
     */
    case Current
    /**
     Use current frame value for fit calculation, but keep it as value for frame
     */
    case KeepCurrent
}

private struct SizeToFitOperation: LayoutOperation {
    let view: UIView?
    let width: SizeToFitIntention
    let height: SizeToFitIntention
    
    func calculateLayouts(inout layouts: [UIView : CGRect], viewport: Viewport) {
        
        guard let view = view else {
            return
        }
        
        let fr = frameForView(view, layouts: &layouts)
        
        var w: CGFloat = 0
        switch width {
        case .Value(let val):
            w = val
        case .Max:
            w = CGFloat.max
        case .Current:
            w = fr.width
        case .KeepCurrent:
            w = fr.width
        }
        
        var h: CGFloat = 0
        switch height {
        case .Value(let val):
            h = val
        case .Max:
            h = CGFloat.max
        case .Current:
            h = fr.height
        case .KeepCurrent:
            h = fr.height
        }
        
        var sz = view.sizeThatFits(CGSizeMake(w, h))
        
        if case .KeepCurrent = width {
            sz.width = fr.width
        }
        
        if case .KeepCurrent = height {
            sz.height = fr.height
        }
        
        SetSize(view, width: sz.width, height: sz.height).calculateLayouts(&layouts, viewport: viewport)
    }
}

public func SizeToFit(view: UIView?, width: SizeToFitIntention, height: SizeToFitIntention) -> LayoutOperation {
    return SizeToFitOperation(view: view, width: width, height: height)
}

// same as SizeToFit(view, width: .Max, height: .Max)
public func SizeToFitMax(view: UIView?) -> LayoutOperation {
    return SizeToFit(view, width: .Max, height: .Max)
}

// same as SizeToFit(view, width: .Current, height: .Current)
public func SizeToFit(view: UIView?) -> LayoutOperation {
    return SizeToFit(view, width: .Current, height: .Current)
}


//MARK: center

public func Center(view: UIView?, insets: UIEdgeInsets) -> LayoutOperation {
    return Combine( [

    }
}

//MARK: - NOOP

private struct NoLayoutOperation: LayoutOperation {
    
    func calculateLayouts(inout layouts: [UIView : CGRect], viewport: Viewport) {
        
