<commit_before>//
// DynamicTableView.swift
//
// Copyright © 2016 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

import UIKit
import BEMCheckBox

public class DynamicTableView: ReorderTableView, UITableViewDelegate, UITableViewDataSource {
    private let reuseIdentifier = DynamicTableViewCell.reuseIdentifier
    private var allowReordering: Bool { return cellOptions.contains(.Movable) }
    private var allowDeletion: Bool   { return cellOptions.contains(.Deletable) }
    public var sections: [Section<DynamicTableModel>] = []
    public var cellOptions: DynamicTableCellOptions = [] {
        didSet { canReorder = allowReordering }
    }
    public dynamic var rowActionDeleteColor: UIColor?
    /// Text to display in the swipe to delete row action. The default value is **"Delete"**.
    public var rowActionDeleteTitle: String = "Delete"
    /// A boolean value to determine whether the content is centered in the table view. The default value is `false`.
    public var isContentCentered = false
    /// A boolean value to determine whether the empty table view cells are hidden. The default value is `false`.
    public var emptyCellsHidden = false {
        didSet {
            tableFooterView = emptyCellsHidden ? UIView(frame: .zero) : nil
        }
    }

    private var configureCell: ((indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void)?
    public func configureCell(callback: (indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void) {
        configureCell = callback
    }

    private var willDisplayCell: ((indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void)?
    public func willDisplayCell(callback: (indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void) {
        willDisplayCell = callback
    }

    private var configureHeader: ((section: Int, header: UITableViewHeaderFooterView, text: String?) -> Void)?
    public func configureHeader(callback: (section: Int, header: UITableViewHeaderFooterView, text: String?) -> Void) {
        configureHeader = callback
    }

    private var configureFooter: ((section: Int, footer: UITableViewHeaderFooterView, text: String?) -> Void)?
    public func configureFooter(callback: (section: Int, footer: UITableViewHeaderFooterView, text: String?) -> Void) {
        configureFooter = callback
    }

    private var didSelectItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didSelectItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didSelectItem = callback
    }

    private var didDeselectItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didDeselectItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didDeselectItem = callback
    }

    private var didRemoveItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didRemoveItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didRemoveItem = callback
    }

    private var didMoveItem: ((sourceIndexPath: NSIndexPath, destinationIndexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didMoveItem(callback: (sourceIndexPath: NSIndexPath, destinationIndexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didMoveItem = callback
    }

    // MARK: Init Methods

    public convenience init() {
        self.init(options: [])
    }

    public convenience init(frame: CGRect) {
        self.init(frame: frame, options: [])
    }

    public convenience init(style: UITableViewStyle) {
        self.init(style: style, options: [])
    }

    public convenience init(frame: CGRect = CGRectZero, style: UITableViewStyle = .Plain, options: DynamicTableCellOptions) {
        self.init(frame: frame, style: style)
        cellOptions = options
    }

    public override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        commonInit()
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    // MARK: isContentCentered

    private var shouldUpdateActualContentInset = true
    private var actualContentInset = UIEdgeInsets.zero
    public override var contentInset: UIEdgeInsets {
        didSet {
            guard shouldUpdateActualContentInset else { return }
            actualContentInset = contentInset
        }
    }

    public override func reloadData() {
        super.reloadData()
        centerContentIfNeeded()
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        centerContentIfNeeded()
    }

    private func centerContentIfNeeded() {
        guard isContentCentered else { return }

        let totalHeight          = bounds.height
        let contentHeight        = contentSize.height
        let contentCanBeCentered = contentHeight < totalHeight

        shouldUpdateActualContentInset = false
        if contentCanBeCentered {
            contentInset.top = ceil(totalHeight / 2 - contentHeight / 2)
        } else {
            contentInset.top = actualContentInset.top
        }
        shouldUpdateActualContentInset = true
    }

    // MARK: Setup Methods

    private func commonInit() {
        setupTableView()
        setupSubviews()
    }

    /// The default implementation of this method does nothing.
    ///
    /// Subclasses can override it to perform additional actions,
    /// for example, add new subviews or configure properties.
    /// This method is called when self is initialized using any of the relevant `init` methods.
    public func setupSubviews() {}

    private func setupTableView() {
        delegate           = self
        dataSource         = self
        reorderDelegate    = self
        backgroundColor    = UIColor.clearColor()
        estimatedRowHeight = 44
        rowHeight          = UITableViewAutomaticDimension
        registerClass(DynamicTableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
    }

    public func overrideRegisteredClass(cellClass: DynamicTableViewCell.Type) {
        registerClass(cellClass, forCellReuseIdentifier: reuseIdentifier)
    }

    // MARK: UITableViewDataSource

    public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return sections.count
    }

    public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count
    }

    public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! DynamicTableViewCell
        let item = sections[indexPath]
        cell.setData(item)
        configureAccessoryView(cell, type: item.accessory, indexPath: indexPath)

        if item.userInfo[DynamicTableView.ReorderTableViewDummyItemIdentifier] == nil {
            configureCell?(indexPath: indexPath, cell: cell, item: item)
        }

        return cell<commit_msg>Added isLastCellSeparatorHidden<commit_after>//
// DynamicTableView.swift
//
// Copyright © 2016 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

import UIKit
import BEMCheckBox

public class DynamicTableView: ReorderTableView, UITableViewDelegate, UITableViewDataSource {
    private let reuseIdentifier = DynamicTableViewCell.reuseIdentifier
    private var allowReordering: Bool { return cellOptions.contains(.Movable) }
    private var allowDeletion: Bool   { return cellOptions.contains(.Deletable) }
    public var sections: [Section<DynamicTableModel>] = []
    public var cellOptions: DynamicTableCellOptions = [] {
        didSet { canReorder = allowReordering }
    }
    public dynamic var rowActionDeleteColor: UIColor?
    /// Text to display in the swipe to delete row action. The default value is **"Delete"**.
    public dynamic var rowActionDeleteTitle = "Delete"
    /// A boolean value to determine whether the content is centered in the table view. The default value is `false`.
    public dynamic var isContentCentered = false
    /// A boolean value to determine whether the last table view cell separator is hidden. The default value is `false`.
    public dynamic var isLastCellSeparatorHidden = false
    /// A boolean value to determine whether the empty table view cells are hidden. The default value is `false`.
    public dynamic var emptyCellsHidden = false {
        didSet { tableFooterView = emptyCellsHidden ? UIView(frame: .zero) : nil }
    }

    private var configureCell: ((indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void)?
    public func configureCell(callback: (indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void) {
        configureCell = callback
    }

    private var willDisplayCell: ((indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void)?
    public func willDisplayCell(callback: (indexPath: NSIndexPath, cell: DynamicTableViewCell, item: DynamicTableModel) -> Void) {
        willDisplayCell = callback
    }

    private var configureHeader: ((section: Int, header: UITableViewHeaderFooterView, text: String?) -> Void)?
    public func configureHeader(callback: (section: Int, header: UITableViewHeaderFooterView, text: String?) -> Void) {
        configureHeader = callback
    }

    private var configureFooter: ((section: Int, footer: UITableViewHeaderFooterView, text: String?) -> Void)?
    public func configureFooter(callback: (section: Int, footer: UITableViewHeaderFooterView, text: String?) -> Void) {
        configureFooter = callback
    }

    private var didSelectItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didSelectItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didSelectItem = callback
    }

    private var didDeselectItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didDeselectItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didDeselectItem = callback
    }

    private var didRemoveItem: ((indexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didRemoveItem(callback: (indexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didRemoveItem = callback
    }

    private var didMoveItem: ((sourceIndexPath: NSIndexPath, destinationIndexPath: NSIndexPath, item: DynamicTableModel) -> Void)?
    public func didMoveItem(callback: (sourceIndexPath: NSIndexPath, destinationIndexPath: NSIndexPath, item: DynamicTableModel) -> Void) {
        didMoveItem = callback
    }

    // MARK: Init Methods

    public convenience init() {
        self.init(options: [])
    }

    public convenience init(frame: CGRect) {
        self.init(frame: frame, options: [])
    }

    public convenience init(style: UITableViewStyle) {
        self.init(style: style, options: [])
    }

    public convenience init(frame: CGRect = CGRectZero, style: UITableViewStyle = .Plain, options: DynamicTableCellOptions) {
        self.init(frame: frame, style: style)
        cellOptions = options
    }

    public override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        commonInit()
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    // MARK: isContentCentered

    private var shouldUpdateActualContentInset = true
    private var actualContentInset = UIEdgeInsets.zero
    public override var contentInset: UIEdgeInsets {
        didSet {
            guard shouldUpdateActualContentInset else { return }
            actualContentInset = contentInset
        }
    }

    public override func reloadData() {
        super.reloadData()
        centerContentIfNeeded()
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        centerContentIfNeeded()
    }

    private func centerContentIfNeeded() {
        guard isContentCentered else { return }

        let totalHeight          = bounds.height
        let contentHeight        = contentSize.height
        let contentCanBeCentered = contentHeight < totalHeight

        shouldUpdateActualContentInset = false
        if contentCanBeCentered {
            contentInset.top = ceil(totalHeight / 2 - contentHeight / 2)
        } else {
            contentInset.top = actualContentInset.top
        }
        shouldUpdateActualContentInset = true
    }

    // MARK: Setup Methods

    private func commonInit() {
        setupTableView()
        setupSubviews()
    }

    /// The default implementation of this method does nothing.
    ///
    /// Subclasses can override it to perform additional actions,
    /// for example, add new subviews or configure properties.
    /// This method is called when self is initialized using any of the relevant `init` methods.
    public func setupSubviews() {}

    private func setupTableView() {
        delegate           = self
        dataSource         = self
        reorderDelegate    = self
        backgroundColor    = UIColor.clearColor()
        estimatedRowHeight = 44
        rowHeight          = UITableViewAutomaticDimension
        registerClass(DynamicTableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
    }

    public func overrideRegisteredClass(cellClass: DynamicTableViewCell.Type) {
        registerClass(cellClass, forCellReuseIdentifier: reuseIdentifier)
    }

    // MARK: UITableViewDataSource

    public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return sections.count
    }

    public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count
    }

    public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! DynamicTableViewCell
        let item = sections[indexPath]
        cell.setData(item)
        configureAccessoryView(cell, type: item.accessory, indexPath: indexPath)

        if isLastCellSeparatorHidden {
            if indexPath.row == sections[indexPath.section].count - 1 {
                cell.separatorInset.left = cell.bounds.size.width
            }
        }

        if item.userInfo[DynamicTableView.ReorderTableViewDummyItemIdentifier] == nil {
            configureCell?(indexPath: indexPath, cell: cell, item: item)
        }

        return cell
{'fraction_non_alphanumeric': 0.08001189767995241, 'fraction_numerical': 0.0010113027959547888, 'mean_word_length': 3.2452020202020204, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 45, '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': '2139732', 'n_tokens_mistral': 4530, 'n_tokens_neox': 4233, 'n_words': 1424}