<commit_before>// Copyright (c) 2015, <NAME>. All rights reserved. Use of this source
// is governed by a BSD-style license that can be found in the LICENSE file.

library august.options;

import 'package:august/august.dart';

class OptionsDefinition implements ModuleDefinition, InterfaceModuleDefinition {
  final name = 'Options';

  Options createModule(Run run, Map modules) {
    return new Options(run);
  }

  OptionsInterface createInterface(Options options, InterfaceEmit emit) {
    return new OptionsInterface(options, emit);
  }

  OptionsInterfaceHandler createInterfaceHandler(Options options) {
    return new OptionsInterfaceHandler(options);
  }
}

class Options {
  final List<Option> _available = <Option>[];
  final Run _run;

  Options(this._run) {
    additions.listen((e) => _available.add(e.option));
    removals.listen((e) => _available.remove(e.option));
  }

  List<Option> get available =>
      // Check for availability explicitly because events may not have been
      // received yet.
      new List.unmodifiable(_available.where((Option o) => o.isAvailable));

  Stream<AddOptionEvent> get additions =>
      _run.every((e) => e is AddOptionEvent);

  Stream<RemoveOptionEvent> get removals =>
      _run.every((e) => e is RemoveOptionEvent);

  Stream<UseOptionEvent> get uses => _run.every((e) => e is UseOptionEvent);
}

class OptionsInterface implements Interface {
  final Options _options;
  final InterfaceEmit _emit;

  OptionsInterface(this._options, this._emit);

  void use(String option) {
    _emit("use", {"option": option});
  }

  // TODO: UI shouldn't access native Options directly
  // must keep track of UI events, persist them
  List<Option> get available => _options.available;

  Stream<Option> get additions => _options.additions.map((e) => e.option);

  Stream<Option> get removals => _options.removals.map((e) => e.option);

  Stream<Option> get uses => _options.uses.map((e) => e.option);
}

class OptionsInterfaceHandler implements InterfaceHandler {
  final Options _options;

  OptionsInterfaceHandler(this._options);

  void handle(String action, Map args) {
    // TODO: Reimplement
  }
}

class Option {
  // TODO: Maybe allow mutable text too?
  final String text;
  final Run _run;
  final SettableScope _hasUses = new SettableScope.notEntered();

  final int allowedUseCount; // TODO: Allow mutate

  int _useCount = 0;
  int get useCount => _useCount;

  final ScopeAsValue _available = new ScopeAsValue();

  Option(this.text, this._run, {this.allowedUseCount: 1}) {
    if (allowedUseCount < 0) {
      throw new ArgumentError.value(allowedUseCount, "allowedUseCount",
          "Allowed use count must be non-negative.");
    }

    if (allowedUseCount > 0) {
      _hasUses.enter(null);
    }
  }

  /// Set a scope which contributes to determining this options availability.
  /// An option's availability is always governed by its [useCount] and
  /// [allowedUseCount] in addition to the provided scope.
  ///
  /// See [isAvailable] and [availability].
  void available(Scope scope) {
    _available.within(new AndScope(scope, _hasUses));
  }

  bool get isAvailable => _available.observed.value;

  /// A scope that is entered whenever this option is available.
  Scope get availability => _available.asScope;

  Future<UseOptionEvent> use() {
    if (_available.observed.nextValue == false) {
      return new Future.error(new OptionNotAvailableException(this));
    }

    _useCount += 1;

    if(_useCount == allowedUseCount) {
      _hasUses.exit(null);
    }

    return _run.emit(new UseOptionEvent(this));
  }
}

class AddOptionEvent {
  final Option option;<commit_msg>Make use count observable because sure why not<commit_after>// Copyright (c) 2015, <NAME>. All rights reserved. Use of this source
// is governed by a BSD-style license that can be found in the LICENSE file.

library august.options;

import 'package:august/august.dart';

class OptionsDefinition implements ModuleDefinition, InterfaceModuleDefinition {
  final name = 'Options';

  Options createModule(Run run, Map modules) {
    return new Options(run);
  }

  OptionsInterface createInterface(Options options, InterfaceEmit emit) {
    return new OptionsInterface(options, emit);
  }

  OptionsInterfaceHandler createInterfaceHandler(Options options) {
    return new OptionsInterfaceHandler(options);
  }
}

class Options {
  final List<Option> _available = <Option>[];
  final Run _run;

  Options(this._run) {
    additions.listen((e) => _available.add(e.option));
    removals.listen((e) => _available.remove(e.option));
  }

  List<Option> get available =>
      // Check for availability explicitly because events may not have been
      // received yet.
      new List.unmodifiable(_available.where((Option o) => o.isAvailable));

  Stream<AddOptionEvent> get additions =>
      _run.every((e) => e is AddOptionEvent);

  Stream<RemoveOptionEvent> get removals =>
      _run.every((e) => e is RemoveOptionEvent);

  Stream<UseOptionEvent> get uses => _run.every((e) => e is UseOptionEvent);
}

class OptionsInterface implements Interface {
  final Options _options;
  final InterfaceEmit _emit;

  OptionsInterface(this._options, this._emit);

  void use(String option) {
    _emit("use", {"option": option});
  }

  // TODO: UI shouldn't access native Options directly
  // must keep track of UI events, persist them
  List<Option> get available => _options.available;

  Stream<Option> get additions => _options.additions.map((e) => e.option);

  Stream<Option> get removals => _options.removals.map((e) => e.option);

  Stream<Option> get uses => _options.uses.map((e) => e.option);
}

class OptionsInterfaceHandler implements InterfaceHandler {
  final Options _options;

  OptionsInterfaceHandler(this._options);

  void handle(String action, Map args) {
    // TODO: Reimplement
  }
}

class Option {
  // TODO: Maybe allow mutable text too?
  final String text;
  final Run _run;
  final SettableScope _hasUses = new SettableScope.notEntered();

  final int allowedUseCount; // TODO: Allow mutate

  Observable<int> _useCount = new Observable.ofImmutable(0);
  Observed<int> get useCount => _useCount;

  final ScopeAsValue _available = new ScopeAsValue();

  Option(this.text, this._run, {this.allowedUseCount: 1}) {
    if (allowedUseCount < 0) {
      throw new ArgumentError.value(allowedUseCount, "allowedUseCount",
          "Allowed use count must be non-negative.");
    }

    if (allowedUseCount > 0) {
      _hasUses.enter(null);
    }
  }

  /// Set a scope which contributes to determining this options availability.
  /// An option's availability is always governed by its [useCount] and
  /// [allowedUseCount] in addition to the provided scope.
  ///
  /// See [isAvailable] and [availability].
  void available(Scope scope) {
    _available.within(new AndScope(scope, _hasUses));
  }

  bool get isAvailable => _available.observed.value;

  /// A scope that is entered whenever this option is available.
  Scope get availability => _available.asScope;

  Future<UseOptionEvent> use() {
    if (_available.observed.nextValue == false) {
      return new Future.error(new OptionNotAvailableException(this));
    }

    _useCount.set((c) => c + 1);

    if(_useCount.nextValue == allowedUseCount) {
      _hasUses.exit(null);
    }

    return _run.emit(new UseOptionEvent(this));
  }
}

class AddOptionEvent {
  final Option option;
{'fraction_non_alphanumeric': 0.11048234977095123, 'fraction_numerical': 0.002425222312045271, 'mean_word_length': 3.8014230271668823, 'pattern_counts': {'":': 2, '<': 31, '<?xml version=': 0, '>': 72, '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': '1019046', 'n_tokens_mistral': 2218, 'n_tokens_neox': 2117, 'n_words': 642}