// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/rendering.dart';

import 'framework.dart';

/// The options that control whether the statistics overlay displays certain
/// aspects of the compositor
enum StatisticsOption {
  /// Display the frame time and FPS of the last frame rendered. This field is
  /// updated every frame.
  ///
  /// This is the time spent by the rasterizer as it tries
  /// to convert the layer tree obtained from the widgets into OpenGL commands
  /// and tries to flush them onto the screen. When the total time taken by this
  /// step exceeds the frame slice, a frame is lost.
  displayRasterizerStatistics,
  /// Display the rasterizer frame times as they change over a set period of
  /// time in the form of a graph. The y axis of the graph denotes the total
  /// time spent by the rasterizer as a fraction of the total frame slice. When
  /// the bar turns red, a frame is lost.
  visualizeRasterizerStatistics,
  /// Display the frame time and FPS at which the interface can construct a
  /// layer tree for the rasterizer (whose behavior is described above) to
  /// consume.
  ///
  /// This involves all layout, animations, etc. When the total time taken by
  /// this step exceeds the frame slice, a frame is lost.
  displayEngineStatistics,
  /// Display the engine frame times as they change over a set period of time
  /// in the form of a graph. The y axis of the graph denotes the total time
  /// spent by the eninge as a fraction of the total frame slice. When the bar
  /// turns red, a frame is lost.
  visualizeEngineStatistics,
}

class StatisticsOverlay extends LeafRenderObjectWidget {

  /// Create a statistics overlay that only displays specific statistics. The
  /// mask is created by shifting 1 by the index of the specific StatisticOption
  /// to enable.
  StatisticsOverlay({ this.optionsMask, this.rasterizerThreshold: 0, Key key }) : super(key: key);

  /// Create a statistics overaly that displays all available statistics
  StatisticsOverlay.allEnabled({ Key key, this.rasterizerThreshold: 0 })
    : optionsMask = (
        1 << StatisticsOption.displayRasterizerStatistics.index |
        1 << StatisticsOption.visualizeRasterizerStatistics.index |
        1 << StatisticsOption.displayEngineStatistics.index |
        1 << StatisticsOption.visualizeEngineStatistics.index
      ),
      super(key: key);

  final int optionsMask;

  /// The rasterizer threshold is an integer specifying the number of frame
  /// intervals that the rasterizer must miss before it decides that the frame
  /// is suitable for capturing an SkPicture trace from for further analysis.
  ///
  /// For example, if you want a trace of all pictures that could not be
  /// renderered by the rasterizer within the frame boundary (and hence caused
  /// jank), specify 1. Specifying 2 will trace all pictures that took more
  /// more than 2 frame intervals to render. Adjust this value to only capture
  /// the particularly expensive pictures while skipping the others. Specifying
  /// 0 disables all capture.
  ///
  /// Captured traces are placed on your device in the application documents
  /// directory in this form "trace_<collection_time>.skp". These can
  /// be viewed in the Skia debugger.
  ///
  /// Notes:
  /// The rasterizer only takes into account the time it took to render
  /// the already constructed picture. This include the Skia calls (which is
  /// also why an SkPicture trace is generated) but not any of the time spent in
  /// dart to construct that picture. To profile that part of your code, use
  /// the instrumentation available in observatory.
  ///
  /// To decide what threshold interval to use, count the number of horizontal
  /// lines displayed in the statistics overlay for the rasterizer (not the
  /// engine). That should give an idea of how often frames are skipped (and by
  /// how many frame intervals).
  final int rasterizerThreshold;

  StatisticsBox createRenderObject() => new StatisticsBox(
    optionsMask: optionsMask,
    rasterizerThreshold: rasterizerThreshold
  );

  void updateRenderObject(StatisticsBox renderObject, RenderObjectWidget oldWidget) {
    renderObject.optionsMask = optionsMask;
    renderObject.rasterizerThreshold = rasterizerThreshold;
  }
}