<commit_before>//
//  GraphView.swift
//  GraphView
//
//  Created by <NAME> on 1/23/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import UIKit

public class GraphView: UIView {
    lazy private var animator: UIDynamicAnimator = UIDynamicAnimator(referenceView: self)
    lazy public var panGestureRecognizer: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panGestureRecognized:")
    
    var panAttachment: UIAttachmentBehavior? {
        willSet {
            if let panAttachment = panAttachment {
                animator.removeBehavior(panAttachment)
            }
        }
        didSet {
            if let panAttachment = panAttachment {
                animator.addBehavior(panAttachment)
            }
        }
    }
    
    func panGestureRecognized(recognizer: UIPanGestureRecognizer) {
        let point = recognizer.locationInView(self)
        switch recognizer.state {
        case .Began:
            if let view = hitTest(recognizer.locationInView(self), withEvent: nil), node = view.superview where graph.nodes.contains(view) {
                panAttachment = UIAttachmentBehavior(item: node, attachedToAnchor: point)
                panAttachment?.frequency = 5
            }
        case .Changed:
            panAttachment?.anchorPoint = point
        case .Ended:
            fallthrough
        case .Cancelled:
            panAttachment = nil
        default:
            break
        }
    }
    
    public var graph: Graph<UIView> {
        willSet {
            let removedNodes = graph.nodes.subtract(newValue.nodes)
            removedNodes.forEach { $0.superview!.removeFromSuperview() }
            animator.removeAllBehaviors()
        }
        didSet {
            // Add new nodes
            let addedNodes = graph.nodes.subtract(oldValue.nodes)
            addedNodes.forEach { self._addNode($0) }
            
            // Setup behaviors
            _setupBehaviors()
        }
    }
    
    public override func layoutSubviews() {
        graph.nodes.map{ $0.superview! }.forEach{ node in
            node.center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
        }
        super.layoutSubviews()
    }
    
    private func _addNode(view: UIView) {
        precondition(!view.isDescendantOfView(self))
        let node = NodeView(view, withPadding: padding)
        addSubview(node)
    }
    
    private func _setupBehaviors() {
        animator.removeAllBehaviors()

        for (a, b) in graph.edges.map({ $0.tuple }) {
            let attachment = UIAttachmentBehavior(item: a.superview!, attachedToItem: b.superview!)
            attachment.length = 0
            attachment.damping = damping
            attachment.frequency = 1
            animator.addBehavior(attachment)
        }
        animator.addBehavior({
            let collision = UICollisionBehavior(items: Array(graph.nodes).map{ $0.superview! })
            collision.setTranslatesReferenceBoundsIntoBoundaryWithInsets(UIEdgeInsets(top: -padding, left: -padding, bottom: -padding, right: -padding))
            collision.collisionMode = .Everything
            return collision
        }())
        animator.addBehavior({
            let behavior = UIDynamicItemBehavior(items: Array(graph.nodes).map{ $0.superview! })
            behavior.allowsRotation = false
            behavior.elasticity = 1
            return behavior<commit_msg>erge branch 'master' of https://github.com/JadenGeller/GraphView<commit_after>//
//  GraphView.swift
//  GraphView
//
//  Created by <NAME> on 1/23/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import UIKit

public class GraphView: UIView {
    lazy private var animator: UIDynamicAnimator = UIDynamicAnimator(referenceView: self)
    lazy public var panGestureRecognizer: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panGestureRecognized:")
    
    var panAttachment: UIAttachmentBehavior? {
        willSet {
            if let panAttachment = panAttachment {
                animator.removeBehavior(panAttachment)
            }
        }
        didSet {
            if let panAttachment = panAttachment {
                animator.addBehavior(panAttachment)
            }
        }
    }
    
    func panGestureRecognized(recognizer: UIPanGestureRecognizer) {
        let point = recognizer.locationInView(self)
        switch recognizer.state {
        case .Began:
            if let view = hitTest(recognizer.locationInView(self), withEvent: nil), node = view.superview where graph.nodes.contains(view) {
                panAttachment = UIAttachmentBehavior(item: node, attachedToAnchor: point)
                panAttachment?.frequency = 5
            }
        case .Changed:
            panAttachment?.anchorPoint = point
        case .Ended:
            fallthrough
        case .Cancelled:
            panAttachment = nil
        default:
            break
        }
    }
    
    public var graph: Graph<UIView> {
        willSet {
            let removedNodes = graph.nodes.subtract(newValue.nodes)
            removedNodes.forEach { $0.superview!.removeFromSuperview() }
            animator.removeAllBehaviors()
        }
        didSet {
            // Add new nodes
            let addedNodes = graph.nodes.subtract(oldValue.nodes)
            addedNodes.forEach { self._addNode($0) }
            
            // Setup behaviors
            _setupBehaviors()
        }
    }
    
    public override func layoutSubviews() {
        graph.nodes.map{ $0.superview! }.forEach{ node in
            node.center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
        }
        for a in graph.nodes {
            let centerGravity = UIAttachmentBehavior(item: a.superview!, attachedToAnchor: self.center)
            centerGravity.length = 0
            centerGravity.damping = 1
            centerGravity.frequency = 0.5
            animator.addBehavior(centerGravity)
        }
        super.layoutSubviews()
    }
    
    private func _addNode(view: UIView) {
        precondition(!view.isDescendantOfView(self))
        let node = NodeView(view, withPadding: padding)
        addSubview(node)
    }
    
    private func _setupBehaviors() {
        animator.removeAllBehaviors()

        for (a, b) in graph.edges.map({ $0.tuple }) {
            let attachment = UIAttachmentBehavior(item: a.superview!, attachedToItem: b.superview!)
            attachment.length = 0
            attachment.damping = damping
            attachment.frequency = 1
            animator.addBehavior(attachment)
        }
        
        if frame.size != CGSizeZero {
            print("not 0")
        }
        else {
            print("zero")
        }
        animator.addBehavior({
            let collision = UICollisionBehavior(items: Array(graph.nodes).map{ $0.superview! })
            collision.setTranslatesReferenceBoundsIntoBoundaryWithInsets(UIEdgeInsets(top: -padding, left: -padding, bottom: -padding, right: -padding))
            collision.collisionMode = .Everything
            return collision
        }())
        animator.addBehavior({
            let behavior = UIDynamicItemBehavior(items: Array(graph.nodes).map{ $0.superview! })
            behavior.allowsRotation = false
            behavior.elasticity = 1
            return behavior
{'fraction_non_alphanumeric': 0.08992903930131005, 'fraction_numerical': 0.006413755458515284, 'mean_word_length': 1.980479869865799, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2062709', 'n_tokens_mistral': 2047, 'n_tokens_neox': 2002, 'n_words': 419}