// 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 'package:flutter/material.dart';
import 'package:logging/logging.dart';

import '../stores/store.dart';
import '../styles/common.dart' as style;
import '../utils/image_provider.dart' as image_provider;
import 'askquestion.dart';
import 'questionlist.dart';
import 'slideshow_fullscreen.dart';
import 'syncslides_page.dart';

final GlobalKey _scaffoldKey = new GlobalKey();

final Logger log = new Logger('components/slideshow');

class SlideshowPage extends SyncSlidesPage {
  final String _deckId;

  SlideshowPage(this._deckId);

  @override
  Widget build(BuildContext context, AppState appState, AppActions appActions) {
    if (!appState.decks.containsKey(_deckId)) {
      // TODO(aghassemi): Proper error page with navigation back to main view.
      return new Text('Deck no longer exists.');
    }

    return new Scaffold(
        key: _scaffoldKey,
        body: new Material(
            child:
                new SlideShow(appActions, appState, appState.decks[_deckId])));
  }
}

class SlideShow extends StatelessWidget {
  AppActions _appActions;
  AppState _appState;
  DeckState _deckState;
  int _currSlideNum;

  SlideShow(this._appActions, this._appState, this._deckState);

  @override
  Widget build(BuildContext context) {
    if (_deckState.slides.length == 0) {
      // TODO(aghassemi): Proper error page with navigation back to main view.
      return new Text('No slide to show.');
    }

    if (_deckState.presentation != null &&
        _deckState.presentation.isFollowingPresentation) {
      _currSlideNum = _deckState.presentation.currSlideNum;
    } else {
      _currSlideNum = _deckState.currSlideNum;
    }

    if (_currSlideNum >= _deckState.slides.length) {
      // TODO(aghassemi): Can this ever happen?
      //  -What if slide number set by another peer is synced before the actual slides?
      //  -What if we have navigated to a particular slide on our own and peer deletes that slide?
      // I think without careful batching and consuming watch events as batches, this could happen
      // maybe for a split second until rest of data syncs up.
      // UI needs to be bullet-roof, a flicker in the UI is better than an exception and crash.
      log.shout(
          'Current slide number $_currSlideNum is greater than the number of slides ${_deckState.slides.length}.');

      // TODO(aghassemi): Proper error page with navigation back to main view.
      return new Text('Slide does not exist.');
    }

    if (MediaQuery.of(context).orientation == Orientation.landscape) {
      return _buildLandscapeLayout(context);
    } else {
      return _buildPortraitLayout(context);
    }
  }

  Widget _buildPortraitLayout(BuildContext context) {
    var image = new Flexible(child: _buildImage(context), flex: 5);
    var actions = new Flexible(child: _buildActions(context), flex: 0);
    var notes = new Flexible(child: _buildNotes(), flex: 3);
    var nav =
        new Flexible(child: new Row(children: _buildThumbnailNavs()), flex: 3);

    var items = [image, actions, notes, nav];

    var footer = _buildFooter();
    if (footer != null) {
      items.add(footer);
    }

    var layout = new Column(
        children: items, crossAxisAlignment: CrossAxisAlignment.stretch);

    return layout;
  }

  Widget _buildLandscapeLayout(BuildContext context) {
    var notes = new Flexible(child: _buildNotes(), flex: 5);
    var nav = new Flexible(
        child: new Column(children: _buildThumbnailNavs()), flex: 8);

    var image = new Flexible(child: _buildImage(context), flex: 11);
    var actions = new Flexible(child: _buildActions(context), flex: 0);

    var notesAndNavColumn = new Flexible(
        child: new Column(
            children: [notes, nav],
            crossAxisAlignment: CrossAxisAlignment.stretch),
        flex: 4);
    var imageAndActionsColumn = new Flexible(
        child: new Column(
            children: [image, actions],
            crossAxisAlignment: CrossAxisAlignment.stretch),
        flex: 16);

    var layout = new Row(
        children: [notesAndNavColumn, imageAndActionsColumn],
        crossAxisAlignment: CrossAxisAlignment.stretch);

    var footer = _buildFooter();
    if (footer != null) {
      layout = new Column(
          children: [new Flexible(child: layout, flex: 8), footer],
          crossAxisAlignment: CrossAxisAlignment.stretch);
    }

    return layout;
  }

  List<Widget> _buildThumbnailNavs() {
    return <Widget>[
      _buildThumbnailNav(_currSlideNum - 1, 'Previous'),
      _buildThumbnailNav(_currSlideNum + 1, 'Next')
    ];
  }

