text: // Copyright (c) 2012, 2015 the Dart project authors.
  // Please see the AUTHORS file for details. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  import 'dart:async';
  import 'dart:html';
  
  import 'package:http/browser_client.dart';
  import 'package:server_code_lab/client/piratesapi.dart';
  import 'package:server_code_lab/common/messages.dart';
  import 'package:server_code_lab/common/utils.dart';
  
  final String treasureKey = 'pirateName';
  
  ButtonElement genButton;
  ButtonElement storeButton;
  ButtonElement fireButton;
  ButtonElement slayButton;
  SpanElement badgeNameElement;
  SelectElement pirateList;
  
  // By default the generated client code uses
  // 'http://localhost:8080/'. Since our server is running on
  // port 8088 we override the default url when instantiating
  // the generated PiratesApi class.
  final String _serverUrl = 'localhost:8088/';
  final BrowserClient _client = new BrowserClient();
  PiratesApi _api;
  PirateShanghaier _shanghaier;
  
  Future main() async {
    // We need to determine if the client is using http or https
    // and use the same protocol for the client stub requests
    // (the protocol includes the ':').
    var protocol = window.location.protocol;
    if (!['http:', 'https:'].contains(protocol)) {
      // Default to http if unknown protocol.
      protocol = 'http:';
    }
    _api = new PiratesApi(_client, rootUrl: '$protocol//$_serverUrl');
    _shanghaier = new PirateShanghaier();
  
    InputElement inputField = querySelector('#inputName');
    inputField.onInput.listen(updateBadge);
    genButton = querySelector('#generateButton');
    genButton.onClick.listen(generateBadge);
    inputField.disabled = false; //enable
    genButton.disabled = false; //enable
    badgeNameElement = querySelector('#badgeName');
    storeButton = querySelector('#storeButton');
    storeButton.onClick.listen(storeBadge);
    pirateList = querySelector('#pirateList');
    pirateList.onClick.listen(selectListener);
    fireButton = querySelector('#fireButton');
    fireButton.onClick.listen(removeBadge);
    slayButton = querySelector('#slayButton');
    slayButton.onClick.listen(removeAllBadges);
    setBadgeName(getBadgeNameFromStorage());
    refreshList();
  
    var buttons = querySelectorAll("button");
    buttons.onClick.listen(addRippleEffect);
  }
  
  Future refreshList() async {
    List<Pirate> pirates = await _api.listPirates();
    pirateList.children.clear();
    pirates.forEach((pirate) {
      var option = new OptionElement(data: pirate.toString());
      pirateList.add(option, 0);
    });
  
    var disabled = true;
    if (pirateList.length > 0) {
      disabled = false;
    }
  
    new Future.delayed(new Duration(milliseconds: 300), () {
      slayButton.disabled = disabled;
    });
  }
  
  void updateBadge(Event e) {
    String inputName = (e.target as InputElement).value.trim();
    var pirate = _shanghaier.shanghaiAPirate(name: inputName);
    setBadgeName(pirate);
    if (inputName.trim().isEmpty) {
      genButton
        ..disabled = false
        ..text = 'Aye! Gimme a name!';
      storeButton..disabled = true;
    } else {
      genButton
        ..disabled = true
        ..text = 'Arrr! Write yer name!';
      storeButton..disabled = false;
    }
  }
  
  Future storeBadge(Event e) async {
    var pirateName = badgeNameElement.text;
    if (pirateName == null || pirateName.isEmpty) return null;
    var pirate = new Pirate.fromString(pirateName);
    try {
      await _api.hirePirate(pirate);
    } catch (error) {
      window.alert(error.message);
    }
    new Future.delayed(new Duration(milliseconds: 300), () {
      storeButton
        ..disabled = true
        ..text = 'Pirate hired!';
    });
    refreshList();
  }
  
  Future selectListener(Event e) async {
    fireButton.disabled = false;
  }
  
  Future removeBadge(Event e) async {
    var idx = pirateList.selectedIndex;
    if (idx < 0 || idx >= pirateList.options.length) return null;
    var option = pirateList.options.elementAt(idx);
    var pirate = new Pirate.fromString(option.label);
    try {
      await _api.firePirate(pirate.name, pirate.appellation);
    } catch (error) {
      window.alert(error.message);
    }
    new Future.delayed(new Duration(milliseconds: 300), () {
      fireButton.disabled = true;
    });
    refreshList();
  }
  
  Future removeAllBadges(Event e) async {
    for (var option in pirateList.options) {
      var pirate = new Pirate.fromString(option.label);
      try {
        await _api.firePirate(pirate.name, pirate.appellation);
      } catch (error) {
        // ignoring errors.
      }
    }
    new Future.delayed(new Duration(milliseconds: 300), () {
      fireButton.disabled = true;
      slayButton.disabled = true;
    });
    refreshList();
  }
  
  void generateBadge(Event e) {
    var pirate = _shanghaier.shanghaiAPirate();
    setBadgeName(pirate);
  }
  
  void setBadgeName(Pirate pirate) {
    if (pirate == null || pirate.toString().isEmpty) {
      badgeNameElement.text = '';
      storeButton.disabled = true;
      return;
    }
    badgeNameElement.text = pirate.toString();
    window.localStorage[treasureKey] = pirate.toString();
    storeButton
      ..disabled = false
      ..text = 'Hire pirate!';
  }
  
  Pirate getBadgeNameFromStorage() {
    String storedName = window.localStorage[treasureKey];
    if (storedName != null && storedName.contains(' the ')) {
      return new Pirate.fromString(storedName);
    } else {
      return null;
    }
  }
  
  void addRippleEffect(MouseEvent e) {
    var button = e.target as ButtonElement;
    var ripple = button.querySelector(".ripple");
  
    // we need to delete existing ripple element
    if (ripple != null) {
      ripple.remove();
    }
  
    var x = e.client.x - button.getBoundingClientRect().left;
    var y = e.client.y - button.getBoundingClientRect().top;
  
    ripple = new SpanElement()
      ..classes.add("ripple")
      ..style.left = "${x}px"
      ..style.top = "${y}px"
      ..classes.add("show");
  
    button.append(ripple);
  }
  