// 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 stocks;

typedef void ModeUpdater(StockMode mode);

const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200);

class StockHome extends StatefulComponent {
  StockHome(this.navigator, this.stocks, this.symbols, this.stockMode, this.modeUpdater);

  final NavigatorState navigator;
  final Map<String, Stock> stocks;
  final List<String> symbols;
  final StockMode stockMode;
  final ModeUpdater modeUpdater;

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

class StockHomeState extends State<StockHome> {

  bool _isSearching = false;
  String _searchQuery;

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

  void _handleSearchBegin() {
    config.navigator.pushState(this, (_) {
      setState(() {
        _isSearching = false;
        _searchQuery = null;
      });
    });
    setState(() {
      _isSearching = true;
    });
  }

  void _handleSearchEnd() {
    assert(config.navigator.currentRoute is StateRoute);
    assert((config.navigator.currentRoute as StateRoute).owner == this); // TODO(ianh): remove cast once analyzer is cleverer
    config.navigator.pop();
    setState(() {
      _isSearching = false;
      _searchQuery = null;
    });
  }

  void _handleSearchQueryChanged(String query) {
    setState(() {
      _searchQuery = query;
    });
  }

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

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

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

  bool _autorefresh = false;
  void _handleAutorefreshChanged(bool value) {
    setState(() {
      _autorefresh = value;
    });
  }

  void _handleStockModeChange(StockMode value) {
    if (config.modeUpdater != null)
      config.modeUpdater(value);
  }

  void _handleMenuShow() {
    showStockMenu(config.navigator,
      autorefresh: _autorefresh,
      onAutorefreshChanged: _handleAutorefreshChanged
    );
  }

  Drawer buildDrawer() {
    if (_drawerStatus == AnimationStatus.dismissed)
      return null;
    assert(_drawerShowing); // TODO(mpcomplete): this is always true
    return new Drawer(
      level: 3,
      showing: _drawerShowing,
      onDismissed: _handleDrawerDismissed,
      navigator: config.navigator,
      children: [
        new DrawerHeader(child: new Text('Stocks')),
        new DrawerItem(
          icon: 'action/assessment',
          selected: true,
          child: new Text('Stock List')
        ),
        new DrawerItem(
          icon: 'action/account_balance',
          child: new Text('Account Balance')
        ),
        new DrawerItem(
          icon: 'device/dvr',
          onPressed: () { debugDumpApp(); },
          child: new Text('Dump App to Console')
        ),
        new DrawerDivider(),
        new DrawerItem(
          icon: 'action/thumb_up',
          onPressed: () => _handleStockModeChange(StockMode.optimistic),
          child: new Row([
            new Flexible(child: new Text('Optimistic')),
            new Radio(value: StockMode.optimistic, groupValue: config.stockMode, onChanged: _handleStockModeChange)
          ])
        ),
        new DrawerItem(
          icon: 'action/thumb_down',
          onPressed: () => _handleStockModeChange(StockMode.pessimistic),
          child: new Row([
            new Flexible(child: new Text('Pessimistic')),
            new Radio(value: StockMode.pessimistic, groupValue: config.stockMode, onChanged: _handleStockModeChange)
          ])
        ),
        new DrawerDivider(),
        new DrawerItem(
          icon: 'action/settings',
          onPressed: _handleShowSettings,
          child: new Text('Settings')),
        new DrawerItem(
          icon: 'action/help',
          child: new Text('Help & Feedback'))
     ]
    );
  }

  void _handleShowSettings() {
    config.navigator.pop();
    config.navigator.pushNamed('/settings');
  }

  Widget buildToolBar() {
    return new ToolBar(
        left: new IconButton(
          icon: "navigation/menu",
          onPressed: _handleOpenDrawer
        ),
        center: new Text('Stocks'),
        right: [
          new IconButton(
            icon: "action/search",
            onPressed: _handleSearchBegin
          ),
          new IconButton(
            icon: "navigation/more_vert",
            onPressed: _handleMenuShow
          )
        ]
      );
  }

  int selectedTabIndex = 0;

  Iterable<Stock> _getStockList(Iterable<String> symbols) {
    return symbols.map((symbol) => config.stocks[symbol]);
  }

  Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
    if (_searchQuery == null)
      return stocks;
    RegExp regexp = new RegExp(_searchQuery, caseSensitive: false);
    return stocks.where((stock) => stock.symbol.contains(regexp));
  }

  Widget buildStockList(BuildContext context, Iterable<Stock> stocks) {
    return new StockList(
      stocks: stocks.toList(),
      onAction: (Stock stock) {
        setState(() {
          stock.percentChange = 100.0 * (1.0 / stock.lastSale);
          stock.lastSale += 1.0;
        });
      },
      onOpen: (Stock stock) {
        config.navigator.pushNamed('/stock/${stock.symbol}');
      }
    );
  }

  static const List<String> portfolioSymbols = const <String>["AAPL","FIZZ", "FIVE", "FLAT", "ZINC", "ZNGA"];

  Widget buildTabNavigator() {
    return new TabNavigator(
      views: <TabNavigatorView>[
        new TabNavigatorView(
          label: const TabLabel(text: 'MARKET'),
          builder: (BuildContext context) => buildStockList(context, _filterBySearchQuery(_getStockList(config.symbols)).toList())
        ),
        new TabNavigatorView(
          label: const TabLabel(text: 'PORTFOLIO'),
          builder: (BuildContext context) => buildStockList(context, _filterBySearchQuery(_getStockList(portfolioSymbols)).toList())
        )
      ],
      selectedIndex: selectedTabIndex,
      onChanged: (tabIndex) {
        setState(() { selectedTabIndex = tabIndex; } );
      }
    );
  }

  static GlobalKey searchFieldKey = new GlobalKey();

  // TODO(abarth): Should we factor this into a SearchBar in the framework?
  Widget buildSearchBar() {
    return new ToolBar(
      left: new IconButton(
        icon: "navigation/arrow_back",
        color: Theme.of(context).accentColor,
        onPressed: _handleSearchEnd
      ),
      center: new Input(
        key: searchFieldKey,
        placeholder: 'Search stocks',
        onChanged: _handleSearchQueryChanged
      ),
      backgroundColor: Theme.of(context).canvasColor
    );
  }

  void _handleUndo() {
    setState(() {
      _isSnackBarShowing = false;
    });
  }

  GlobalKey snackBarKey = new GlobalKey(label: 'snackbar');
  Widget buildSnackBar() {
    if (_snackBarStatus == AnimationStatus.dismissed)
      return null;
    return new SnackBar(
      showing: _isSnackBarShowing,
      content: new Text("Stock purchased!"),
      actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
      onDismissed: () { setState(() { _snackBarStatus = AnimationStatus.dismissed; }); }
    );
  }

  void _handleStockPurchased() {
    setState(() {
      _isSnackBarShowing = true;
      _snackBarStatus = AnimationStatus.forward;
    });
  }

  Widget buildFloatingActionButton() {
    return new FloatingActionButton(
      child: new Icon(type: 'content/add', size: 24),
      backgroundColor: Colors.redAccent[200],
      onPressed: _handleStockPurchased
    );
  }

  Widget build(BuildContext context) {
    return new Scaffold(
      toolbar: _isSearching ? buildSearchBar() : buildToolBar(),
      body: buildTabNavigator(),
      snackBar: buildSnackBar(),
      floatingActionButton: buildFloatingActionButton(),
      drawer: buildDrawer()
    );
  }
}