// 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/croupier.dart' as logic_croupier;
import '../logic/croupier_settings.dart' show CroupierSettings, RandomSettings;

import 'package:sky/widgets.dart';

typedef void NoArgCb();
typedef void OneStringCb(String data);

enum DialogType { Text, ColorPicker, ImagePicker }

const String nameKey = "name";
const String colorKey = "color";
const String avatarKey = "avatar";

Map<String, GlobalKey> globalKeys = {
  nameKey: new GlobalKey(),
  colorKey: new GlobalKey(),
  avatarKey: new GlobalKey()
};

Map<String, DialogType> dialogTypes = {
  nameKey: DialogType.Text,
  colorKey: DialogType.ColorPicker,
  avatarKey: DialogType.ImagePicker
};

class CroupierSettingsComponent extends StatefulComponent {
  final NavigatorState navigator;
  final logic_croupier.Croupier croupier;
  final NoArgCb backCb;

  CroupierSettingsComponent(this.navigator, this.croupier, this.backCb);

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

class CroupierSettingsComponentState extends State<CroupierSettingsComponent> {
  Map<String, String> _tempData = new Map<String, String>();

  void initState() {
    super.initState();

    _initializeTemp();
  }

  void _initializeTemp() {
    _tempData[nameKey] = config.croupier.settings.name;
    _tempData[colorKey] = "${config.croupier.settings.color}";
    _tempData[avatarKey] = config.croupier.settings.avatar;
  }

  Widget _makeColoredRectangle(int colorInfo, String text, NoArgCb cb) {
    return new Container(
        decoration: new BoxDecoration(backgroundColor: new Color(colorInfo)),
        child: new FlatButton(
            child: new Text(""), enabled: cb != null, onPressed: cb));
  }

  Widget _makeImageButton(String url, NoArgCb cb) {
    return new FlatButton(
        child: new NetworkImage(src: url), enabled: cb != null, onPressed: cb);
  }

  Widget build(BuildContext context) {
    List<Widget> w = new List<Widget>();
    w.add(_makeButtonRow(nameKey, new Text(config.croupier.settings.name)));
    w.add(_makeButtonRow(colorKey,
        _makeColoredRectangle(config.croupier.settings.color, "", null)));
    w.add(_makeButtonRow(
        avatarKey, new NetworkImage(src: config.croupier.settings.avatar)));

    w.add(new FlatButton(child: new Text("Return"), onPressed: config.backCb));
    return new Column(w);
  }

  Widget _makeButtonRow(String type, Widget child) {
    String capType = _capitalize(type);
    return new FlatButton(
        onPressed: () => _handlePressed(type),
        child: new Row([
          new Flexible(
              flex: 1,
              child: new Text(capType, style: Theme.of(context).text.subhead)),
          new Flexible(flex: 3, child: child)
        ], justifyContent: FlexJustifyContent.start));
  }

  void _handlePressed(String type) {
    var capType = _capitalize(type);
    showDialog(config.navigator, (NavigatorState navigator) {
      switch (dialogTypes[type]) {
        case DialogType.Text:
          return new Dialog(
              title: new Text(capType),
              content: new Input(
                  key: globalKeys[type],
                  placeholder: capType,
                  initialValue: config.croupier.settings.getStringValue(type),
                  keyboardType: KeyboardType.TEXT,
                  onChanged: _makeHandleChanged(type)), onDismiss: () {
            navigator.pop();
          }, actions: [
            new FlatButton(child: new Text('CANCEL'), onPressed: () {
              navigator.pop();
            }),
            new FlatButton(child: new Text('SAVE'), onPressed: () {
              navigator.pop(_tempData[type]);
            }),
          ]);
        case DialogType.ColorPicker:
          List<Widget> flexColors = new List<Widget>();
          List<int> colors = <int>[
            0xcfefefef,
            0xcfff3333,
            0xcf33ff33,
            0xcf3333ff,
            0xcf101010,
            0xcf33ffff,
            0xcfff33ff,
            0xcfffff33,
          ];
          for (int i = 0; i < colors.length; i++) {
            int c = colors[i];
            flexColors.add(_makeColoredRectangle(c, "", () {
              // TODO(alexfandrianto): Remove this hack-y subtraction once the
              // Dart + Android issue with int.parse is fixed.
              navigator.pop("${c - 0xcf000000}");
            }));
          }

          return new Dialog(
              title: new Text(capType),
              content: new Grid(flexColors, maxChildExtent: 75.0),
              onDismiss: () {
            navigator.pop();
          }, actions: [
            new FlatButton(child: new Text('CANCEL'), onPressed: () {
              navigator.pop();
            })
          ]);
        case DialogType.ImagePicker:
          List<Widget> flexAvatars = new List<Widget>();
          for (int i = 0; i < RandomSettings.avatars.length; i++) {
            String avatar = RandomSettings.avatars[i];
            flexAvatars.add(_makeImageButton(avatar, () {
              navigator.pop(avatar);
            }));
          }

          return new Dialog(
              title: new Text(capType),
              content: new Grid(flexAvatars, maxChildExtent: 75.0),
              onDismiss: () {
            navigator.pop();
          }, actions: [
            new FlatButton(child: new Text('CANCEL'), onPressed: () {
              navigator.pop();
            })
          ]);
        default:
          assert(false);
          return null;
      }
    }).then((String data) => _persist(type, data));
  }

  void _persist(String type, String data) {
    if (data == null) {
      return;
    }
    setState(() {
      config.croupier.settings.setStringValue(type, data);
      config.croupier.settings_manager.save(config.croupier.settings.userID,
          config.croupier.settings.toJSONString());
    });
  }

  String _capitalize(String s) => s[0].toUpperCase() + s.substring(1);

  OneStringCb _makeHandleChanged(String type) {
    return (String data) {
      setState(() {
        print("Updating ${type} with ${data}");
        _tempData[type] = data;
      });
    };
  }
}
