// Copyright 2015 The Vanadium 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 '../logic/card.dart' as logic_card;

import 'dart:async';

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart' as widgets;
import 'package:flutter/rendering.dart';
import 'package:vector_math/vector_math_64.dart' as vector_math;

enum CardAnimationType { NONE, OLD_TO_NEW, IN_TOP }

enum CardUIType { CARD, ZCARD }

class GlobalCardKey extends widgets.GlobalKey {
  logic_card.Card card;
  CardUIType type;

  GlobalCardKey(this.card, this.type) : super.constructor();

  bool operator ==(Object other) {
    if (other is! GlobalCardKey) {
      return false;
    }
    GlobalCardKey k = other;
    return k.card == card && k.type == type;
  }

  int get hashCode {
    return 17 * card.hashCode + 33 * type.hashCode;
  }
}

class ZCard extends widgets.StatefulComponent {
  final logic_card.Card card;
  final bool faceUp;
  final double width;
  final double height;
  final double rotation;
  final bool animateEntrance;
  final double z;

  // These points are in local coordinates.
  final Point startingPosition;
  final Point endingPosition;

  ZCard(Card dataComponent, this.startingPosition, this.endingPosition)
      : super(key: new GlobalCardKey(dataComponent.card, CardUIType.ZCARD)),
        card = dataComponent.card,
        faceUp = dataComponent.faceUp,
        width = dataComponent.width ?? 40.0,
        height = dataComponent.height ?? 40.0,
        rotation = dataComponent.rotation,
        animateEntrance = dataComponent.animateEntrance,
        z = dataComponent.z;

  _ZCardState createState() => new _ZCardState();
}

class Card extends widgets.StatefulComponent {
  final logic_card.Card card;
  final bool faceUp;
  final double width;
  final double height;
  final double rotation;
  final bool useKey;
  final bool visible;
  final bool animateEntrance;
  final double z;

  Card(logic_card.Card card, this.faceUp,
      {double width,
      double height,
      this.rotation: 0.0,
      bool useKey: false,
      this.visible: true,
      this.animateEntrance: true,
      this.z})
      : card = card,
        width = width ?? 40.0,
        height = height ?? 40.0,
        useKey = useKey,
        super(key: useKey ? new GlobalCardKey(card, CardUIType.CARD) : null);

  // Use this helper to help create a Card clone.
  // Used by the drag and drop layer.
  Card clone({bool visible}) {
    return new Card(this.card, this.faceUp,
        width: width,
        height: height,
        rotation: rotation,
        useKey: false,
        visible: visible ?? this.visible,
        animateEntrance: false,
        z: z);
  }

  // Check if the data between these Cards matches.
  // This isn't == since I don't want to override that and hashCode.
  bool isMatchWith(Card c) {
    return c.card == card && c.faceUp == faceUp && c.width == width &&
      c.height == height && c.rotation == rotation && c.useKey == useKey &&
      c.visible == visible && c.animateEntrance == animateEntrance && c.z == z;
  }

  CardState createState() => new CardState();
}

class CardState extends widgets.State<Card> {
  // TODO(alexfandrianto): This bug is why some cards appear slightly off.
  // https://github.com/flutter/engine/issues/1939
  Point getGlobalPosition() {
    RenderBox box = context.findRenderObject();
    return box.localToGlobal(Point.origin);
  }

  widgets.Widget build(widgets.BuildContext context) {
    widgets.Widget image = new widgets.Opacity(
        opacity: config.visible ? 1.0 : 0.0,
        child: new widgets.Transform(
            child: _imageFromCard(config.card, config.faceUp),
            transform:
                new vector_math.Matrix4.identity().rotateZ(config.rotation),
            alignment: new FractionalOffset(0.5, 0.5)));

    return new widgets.Container(
        width: config.width, height: config.height, child: image);
  }
}

widgets.Widget _imageFromCard(logic_card.Card c, bool faceUp) {
  // TODO(alexfandrianto): Instead of 'default', what if we were told which theme to use?
  String imageName =
      "images/default/${c.deck}/${faceUp ? 'up' : 'down'}/${c.identifier}.png";
  return new widgets.NetworkImage(src: imageName);
}

class _ZCardState extends widgets.State<ZCard> {
  ValuePerformance<Point> _performance;
  List<
      Point> _pointQueue; // at least 1 longer than the current animation index.
  int _animationIndex;
  bool _cardUpdateScheduled = false;

  @override
  void initState() {
    super.initState();
    _initialize();
    scheduleUpdatePosition();
  }

  void _initialize() {
    _pointQueue = new List<Point>();
    _animationIndex = 0;
    if (config.startingPosition != null) {
      _pointQueue.add(config.startingPosition);
    }
    _pointQueue.add(config.endingPosition);
    _performance = new ValuePerformance<Point>(
        variable: new AnimatedValue<Point>(Point.origin, curve: Curves.ease),
        duration: const Duration(milliseconds: 250));
    _performance.addStatusListener((PerformanceStatus status) {
      if (status == PerformanceStatus.completed) {
        _animationIndex++;
        _tryAnimate();
      }
    });
  }

  void scheduleUpdatePosition() {
    if (!_cardUpdateScheduled) {
      _cardUpdateScheduled = true;
      scheduleMicrotask(_updatePosition);
    }
  }

  // These microtasks are being scheduled on every build change.
  // Theoretically, this is too often, but to be safe, it is also good to do it.
  @override
  void didUpdateConfig(ZCard oldConfig) {
    if (config.key != oldConfig.key) {
      _initialize();
    } else {
      // Do we need to animate to a new location? If so, add it to the queue.
      if (config.endingPosition != _pointQueue.last) {
        setState(() {
          _pointQueue.add(config.endingPosition);
          _tryAnimate();
        });
      }
    }
    scheduleUpdatePosition();
  }

  // A callback that sets up the animation from point a to point b.
  void _updatePosition() {
    _cardUpdateScheduled =
        false; // allow the next attempt to schedule _updatePosition to succeed.
    if (!config.animateEntrance || _pointQueue.length == 1) {
      Point endingLocation = config.endingPosition;
      _performance.variable
        ..begin = endingLocation
        ..value = endingLocation
        ..end = endingLocation;
      _performance.progress = 0.0;
      return;
    }

    _tryAnimate();
  }

  bool _needsAnimation() {
    return _animationIndex < _pointQueue.length - 1;
  }

  void _tryAnimate() {
    // Let animations finish... (Is this a good idea?)
    if (!_performance.isAnimating && _needsAnimation()) {
      Point startingLocation = _pointQueue[_animationIndex];
      Point endingLocation = _pointQueue[_animationIndex + 1];
      _performance.variable
        ..begin = startingLocation
        ..value = startingLocation
        ..end = endingLocation;
      _performance.progress = 0.0;
      _performance.play();
    }
  }

  widgets.Widget build(widgets.BuildContext context) {
    widgets.Widget image = new widgets.Transform(
        child: _imageFromCard(config.card, config.faceUp),
        transform: new vector_math.Matrix4.identity().rotateZ(config.rotation),
        alignment: new FractionalOffset(0.5, 0.5));

    // Size the card appropriately.
    widgets.Widget containedCard = new widgets.Container(
        width: config.width, height: config.height, child: image);

    // Set up the slide transition.
    // During animation, we must ignore all events.
    widgets.Widget retWidget = new widgets.SlideTransition(
        performance: _performance.view,
        position: _performance.variable,
        child: containedCard);

    return retWidget;
  }
}
