{"ast":null,"code":"import { Subscriber } from '../Subscriber';\nimport { Subscription } from '../Subscription';\nimport { Observable } from '../Observable';\nimport { Subject } from '../Subject';\nexport function groupBy(keySelector, elementSelector, durationSelector, subjectSelector) {\n  return source => source.lift(new GroupByOperator(keySelector, elementSelector, durationSelector, subjectSelector));\n}\n\nclass GroupByOperator {\n  constructor(keySelector, elementSelector, durationSelector, subjectSelector) {\n    this.keySelector = keySelector;\n    this.elementSelector = elementSelector;\n    this.durationSelector = durationSelector;\n    this.subjectSelector = subjectSelector;\n  }\n\n  call(subscriber, source) {\n    return source.subscribe(new GroupBySubscriber(subscriber, this.keySelector, this.elementSelector, this.durationSelector, this.subjectSelector));\n  }\n\n}\n\nclass GroupBySubscriber extends Subscriber {\n  constructor(destination, keySelector, elementSelector, durationSelector, subjectSelector) {\n    super(destination);\n    this.keySelector = keySelector;\n    this.elementSelector = elementSelector;\n    this.durationSelector = durationSelector;\n    this.subjectSelector = subjectSelector;\n    this.groups = null;\n    this.attemptedToUnsubscribe = false;\n    this.count = 0;\n  }\n\n  _next(value) {\n    let key;\n\n    try {\n      key = this.keySelector(value);\n    } catch (err) {\n      this.error(err);\n      return;\n    }\n\n    this._group(value, key);\n  }\n\n  _group(value, key) {\n    let groups = this.groups;\n\n    if (!groups) {\n      groups = this.groups = new Map();\n    }\n\n    let group = groups.get(key);\n    let element;\n\n    if (this.elementSelector) {\n      try {\n        element = this.elementSelector(value);\n      } catch (err) {\n        this.error(err);\n      }\n    } else {\n      element = value;\n    }\n\n    if (!group) {\n      group = this.subjectSelector ? this.subjectSelector() : new Subject();\n      groups.set(key, group);\n      const groupedObservable = new GroupedObservable(key, group, this);\n      this.destination.next(groupedObservable);\n\n      if (this.durationSelector) {\n        let duration;\n\n        try {\n          duration = this.durationSelector(new GroupedObservable(key, group));\n        } catch (err) {\n          this.error(err);\n          return;\n        }\n\n        this.add(duration.subscribe(new GroupDurationSubscriber(key, group, this)));\n      }\n    }\n\n    if (!group.closed) {\n      group.next(element);\n    }\n  }\n\n  _error(err) {\n    const groups = this.groups;\n\n    if (groups) {\n      groups.forEach((group, key) => {\n        group.error(err);\n      });\n      groups.clear();\n    }\n\n    this.destination.error(err);\n  }\n\n  _complete() {\n    const groups = this.groups;\n\n    if (groups) {\n      groups.forEach((group, key) => {\n        group.complete();\n      });\n      groups.clear();\n    }\n\n    this.destination.complete();\n  }\n\n  removeGroup(key) {\n    this.groups.delete(key);\n  }\n\n  unsubscribe() {\n    if (!this.closed) {\n      this.attemptedToUnsubscribe = true;\n\n      if (this.count === 0) {\n        super.unsubscribe();\n      }\n    }\n  }\n\n}\n\nclass GroupDurationSubscriber extends Subscriber {\n  constructor(key, group, parent) {\n    super(group);\n    this.key = key;\n    this.group = group;\n    this.parent = parent;\n  }\n\n  _next(value) {\n    this.complete();\n  }\n\n  _unsubscribe() {\n    const {\n      parent,\n      key\n    } = this;\n    this.key = this.parent = null;\n\n    if (parent) {\n      parent.removeGroup(key);\n    }\n  }\n\n}\n\nexport class GroupedObservable extends Observable {\n  constructor(key, groupSubject, refCountSubscription) {\n    super();\n    this.key = key;\n    this.groupSubject = groupSubject;\n    this.refCountSubscription = refCountSubscription;\n  }\n\n  _subscribe(subscriber) {\n    const subscription = new Subscription();\n    const {\n      refCountSubscription,\n      groupSubject\n    } = this;\n\n    if (refCountSubscription && !refCountSubscription.closed) {\n      subscription.add(new InnerRefCountSubscription(refCountSubscription));\n    }\n\n    subscription.add(groupSubject.subscribe(subscriber));\n    return subscription;\n  }\n\n}\n\nclass InnerRefCountSubscription extends Subscription {\n  constructor(parent) {\n    super();\n    this.parent = parent;\n    parent.count++;\n  }\n\n  unsubscribe() {\n    const parent = this.parent;\n\n    if (!parent.closed && !this.closed) {\n      super.unsubscribe();\n      parent.count -= 1;\n\n      if (parent.count === 0 && parent.attemptedToUnsubscribe) {\n        parent.unsubscribe();\n      }\n    }\n  }\n\n} //# sourceMappingURL=groupBy.js.map","map":null,"metadata":{},"sourceType":"module"}