// Copyright 2018 The Fuchsia 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 'dart:math' as math;

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:meta/meta.dart';

const EdgeInsets _kPadding = const EdgeInsets.only(top: 32.0, bottom: 12.0);

const ListEquality<RawImage> _kImageListEquality =
    const ListEquality<RawImage>();

// Shows a grid of horizontally scrolling images. Their scroll behavior is
// driven automatically using a ScrollController (see ImageGridModel).
class ImageGrid extends StatelessWidget {
  /// Image data used for rendering this grid.
  final List<RawImage> images;
  // If false, just use empty Containers instead of painting the RawImages.
  final bool drawImages;

  /// If not null, this is used to scroll the grid.
  final ScrollController scrollController;

  /// Constructor.
  const ImageGrid({
    @required this.images,
    @required this.drawImages,
    this.scrollController,
  });

  @override
  Widget build(BuildContext context) {
    return new DefaultTextStyle(
      style: const TextStyle(
        color: Colors.black,
        fontSize: 8.0,
        height: 1.2,
      ),
      child: new Container(
        padding: _kPadding,
        child: new Column(
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            new Text('Image Grid Test (Flutter)'),
            new Container(
              height: 8.0,
            ),
            new Expanded(
              child: new CustomScrollView(
                scrollDirection: Axis.horizontal,
                controller: scrollController,
                slivers: <Widget>[
                  new SliverPadding(
                    padding: const EdgeInsets.only(left: 32.0),
                    sliver: new SliverGrid(
                      gridDelegate: new _ImageGridDelegate(
                        images: images,
                        rowCount: 3,
                      ),
                      delegate: new SliverChildBuilderDelegate(
                          (BuildContext context, int index) =>
                              _buildItem(images[index]),
                          childCount: images.length),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildItem(RawImage image) {
    return new Container(
      padding: const EdgeInsets.only(
        right: 16.0,
        bottom: 16.0,
      ),
      child: new PhysicalModel(
        color: Colors.grey[200],
        borderRadius: new BorderRadius.circular(4.0),
        elevation: 2.0,
        child: drawImages
            ? image
            : new Container(
                width: 500.0,
                height: 500.0,
              ),
      ),
    );
  }
}

class _ImageGridDelegate extends SliverGridDelegate {
  final List<RawImage> images;
  final int rowCount;
  SliverConstraints _lastConstraints;
  _ImageGridLayout _lastLayout;

  _ImageGridDelegate({
    this.images,
    this.rowCount,
  });

  @override
  SliverGridLayout getLayout(SliverConstraints constraints) {
    if (_newConstraints(constraints)) {
      _lastConstraints = constraints;
      _lastLayout = new _ImageGridLayout(
        sliverGridGeometryList: _getSliverGeometryList(
          constraints.crossAxisExtent,
        ),
        rowCount: rowCount,
      );
    }
    return _lastLayout;
  }

  bool _newConstraints(SliverConstraints constraints) {
    return _lastConstraints == null ||
        _lastConstraints.crossAxisExtent != constraints.crossAxisExtent;
  }

  @override
  bool shouldRelayout(_ImageGridDelegate oldDelegate) {
    return oldDelegate.rowCount != rowCount ||
        !_kImageListEquality.equals(oldDelegate.images, images);
  }

  /// Generates the individual SliverGridGeometry elements that correspond to
  /// each image.
  List<SliverGridGeometry> _getSliverGeometryList(
    double crossAxisExtent,
  ) {
    List<SliverGridGeometry> sliverGridGeometryList = <SliverGridGeometry>[];
    List<SliverGridGeometry> lastElementInRow = <SliverGridGeometry>[];
    double rowHeight = crossAxisExtent / rowCount;

    int getShortestRow() {
      double smallestOffest = double.infinity;
      int smallestOffestIndex = 0;
      for (int i = 0; i < rowCount; i++) {
        if (lastElementInRow.length < i + 1) {
          smallestOffestIndex = i;
          lastElementInRow.add(const SliverGridGeometry(
            scrollOffset: 0.0,
            crossAxisOffset: 0.0,
            mainAxisExtent: 0.0,
            crossAxisExtent: 0.0,
          ));
          break;
        }
        double offset = lastElementInRow[i].scrollOffset +
            lastElementInRow[i].mainAxisExtent;
        if (offset < smallestOffest) {
          smallestOffestIndex = i;
          smallestOffest = offset;
        }
      }
      return smallestOffestIndex;
    }

    for (RawImage image in images) {
      int rowIndex = getShortestRow();
      double scrollOffset = lastElementInRow[rowIndex].scrollOffset +
          lastElementInRow[rowIndex].mainAxisExtent;
      double crossAxisOffset = rowHeight * rowIndex;
      double mainAxisExtent = _getScaledImageWidth(image, rowHeight);
      double crossAxisExtent = rowHeight;
      SliverGridGeometry gridGeometry = new SliverGridGeometry(
        scrollOffset: scrollOffset,
        crossAxisOffset: crossAxisOffset,
        mainAxisExtent: mainAxisExtent,
        crossAxisExtent: crossAxisExtent,
      );
      lastElementInRow[rowIndex] = gridGeometry;
      sliverGridGeometryList.add(gridGeometry);
    }
    return sliverGridGeometryList;
  }

  /// Gets the scaled width of the image given the height.
  /// This will maintain the aspect-ratio of the image as well.
  double _getScaledImageWidth(RawImage image, double height) =>
      image.width * height / image.height;
}

class _ImageGridLayout extends SliverGridLayout {
  final List<SliverGridGeometry> sliverGridGeometryList;
  final int rowCount;

  const _ImageGridLayout({
    this.sliverGridGeometryList,
    this.rowCount,
  });

  /// The minimum child index that is visible at (or after) this scroll offset.
  @override
  int getMinChildIndexForScrollOffset(double scrollOffset) {
    int index = 0;
    for (int i = 0; i < sliverGridGeometryList.length; i++) {
      if (sliverGridGeometryList[i].scrollOffset +
              sliverGridGeometryList[i].mainAxisExtent >=
          scrollOffset) {
        index = i;
        break;
      }
    }
    return index;
  }

  /// The maximum child index that is visible at (or before) this scroll offset.
  @override
  int getMaxChildIndexForScrollOffset(double scrollOffset) {
    int index = sliverGridGeometryList.length - 1;
    for (int i = 0; i < sliverGridGeometryList.length; i++) {
      if (sliverGridGeometryList[i].scrollOffset > scrollOffset) {
        index = math.max(0, i - 1);
        break;
      }
    }
    return index;
  }

  @override
  SliverGridGeometry getGeometryForChildIndex(int index) {
    return sliverGridGeometryList[index];
  }

  @override
  double computeMaxScrollOffset(int childCount) {
    double maxScrollOffset = double.negativeInfinity;

    /// Get the max of the last few elements based on rowCount
    for (int i = childCount - 1; i >= 0 && i > i - rowCount; i--) {
      double offset = sliverGridGeometryList[i].scrollOffset +
          sliverGridGeometryList[i].mainAxisExtent;
      if (offset > maxScrollOffset) {
        maxScrollOffset = offset;
      }
    }

    return maxScrollOffset;
  }
}
