<commit_before>//
//  StreamDataSource.swift
//  Ello
//
//  Created by <NAME> on 11/22/14.
//  Copyright (c) 2014 Ello. All rights reserved.
//

import UIKit
import WebKit

class StreamDataSource: NSObject, UICollectionViewDataSource {

    typealias StreamContentReady = (indexPaths:[NSIndexPath]) -> ()
    typealias StreamFilter = (StreamCellItem -> Bool)?

    let imageBottomPadding:CGFloat = 10.0
    var streamKind:StreamKind
    var currentUser: User?

    // these are the items assigned from the parent controller
    var streamCellItems:[StreamCellItem] = []
    // these are either the same as streamCellItems (no filter) or if a filter
    // is applied this stores the filtered items
    var visibleCellItems:[StreamCellItem] = []
    // if a filter is added or removed, we update the items
    var streamFilter: StreamFilter {
        didSet { updateFilteredItems() }
    }

    let textSizeCalculator:StreamTextCellSizeCalculator
    let notificationSizeCalculator:StreamNotificationCellSizeCalculator

    weak var postbarDelegate:PostbarDelegate?
    weak var notificationDelegate:NotificationDelegate?
    weak var webLinkDelegate:WebLinkDelegate?
    weak var imageDelegate:StreamImageCellDelegate?
    weak var userDelegate:UserDelegate?
    weak var relationshipDelegate: RelationshipDelegate?
    weak var userListDelegate: UserListDelegate?

    init(streamKind:StreamKind,
        textSizeCalculator: StreamTextCellSizeCalculator,
        notificationSizeCalculator: StreamNotificationCellSizeCalculator)
    {
        self.streamKind = streamKind
        self.textSizeCalculator = textSizeCalculator
        self.notificationSizeCalculator = notificationSizeCalculator
        super.init()
    }

    // MARK: - Public

    func removeAllCellItems() {
        streamCellItems = []
        updateFilteredItems()
    }

    func removeCellItemsBelow(index: Int) {
        var belowIndex = index
        if index > streamCellItems.count {
            belowIndex = streamCellItems.count
        }
        let remainingCellItems = streamCellItems[0 ..< belowIndex]
        streamCellItems = Array(remainingCellItems)
        updateFilteredItems()
    }

    func postForIndexPath(indexPath: NSIndexPath) -> Post? {
        if !isValidIndexPath(indexPath) { return nil }

        return visibleCellItems[indexPath.item].jsonable as? Post
    }

    func commentForIndexPath(indexPath: NSIndexPath) -> Comment? {
        if !isValidIndexPath(indexPath) { return nil }

        return visibleCellItems[indexPath.item].jsonable as? Comment
    }

    func streamCellItem(at indexPath: NSIndexPath) -> StreamCellItem? {
        return visibleCellItems[indexPath.item]
    }

    // TODO: also grab out comment cells for the detail view
    func cellItemsForPost(post:Post) -> [StreamCellItem] {
        return visibleCellItems.filter({ (item) -> Bool in
            if let cellPost = item.jsonable as? Post {
                return post.postId == cellPost.postId
            }
            else {
                return false
            }
        })
    }

    func userForIndexPath(indexPath: NSIndexPath) -> User? {
        if !isValidIndexPath(indexPath) { return nil }

        if let user = visibleCellItems[indexPath.item].jsonable as? User {
            return user
        }
        else if let authorable = visibleCellItems[indexPath.item].jsonable as? Authorable {
            return authorable.author
        }
        return nil
    }

    func commentIndexPathsForPost(post: Post) -> [NSIndexPath] {
        var indexPaths:[NSIndexPath] = []

        for (index,value) in enumerate(visibleCellItems) {

            if let comment = value.jsonable as? Comment {
                if comment.parentPost?.postId == post.postId {
                    indexPaths.append(NSIndexPath(forItem: index, inSection: 0))
                }
            }
        }
        return indexPaths
    }

    func removeCommentsForPost(post: Post) -> [NSIndexPath] {
        let indexPaths = self.commentIndexPathsForPost(post)
        temporarilyUnfilter() {
            // these paths might be different depending on the filter
            let unfilteredIndexPaths = self.commentIndexPathsForPost(post)
            var newItems = [StreamCellItem]()
            for (index, item) in enumerate(self.streamCellItems) {
                var remove = unfilteredIndexPaths.reduce(false) { remove, path in
                    return remove || path.item == index
                }
                if !remove {
                    newItems.append(item)
                }
            }
            self.streamCellItems = newItems
        }
        return indexPaths
    }

    func removeItemAtIndexPath(indexPath: NSIndexPath) {
        if let itemToRemove = self.visibleCellItems[indexPath.item] {
            temporarilyUnfilter() {
                if let index = find(self.streamCellItems, itemToRemove) {
                    self.streamCellItems.removeAtIndex(index)
                }
            }
        }
    }

    func updateHeightForIndexPath(indexPath:NSIndexPath?, height:CGFloat) {
        if let indexPath = indexPath {
            if indexPath.item < countElements(visibleCellItems) {
                visibleCellItems[indexPath.item].oneColumnCellHeight = height + imageBottomPadding
                visibleCellItems[indexPath.item].multiColumnCellHeight = height + imageBottomPadding
            }
        }
    }

