// 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 'dart:sky' as sky;

import 'package:sky/base/lerp.dart';
import 'package:sky/rendering.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets.dart';

class CardModel {
  CardModel(this.value, this.height, this.color);
  int value;
  double height;
  Color color;
  String get label => "Card $value";
  Key get key => new Key.fromObjectIdentity(this);
}

enum MarkerType { topLeft, bottomRight, touch }

class Marker extends Component {
  Marker({
    this.type: MarkerType.touch,
    this.position,
    this.size: 40.0,
    Key key }) : super(key: key);

  final Point position;
  final double size;
  final MarkerType type;

  void paintMarker(sky.Canvas canvas, _) {
    Paint paint = new Paint()..color = const Color(0x8000FF00);
    paint.setStyle(sky.PaintingStyle.fill);
    double r = size / 2.0;
    canvas.drawCircle(new Point(r, r), r, paint);

    paint.color = const Color(0xFFFFFFFF);
    paint.setStyle(sky.PaintingStyle.stroke);
    paint.strokeWidth = 1.0;
    if (type == MarkerType.topLeft) {
      canvas.drawLine(new Point(r, r), new Point(r + r - 1.0, r), paint);
      canvas.drawLine(new Point(r, r), new Point(r, r + r - 1.0), paint);
    }
    if (type == MarkerType.bottomRight) {
      canvas.drawLine(new Point(r, r), new Point(1.0, r), paint);
      canvas.drawLine(new Point(r, r), new Point(r, 1.0), paint);
    }
  }

  Widget build() {
    return new Positioned(
      left: position.x - size / 2.0,
      top: position.y - size / 2.0,
      child: new IgnorePointer(
        child: new Container(
          width: size,
          height: size,
          child: new CustomPaint(callback: paintMarker)
        )
      )
    );
  }
}

class OverlayGeometryApp extends App {

  static const TextStyle cardLabelStyle =
    const TextStyle(color: colors.white, fontSize: 18.0, fontWeight: bold);

  List<CardModel> cardModels;
  BlockViewportLayoutState layoutState = new BlockViewportLayoutState();
  Map<MarkerType, Point> markers = new Map<MarkerType, Point>();
  double markersScrollOffset;
  ScrollListener scrollListener;

  void initState() {
    List<double> cardHeights = <double>[
      48.0, 63.0, 82.0, 146.0, 60.0, 55.0, 84.0, 96.0, 50.0,
      48.0, 63.0, 82.0, 146.0, 60.0, 55.0, 84.0, 96.0, 50.0,
      48.0, 63.0, 82.0, 146.0, 60.0, 55.0, 84.0, 96.0, 50.0
    ];
    cardModels = new List.generate(cardHeights.length, (i) {
      Color color = lerpColor(colors.Red[300], colors.Blue[900], i / cardHeights.length);
      return new CardModel(i, cardHeights[i], color);
    });
    super.initState();
  }

  void handleScroll(Scrollable scrollable) {
    setState(() {
      double dy = markersScrollOffset - scrollable.scrollOffset;
      markersScrollOffset = scrollable.scrollOffset;
      for (MarkerType type in markers.keys) {
        Point oldPosition = markers[type];
        markers[type] = new Point(oldPosition.x, oldPosition.y + dy);
      }
    });
  }

  EventDisposition handlePointerDown(Widget target, sky.PointerEvent event) {
    setState(() {
      markers[MarkerType.touch] = new Point(event.x, event.y);
      markers[MarkerType.topLeft] = target.localToGlobal(new Point(0.0, 0.0));
      Size size = (target.renderObject as RenderBox).size;
      markers[MarkerType.bottomRight] = target.localToGlobal(new Point(size.width, size.height));

      Scrollable scrollable = findScrollableAncestor(target: target);
      markersScrollOffset = scrollable.scrollOffset;
      if (scrollListener == null) {
        scrollListener = () { handleScroll(scrollable); };
        scrollable.addListener(scrollListener);
      }
    });

    return EventDisposition.processed;
  }

  Widget builder(int index) {
    if (index >= cardModels.length)
      return null;
    CardModel cardModel = cardModels[index];
    Widget card = new Card(
      color: cardModel.color,
      child: new Container(
        height: cardModel.height,
        padding: const EdgeDims.all(8.0),
        child: new Center(child: new Text(cardModel.label, style: cardLabelStyle))
      )
    );
    return new Listener(
      key: cardModel.key,
      onPointerDown: (e) { return handlePointerDown(card, e); },
      child: card
    );
  }

  Widget build() {
    Scrollable scrollable = new VariableHeightScrollable(
      builder: builder,
      token: cardModels.length,
      layoutState: layoutState
    );

    Widget cardCollection = new Container(
      padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
      decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatch[50]),
      child: scrollable
    );

    List<Widget> layers = <Widget>[
      new Scaffold(
        toolbar: new ToolBar(center: new Text('Tap a Card')),
        body: cardCollection
      )
    ];
    for (MarkerType type in markers.keys)
      layers.add(new Marker(type: type, position: markers[type]));

    return new IconTheme(
      data: const IconThemeData(color: IconThemeColor.white),
      child: new Theme(
        data: new ThemeData(
          brightness: ThemeBrightness.light,
          primarySwatch: colors.Blue,
          accentColor: colors.RedAccent[200]
        ),
        child: new TaskDescription(label: 'Cards', child: new Stack(layers))
      )
    );
  }
}

void main() {
  runApp(new OverlayGeometryApp());
}