// 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.

part of fitness;

class FitnessItemList extends Component {
  FitnessItemList({ Key key, this.items, this.onDismissed }) : super(key: key) {
    assert(items != null);
    assert(onDismissed != null);
  }

  final List<FitnessItem> items;
  final FitnessItemHandler onDismissed;

  Widget build() {
    return new Material(
      type: MaterialType.canvas,
      child: new ScrollableList<FitnessItem>(
        padding: const EdgeDims.all(4.0),
        items: items,
        itemExtent: kFitnessItemHeight,
        itemBuilder: (item) => item.toRow(onDismissed: onDismissed)
      )
    );
  }
}

class DialogMenuItem extends ButtonBase {
  DialogMenuItem(this.children, { Key key, this.onPressed }) : super(key: key);

  List<Widget> children;
  Function onPressed;

  void syncConstructorArguments(DialogMenuItem source) {
    children = source.children;
    onPressed = source.onPressed;
    super.syncConstructorArguments(source);
  }

  Widget buildContent() {
    return new Listener(
      onGestureTap: (_) {
        if (onPressed != null)
          onPressed();
      },
      child: new Container(
        height: 48.0,
        child: new InkWell(
          child: new Padding(
            padding: const EdgeDims.symmetric(horizontal: 16.0),
            child: new Row(children)
          )
        )
      )
    );
  }
}

class FeedFragment extends StatefulComponent {
  FeedFragment({ this.navigator, this.userData, this.onItemCreated, this.onItemDeleted });

  Navigator navigator;
  UserData userData;
  FitnessItemHandler onItemCreated;
  FitnessItemHandler onItemDeleted;

  FitnessMode _fitnessMode = FitnessMode.feed;

  void initState() {
    // if (debug)
    //   new Timer(new Duration(seconds: 1), dumpState);
    super.initState();
  }

  void syncConstructorArguments(FeedFragment source) {
    navigator = source.navigator;
    userData = source.userData;
    onItemCreated = source.onItemCreated;
    onItemDeleted = source.onItemDeleted;
  }

  AnimationStatus _snackBarStatus = AnimationStatus.dismissed;
  bool _isShowingSnackBar = false;

  EventDisposition _handleFitnessModeChange(FitnessMode value) {
    setState(() {
      _fitnessMode = value;
      _drawerShowing = false;
    });
    return EventDisposition.processed;
  }

  Drawer buildDrawer() {
    if (_drawerStatus == AnimationStatus.dismissed)
      return null;
    return new Drawer(
      showing: _drawerShowing,
      level: 3,
      onDismissed: _handleDrawerDismissed,
      navigator: navigator,
      children: [
        new DrawerHeader(child: new Text('Fitness')),
        new DrawerItem(
          icon: 'action/view_list',
          onPressed: () => _handleFitnessModeChange(FitnessMode.feed),
          selected: _fitnessMode == FitnessMode.feed,
          child: new Text('Feed')),
        new DrawerItem(
          icon: 'action/assessment',
          onPressed: () => _handleFitnessModeChange(FitnessMode.chart),
          selected: _fitnessMode == FitnessMode.chart,
          child: new Text('Chart')),
        new DrawerDivider(),
        new DrawerItem(
          icon: 'action/settings',
          onPressed: _handleShowSettings,
          child: new Text('Settings')),
        new DrawerItem(
          icon: 'action/help',
          child: new Text('Help & Feedback'))
      ]
    );
  }

  bool _drawerShowing = false;
  AnimationStatus _drawerStatus = AnimationStatus.dismissed;

  void _handleOpenDrawer() {
    setState(() {
      _drawerShowing = true;
      _drawerStatus = AnimationStatus.forward;
    });
  }

  void _handleDrawerDismissed() {
    setState(() {
      _drawerStatus = AnimationStatus.dismissed;
    });
  }

  EventDisposition _handleShowSettings() {
    navigator.pop();
    navigator.pushNamed('/settings');
    return EventDisposition.processed;
  }

  // TODO(jackson): We should be localizing
  String get fitnessModeTitle {
    switch(_fitnessMode) {
      case FitnessMode.feed: return "Feed";
      case FitnessMode.chart: return "Chart";
    }
  }

  Widget buildToolBar() {
    return new ToolBar(
      left: new IconButton(
        icon: "navigation/menu",
        onPressed: _handleOpenDrawer),
      center: new Text(fitnessModeTitle)
    );
  }

  FitnessItem _undoItem;

  void _handleItemDismissed(FitnessItem item) {
    onItemDeleted(item);
    setState(() {
      _undoItem = item;
      _isShowingSnackBar = true;
      _snackBarStatus = AnimationStatus.forward;
    });
  }