  Widget _buildImage(BuildContext context) {
    var provider = image_provider.getSlideImage(
        _deckState.deck.key, _deckState.slides[_currSlideNum]);

    var image = new AsyncImage(provider: provider, fit: ImageFit.scaleDown);

    // If not driving the presentation, tapping the image navigates to fullscreen mode.
    if (_deckState.presentation == null ||
        !_deckState.presentation.isDriving(_appState.user)) {
      image = new InkWell(
          child: image,
          onTap: () {
            Navigator.push(
                context,
                new MaterialPageRoute(builder: (context) =>
                    new SlideshowFullscreenPage(_deckState.deck.key)));
          });
    }

    var counter = _buildBubbleOverlay(
        '${_currSlideNum + 1} of ${_deckState.slides.length}', 0.5, 0.98);
    image = new Stack(children: [image, counter]);

    return new ClipRect(child: image);
  }

  Widget _buildNotes() {
    var notes =
        new Text('Notes (only you see these)', style: style.Text.subtitleStyle);
    var container = new Container(
        child: notes,
        padding: style.Spacing.normalPadding,
        decoration: new BoxDecoration(border: new Border(
            bottom: new BorderSide(color: style.theme.dividerColor))));
    return container;
  }

  Widget _buildThumbnailNav(int slideNum, String label) {
    var container;

    if (slideNum >= 0 && slideNum < _deckState.slides.length) {
      var thumbnail = new AsyncImage(
          provider: image_provider.getSlideImage(
              _deckState.deck.key, _deckState.slides[slideNum]),
          height: style.Size.thumbnailNavHeight,
          fit: ImageFit.scaleDown);

      container = new InkWell(
          child: thumbnail,
          onTap: () {
            _appActions.setCurrSlideNum(_deckState.deck.key, slideNum);
          });
    } else {
      // Empty grey placeholder.
      container = new Container(
          decoration: new BoxDecoration(backgroundColor: Colors.grey[100]));
    }

    var nextPreviousBubble = _buildBubbleOverlay(label, 0.5, 0.05);
    container = new Stack(children: [container, nextPreviousBubble]);
    container = new ClipRect(child: container);

    return new Flexible(child: container, flex: 1);
  }

  Widget _buildActions(BuildContext context) {
    // It collects a list of action widgets for the action bar and fabs.
    // Left contains items that are in-line on the left side of the UI.
    // Right contains the FABs that hover over the right side of the UI.
    List<Widget> left = [];
    List<Widget> right = [];

    _buildActionsPrev(left, right);
    _buildActionsSlidelist(left, right, context);
    _buildActionsQuestion(left, right, context);
    _buildActionsNext(left, right);
    _buildActionsFollowPresentation(left, right);

    return new AppBar(
        leading: new Row(children: _buildActionsAddMargin(left)),
        actions: right);
  }

  void _buildActionsPrev(List<Widget> left, List<Widget> right) {
    if (_currSlideNum == 0) {
      return;
    }
    var prev = new InkWell(
        child: new Icon(icon: Icons.arrow_back),
        onTap: () {
          _appActions.setCurrSlideNum(_deckState.deck.key, _currSlideNum - 1);
        });
    left.add(prev);
  }

  void _buildActionsSlidelist(
      List<Widget> left, List<Widget> right, BuildContext context) {
    var slideList = new InkWell(
        child: new Icon(icon: Icons.layers),
        onTap: () {
          Navigator.pop(context);
        });
    left.add(slideList);
  }

  void _buildActionsQuestion(
      List<Widget> left, List<Widget> right, BuildContext context) {
    if (_deckState.presentation == null) {
      return;
    }

    // Presentation over is taken to a list of questions view.
    if (_deckState.presentation.isOwner) {
      var numQuestions = new FloatingActionButton(child: new Text(
          _deckState.presentation.questions.length.toString(),
          style: style.theme.primaryTextTheme.title));
      // TODO(aghassemi): Find a better way. Scaling down a FAB and
      // using transform to position it does not seem to be the best approach.
      final Matrix4 moveUp = new Matrix4.identity().translate(-95.0, 25.0);
      final Matrix4 scaleDown = new Matrix4.identity().scale(0.3);
      numQuestions = new Transform(child: numQuestions, transform: moveUp);
      numQuestions = new Transform(child: numQuestions, transform: scaleDown);

      var questions = new InkWell(
          child: new Icon(icon: Icons.help),
          onTap: () {
            Navigator.push(
                context,
                new MaterialPageRoute(builder: (context) =>
                    new QuestionListPage(_deckState.deck.key)));
          });

      left.add(questions);
      left.add(numQuestions);
    } else {
      // Audience is taken to ask a question view.
      var route = new MaterialPageRoute(builder: (context) =>
          new AskQuestionPage(_deckState.deck.key, _currSlideNum));

      var askQuestion = new InkWell(
          child: new Icon(icon: Icons.help),
          onTap: () {
            Navigator.push(context, route);
          });
      left.add(askQuestion);
    }
  }

