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

import 'calculator_logic.dart';

class Calculator extends StatefulWidget {
  Calculator({Key key}) : super(key: key);

  static const String routeName = '/calculator';

  @override
  _CalculatorState createState() => new _CalculatorState();
}

class _CalculatorState extends State<Calculator> {
  /// As the user taps keys we update the current `_expression` and we also
  /// keep a stack of previous expressions so we can return to earlier states
  /// when the user hits the DEL key.
  final List<CalcExpression> _expressionStack = <CalcExpression>[];
  CalcExpression _expression = new CalcExpression.Empty();

  // Make `expression` the current expression and push the previous current
  // expression onto the stack.
  void pushExpression(CalcExpression expression) {
    _expressionStack.add(_expression);
    _expression = expression;
  }

  /// Pop the top expression off of the stack and make it the current expression.
  void popCalcExpression() {
    if (_expressionStack.length > 0) {
      _expression = _expressionStack.removeLast();
    } else {
      _expression = new CalcExpression.Empty();
    }
  }

  /// Set `resultExpression` to the currrent expression and clear the stack.
  void setResult(CalcExpression resultExpression) {
    _expressionStack.clear();
    _expression = resultExpression;
  }

  void handleNumberTap(int n) {
    final CalcExpression expression = _expression.appendDigit(n);
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handlePointTap() {
    final CalcExpression expression = _expression.appendPoint();
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handlePlusTap() {
    final CalcExpression expression = _expression.appendOperation(Operation.Addition);
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handleMinusTap() {
    final CalcExpression expression = _expression.appendMinus();
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handleMultTap() {
    final CalcExpression expression = _expression.appendOperation(Operation.Multiplication);
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handleDivTap() {
    final CalcExpression expression = _expression.appendOperation(Operation.Division);
    if (expression != null) {
      setState(() {
        pushExpression(expression);
      });
    }
  }

  void handleEqualsTap() {
    final CalcExpression resultExpression = _expression.computeResult();
    if (resultExpression != null) {
      setState(() {
        setResult(resultExpression);
      });
    }
  }

  void handleDelTap() {
    setState(() {
      popCalcExpression();
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Calculator')),
      body: new Column(
        children: <Widget>[
          // Give the key-pad 3/5 of the vertical space and the display 2/5.
          new CalcDisplay(2, _expression.toString()),
          new KeyPad(3, calcState: this)
        ]
      )
    );
  }
}

class CalcDisplay extends StatelessWidget {
  CalcDisplay(this._flex, this._contents);

  final int _flex;
  final String _contents;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
      flex: _flex,
      child: new Center(
        child: new Text(
          _contents,
          style: const TextStyle(color: Colors.black, fontSize: 24.0)
        )
      )
    );
  }
}

class KeyPad extends StatelessWidget {
  KeyPad(this._flex, {this.calcState});

  final int _flex;
  final _CalculatorState calcState;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
      flex: _flex,
      child: new Row(
        children: <Widget>[
          new MainKeyPad(calcState: calcState),
          new OpKeyPad(calcState: calcState),
        ]
      )
    );
  }
}

class MainKeyPad extends StatelessWidget {
  MainKeyPad({this.calcState});

  final _CalculatorState calcState;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
      // We set flex equal to the number of columns so that the main keypad
      // and the op keypad have sizes proportional to their number of
      // columns.
      flex: 3,
      child: new Material(
        elevation: 12,
        color: Colors.grey[800],
        child: new Column(
          children: <Widget>[
            new KeyRow(<Widget>[
              new NumberKey(7, calcState),
              new NumberKey(8, calcState),
              new NumberKey(9, calcState)
            ]),
            new KeyRow(<Widget>[
              new NumberKey(4, calcState),
              new NumberKey(5, calcState),
              new NumberKey(6, calcState)
            ]),
            new KeyRow(<Widget>[
              new NumberKey(1, calcState),
              new NumberKey(2, calcState),
              new NumberKey(3, calcState)
            ]),
            new KeyRow(<Widget>[
              new CalcKey('.', calcState.handlePointTap),
              new NumberKey(0, calcState),
              new CalcKey('=', calcState.handleEqualsTap),
            ])
          ]
        )
      )
    );
  }
}

class OpKeyPad extends StatelessWidget {
  OpKeyPad({this.calcState});

  final _CalculatorState calcState;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
      child: new Material(
        elevation: 24,
        color: Colors.grey[700],
        child: new Column(
          children: <Widget>[
            new CalcKey('\u232B', calcState.handleDelTap),
            new CalcKey('\u00F7', calcState.handleDivTap),
            new CalcKey('\u00D7', calcState.handleMultTap),
            new CalcKey('-', calcState.handleMinusTap),
            new CalcKey('+', calcState.handlePlusTap)
          ]
        )
      )
    );
  }
}

class KeyRow extends StatelessWidget {
  KeyRow(this.keys);

  final List<Widget> keys;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.center, children: this.keys
      )
    );
  }
}

class CalcKey extends StatelessWidget {
  CalcKey(this.text, this.onTap);

  final String text;
  final GestureTapCallback onTap;

  @override
  Widget build(BuildContext context) {
    return new Flexible(
//      child: new Container(
        child: new InkResponse(
          onTap: this.onTap,
          child: new Center(
            child: new Text(
              this.text,
              style: const TextStyle(color: Colors.white, fontSize: 32.0)
            )
          )
        )
//      )
    );
  }
}

class NumberKey extends CalcKey {
  NumberKey(int value, _CalculatorState calcState)
    : super('$value', () {
        calcState.handleNumberTap(value);
      });
}