You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.8 KiB

//
// TimePeriodGroup.swift
// DateTools
//
// Created by Grayson Webster on 8/17/16.
// Copyright © 2016 Grayson Webster. All rights reserved.
//
import Foundation
/**
* Time period groups are the final abstraction of date and time in DateTools. Here, time
* periods are gathered and organized into something useful. There are two main types of time
* period groups, `TimePeriodCollection` and `TimePeriodChain`.
*
* [Visit our github page](https://github.com/MatthewYork/DateTools#time-period-groups) for more information.
*/
open class TimePeriodGroup: Sequence {
6 years ago
// MARK: - Variables
6 years ago
/**
* The array of periods that define the group.
*/
internal var periods: [TimePeriodProtocol] = []
6 years ago
internal var _beginning: Date?
internal var _end: Date?
6 years ago
/**
* The earliest beginning date of a `TimePeriod` in the group.
* Nil if any `TimePeriod` in group has a nil beginning date (indefinite).
* (Read Only)
*/
public var beginning: Date? {
return _beginning
}
6 years ago
/**
* The latest end date of a `TimePeriod` in the group.
* Nil if any `TimePeriod` in group has a nil end date (indefinite).
* (Read Only)
*/
public var end: Date? {
return _end
}
6 years ago
/**
* The number of periods in the periods array.
*/
public var count: Int {
return periods.count
}
6 years ago
/**
* The total amount of time between the earliest and latest dates stored in the
* periods array. Nil if any beginning or end date in any contained period is nil.
*/
public var duration: TimeInterval? {
if beginning != nil && end != nil {
return end!.timeIntervalSince(beginning!)
}
return nil
}
6 years ago
// MARK: - Initializers
6 years ago
public init() {
6 years ago
}
6 years ago
// MARK: - Comparisons
6 years ago
/**
* If `self.periods` contains the exact elements as the given group's periods array.
*
* - parameter group: The group to compare to self
*
* - returns: True if the periods arrays are the same
*/
public func equals(_ group: TimePeriodGroup) -> Bool {
return containSameElements(array1: self.periods, group.periods)
}
// MARK: - Sequence Protocol
6 years ago
public func makeIterator() -> IndexingIterator<Array<TimePeriodProtocol>> {
return periods.makeIterator()
}
6 years ago
public func map<T>(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] {
return try periods.map(transform)
}
6 years ago
public func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] {
return try periods.filter(isIncluded)
}
6 years ago
public func forEach(_ body: (TimePeriodProtocol) throws -> Void) rethrows {
return try periods.forEach(body)
}
6 years ago
public func split(maxSplits: Int, omittingEmptySubsequences: Bool, whereSeparator isSeparator: (TimePeriodProtocol) throws -> Bool) rethrows -> [AnySequence<TimePeriodProtocol>] {
return try periods.split(maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences, whereSeparator: isSeparator).map(AnySequence.init)
}
6 years ago
subscript(index: Int) -> TimePeriodProtocol {
get {
return periods[index]
}
}
6 years ago
internal func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result {
return try periods.reduce(initialResult, nextPartialResult)
}
6 years ago
internal func containSameElements(array1: [TimePeriodProtocol], _ array2: [TimePeriodProtocol]) -> Bool {
guard array1.count == array2.count else {
return false // No need to sorting if they already have different counts
}
6 years ago
var compArray1: [TimePeriodProtocol] = array1.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in
if period1.beginning == nil && period2.beginning == nil {
return false
} else if (period1.beginning == nil) {
return true
} else if (period2.beginning == nil) {
return false
} else {
return period2.beginning! < period1.beginning!
}
}
var compArray2: [TimePeriodProtocol] = array2.sorted { (period1: TimePeriodProtocol, period2: TimePeriodProtocol) -> Bool in
if period1.beginning == nil && period2.beginning == nil {
return false
} else if (period1.beginning == nil) {
return true
} else if (period2.beginning == nil) {
return false
} else {
return period2.beginning! < period1.beginning!
}
}
for x in 0..<compArray1.count {
if !compArray1[x].equals(compArray2[x]) {
return false
}
}
return true
}
}