    func heightForIndexPath(indexPath:NSIndexPath, numberOfColumns:NSInteger) -> CGFloat {
        if !isValidIndexPath(indexPath) { return 0 }<commit_msg>this isn't an optional? strange<commit_after>//
//  StreamDataSource.swift
//  Ello
//
//  Created by <NAME> on 11/22/14.
//  Copyright (c) 2014 Ello. All rights reserved.
//

import UIKit
import WebKit

class StreamDataSource: NSObject, UICollectionViewDataSource {

    typealias StreamContentReady = (indexPaths:[NSIndexPath]) -> ()
    typealias StreamFilter = (StreamCellItem -> Bool)?

    let imageBottomPadding:CGFloat = 10.0
    var streamKind:StreamKind
    var currentUser: User?

    // these are the items assigned from the parent controller
    var streamCellItems:[StreamCellItem] = []
    // these are either the same as streamCellItems (no filter) or if a filter
    // is applied this stores the filtered items
    var visibleCellItems:[StreamCellItem] = []
    // if a filter is added or removed, we update the items
    var streamFilter: StreamFilter {
        didSet { updateFilteredItems() }
    }

    let textSizeCalculator:StreamTextCellSizeCalculator
    let notificationSizeCalculator:StreamNotificationCellSizeCalculator

    weak var postbarDelegate:PostbarDelegate?
    weak var notificationDelegate:NotificationDelegate?
    weak var webLinkDelegate:WebLinkDelegate?
    weak var imageDelegate:StreamImageCellDelegate?
    weak var userDelegate:UserDelegate?
    weak var relationshipDelegate: RelationshipDelegate?
    weak var userListDelegate: UserListDelegate?

    init(streamKind:StreamKind,
        textSizeCalculator: StreamTextCellSizeCalculator,
        notificationSizeCalculator: StreamNotificationCellSizeCalculator)
    {
        self.streamKind = streamKind
        self.textSizeCalculator = textSizeCalculator
        self.notificationSizeCalculator = notificationSizeCalculator
        super.init()
    }

    // MARK: - Public

    func removeAllCellItems() {
        streamCellItems = []
        updateFilteredItems()
    }

    func removeCellItemsBelow(index: Int) {
        var belowIndex = index
        if index > streamCellItems.count {
            belowIndex = streamCellItems.count
        }
        let remainingCellItems = streamCellItems[0 ..< belowIndex]
        streamCellItems = Array(remainingCellItems)
        updateFilteredItems()
    }

    func postForIndexPath(indexPath: NSIndexPath) -> Post? {
        if !isValidIndexPath(indexPath) { return nil }

        return visibleCellItems[indexPath.item].jsonable as? Post
    }

    func commentForIndexPath(indexPath: NSIndexPath) -> Comment? {
        if !isValidIndexPath(indexPath) { return nil }

        return visibleCellItems[indexPath.item].jsonable as? Comment
    }

    func streamCellItem(at indexPath: NSIndexPath) -> StreamCellItem? {
        return visibleCellItems[indexPath.item]
    }

    // TODO: also grab out comment cells for the detail view
    func cellItemsForPost(post:Post) -> [StreamCellItem] {
        return visibleCellItems.filter({ (item) -> Bool in
            if let cellPost = item.jsonable as? Post {
                return post.postId == cellPost.postId
            }
            else {
                return false
            }
        })
    }

    func userForIndexPath(indexPath: NSIndexPath) -> User? {
        if !isValidIndexPath(indexPath) { return nil }

        if let user = visibleCellItems[indexPath.item].jsonable as? User {
            return user
        }
        else if let authorable = visibleCellItems[indexPath.item].jsonable as? Authorable {
            return authorable.author
        }
        return nil
    }

    func commentIndexPathsForPost(post: Post) -> [NSIndexPath] {
        var indexPaths:[NSIndexPath] = []

        for (index,value) in enumerate(visibleCellItems) {

            if let comment = value.jsonable as? Comment {
                if comment.parentPost?.postId == post.postId {
                    indexPaths.append(NSIndexPath(forItem: index, inSection: 0))
                }
            }
        }
        return indexPaths
    }

    func removeCommentsForPost(post: Post) -> [NSIndexPath] {
        let indexPaths = self.commentIndexPathsForPost(post)
        temporarilyUnfilter() {
            // these paths might be different depending on the filter
            let unfilteredIndexPaths = self.commentIndexPathsForPost(post)
            var newItems = [StreamCellItem]()
            for (index, item) in enumerate(self.streamCellItems) {
                var remove = unfilteredIndexPaths.reduce(false) { remove, path in
                    return remove || path.item == index
                }
                if !remove {
                    newItems.append(item)
                }
            }
            self.streamCellItems = newItems
        }
        return indexPaths
    }

    func removeItemAtIndexPath(indexPath: NSIndexPath) {
        let itemToRemove = self.visibleCellItems[indexPath.item]
        temporarilyUnfilter() {
            if let index = find(self.streamCellItems, itemToRemove) {
                self.streamCellItems.removeAtIndex(index)
            }
        }
    }

    func updateHeightForIndexPath(indexPath:NSIndexPath?, height:CGFloat) {
        if let indexPath = indexPath {
            if indexPath.item < countElements(visibleCellItems) {
                visibleCellItems[indexPath.item].oneColumnCellHeight = height + imageBottomPadding
                visibleCellItems[indexPath.item].multiColumnCellHeight = height + imageBottomPadding
            }
        }
    }

    func heightForIndexPath(indexPath:NSIndexPath, numberOfColumns:NSInteger) -> CGFloat {
        if !isValidIndexPath(indexPath) { return 0 }
{'fraction_non_alphanumeric': 0.0769437718590261, 'fraction_numerical': 0.0028696977849520223, 'mean_word_length': 2.4398519432449106, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 29, 'https://': 0, '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': '6195448', 'n_tokens_mistral': 2995, 'n_tokens_neox': 2857, 'n_words': 695}