  Widget buildChart() {
    double startX;
    double endX;
    double startY;
    double endY;
    List<Point> dataSet = new List<Point>();
    for (FitnessItem item in userData.items) {
      if (item is Measurement) {
          double x = item.when.millisecondsSinceEpoch.toDouble();
          double y = item.weight;
          if (startX == null || startX > x)
            startX = x;
          if (endX == null || endX < x)
          endX = x;
          if (startY == null || startY > y)
            startY = y;
          if (endY == null || endY < y)
            endY = y;
          dataSet.add(new Point(x, y));
      }
    }
    if (userData.goalWeight != null && userData.goalWeight > 0.0) {
      startY = math.min(startY, userData.goalWeight);
      endY = math.max(endY, userData.goalWeight);
    }
    playfair.ChartData data = new playfair.ChartData(
      startX: startX,
      startY: startY,
      endX: endX,
      endY: endY,
      dataSet: dataSet,
      numHorizontalGridlines: 5,
      roundToPlaces: 1,
      indicatorLine: userData.goalWeight,
      indicatorText: "GOAL WEIGHT"
    );
    return new playfair.Chart(data: data);
  }

  Widget buildBody() {
    TextStyle style = Theme.of(this).text.title;
    if (userData == null)
      return new Material(type: MaterialType.canvas);
    if (userData.items.length == 0)
      return new Material(
        type: MaterialType.canvas,
        child: new Row(
          [new Text("No data yet.\nAdd some!", style: style)],
          justifyContent: FlexJustifyContent.center
        )
      );
    switch (_fitnessMode) {
      case FitnessMode.feed:
        return new FitnessItemList(
          items: userData.items.reversed.toList(),
          onDismissed: _handleItemDismissed
        );
      case FitnessMode.chart:
        return new Material(
          type: MaterialType.canvas,
          child: new Container(
            padding: const EdgeDims.all(20.0),
            child: buildChart()
          )
        );
    }
  }

  void _handleUndo() {
    onItemCreated(_undoItem);
    setState(() {
      _undoItem = null;
      _isShowingSnackBar = false;
    });
  }

  Anchor _snackBarAnchor = new Anchor();
  Widget buildSnackBar() {
    if (_snackBarStatus == AnimationStatus.dismissed)
      return null;
    return new SnackBar(
      showing: _isShowingSnackBar,
      anchor: _snackBarAnchor,
      content: new Text("Item deleted."),
      actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
      onDismissed: () { setState(() { _snackBarStatus = AnimationStatus.dismissed; }); }
    );
  }

  void _handleActionButtonPressed() {
    showDialog(navigator, (navigator) => new AddItemDialog(navigator)).then((routeName) {
      if (routeName != null)
        navigator.pushNamed(routeName);
    });
  }

  Widget buildFloatingActionButton() {
    switch (_fitnessMode) {
      case FitnessMode.feed:
        return _snackBarAnchor.build(
          new FloatingActionButton(
            child: new Icon(type: 'content/add', size: 24),
            onPressed: _handleActionButtonPressed
          ));
      case FitnessMode.chart:
        return null;
    }
  }

  Widget build() {
    return new Scaffold(
      toolbar: buildToolBar(),
      body: buildBody(),
      snackBar: buildSnackBar(),
      floatingActionButton: buildFloatingActionButton(),
      drawer: buildDrawer()
    );
  }
}

class AddItemDialog extends StatefulComponent {
  AddItemDialog(this.navigator);

  Navigator navigator;

  void syncConstructorArguments(AddItemDialog source) {
    this.navigator = source.navigator;
  }

  // TODO(jackson): Internationalize
  static final Map<String, String> _labels = {
    '/measurements/new': 'Measure',
    '/meals/new': 'Eat',
  };

  String _addItemRoute = _labels.keys.first;

  void _handleAddItemRouteChanged(String routeName) {
    setState(() {
        _addItemRoute = routeName;
    });
  }

  Widget build() {
    List<Widget> menuItems = [];
    for(String routeName in _labels.keys) {
      menuItems.add(new DialogMenuItem([
        new Flexible(child: new Text(_labels[routeName])),
        new Radio(value: routeName, groupValue: _addItemRoute, onChanged: _handleAddItemRouteChanged),
      ], onPressed: () => _handleAddItemRouteChanged(routeName)));
    }
    return new Dialog(
      title: new Text("What are you doing?"),
      content: new Block(menuItems),
      onDismiss: navigator.pop,
      actions: [
        new FlatButton(
          child: new Text('CANCEL'),
          onPressed: navigator.pop
        ),
        new FlatButton(
          child: new Text('ADD'),
          onPressed: () {
            navigator.pop(_addItemRoute);
          }
        ),
      ]
    );
  }
}
