// 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_next.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;
      });
    };
  }
}
