import 'dart:async';

import 'package:comunic/helpers/events_helper.dart';
import 'package:flutter/material.dart';

/// Little State hack to avoid issues
///
/// @author Pierre HUBERT

abstract class SafeState<T extends StatefulWidget> extends State<T> {
  final _subscriptions = List<StreamSubscription>();
  final _timers = List<Timer>();

  bool _unmounted = false;

  @override
  void dispose() {
    _unmounted = true;

    // Close subscriptions
    _subscriptions.forEach((f) => f.cancel());

    // Stop intervals
    _timers.forEach((f) => f.cancel());

    super.dispose();
  }

  @override
  void setState(fn) {
    if (mounted && !_unmounted) super.setState(fn);
  }

  /// Register to a new subscription
  @protected
  void listen<T>(void onEvent(T event)) {
    _subscriptions.add(EventsHelper.on<T>(onEvent));
  }

  /// Register to a new subscription
  ///
  /// Callback will we called inside of setState
  @protected
  void listenChangeState<T>(void onEvent(T event)) {
    _subscriptions.add(EventsHelper.on<T>((d) {
      setState(() => onEvent(d));
    }));
  }

  /// Safely mimic the setTimeout javascript function
  ///
  /// If the widget is unmounted before the end of the timeout,
  /// the callback function is not called
  void setTimeout(int secs, void Function() cb) {
    Timer(Duration(seconds: secs), () {
      if (!_unmounted) cb();
    });
  }

  /// Safely mimic the setInterval javascript function
  void setInterval(int secs, void Function(Timer) cb) {
    final timer = Timer.periodic(Duration(seconds: secs), cb);
    _timers.add(timer);
  }
}