  final Matrix4 moveUpFabTransform =
      new Matrix4.identity().translate(0.0, -27.5);

  void _buildActionsNext(List<Widget> left, List<Widget> right) {
    if (_currSlideNum >= (_deckState.slides.length - 1)) {
      return;
    }

    var nextOnTap = () {
      _appActions.setCurrSlideNum(_deckState.deck.key, _currSlideNum + 1);
    };

    // If driving the presentation, show a bigger FAB next button on the right side,
    // otherwise a regular next button on the left side.
    if (_deckState.presentation != null &&
        _deckState.presentation.isDriving(_appState.user)) {
      var next = new FloatingActionButton(
          child: new Icon(icon: Icons.arrow_forward), onPressed: nextOnTap);

      var container =
          new Container(child: next, margin: style.Spacing.fabMargin);
      next = new Transform(transform: moveUpFabTransform, child: container);

      right.add(next);
    } else {
      var next = new InkWell(
          child: new Icon(icon: Icons.arrow_forward), onTap: nextOnTap);
      left.add(next);
    }
  }

  void _buildActionsFollowPresentation(List<Widget> left, List<Widget> right) {
    if (_deckState.presentation == null ||
        _deckState.presentation.isFollowingPresentation) {
      return;
    }

    var syncNav = new FloatingActionButton(
        child: new Icon(icon: Icons.sync),
        onPressed: () async {
          _appActions.followPresentation(_deckState.deck.key);
        });

    syncNav =
        new Container(child: syncNav, margin: style.Spacing.actionsMargin);
    syncNav = new Transform(transform: moveUpFabTransform, child: syncNav);

    right.add(syncNav);
  }

  Widget _buildFooter() {
    if (_deckState.presentation == null) {
      return null;
    }

    // Owner and not driving?
    if (_deckState.presentation.isOwner &&
        !_deckState.presentation.isDriving(_appState.user)) {
      SnackBarAction resume = new SnackBarAction(
          label: 'RESUME',
          onPressed: () {
            _appActions.setDriver(_deckState.deck.key, _appState.user);
          });

      return _buildSnackbarFooter('You have handed off control.',
          action: resume);
    }

    // Driving but not the owner?
    if (!_deckState.presentation.isOwner &&
        _deckState.presentation.isDriving(_appState.user)) {
      return _buildSnackbarFooter('You are now driving the presentation.');
    }

    return null;
  }

  List<Widget> _buildActionsAddMargin(List<Widget> actions) {
    return actions
        .map(
            (w) => new Container(child: w, margin: style.Spacing.actionsMargin))
        .toList();
  }

  Widget _buildBubbleOverlay(String text, double xOffset, double yOffset) {
    return new Align(
        child: new Container(
            child: new DefaultTextStyle(
                child: new Text(text), style: Typography.white.body1),
            decoration: new BoxDecoration(
                borderRadius: 50.0, // Make the bubble round.
                backgroundColor:
                    style.Box.bubbleOverlayBackground), // Transparent gray.
            padding: new EdgeInsets.symmetric(horizontal: 5.0, vertical: 2.0)),
        alignment: new FractionalOffset(xOffset, yOffset));
  }

  Widget _buildSnackbarFooter(String lable, {SnackBarAction action}) {
    var text = new Text(lable);
    text = new DefaultTextStyle(style: Typography.white.subhead, child: text);
    List<Widget> children = <Widget>[
      new Flexible(child: new Container(
          margin: style.Spacing.footerVerticalMargin,
          child: new DefaultTextStyle(
              style: Typography.white.subhead, child: text)))
    ];

    if (action != null) {
      children.add(action);
    }

    var clipper = new ClipRect(child: new Material(
        elevation: 6,
        color: style.Box.footerBackground,
        child: new Container(
            margin: style.Spacing.footerHorizontalMargin,
            child: new DefaultTextStyle(
                style: new TextStyle(color: style.theme.accentColor),
                child: new Row(children: children)))));

    return new Flexible(child: clipper, flex: 1);
  }
}
