// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client;

import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;
import com.google.gwt.user.client.WindowScrollListener;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;

import java.util.HashMap;
import java.util.Map;

/**
 * Popup that shows a status message while an asynchronous request is
 * happening.
 *
 */
public class RpcStatusPopup extends DecoratedPopupPanel implements RpcListener {
  // Map from method names to messages
  private static final Map<String, String> statusMessages = initMessages();

  // Label that shows the message for the current RPC
  private final Label label = new Label();

  // Number of active RPCs. The popup is shown iff this is positive.
  private int activeRPCs = 0;

  /**
   * Initializes the LoadingPopup.
   */
  public RpcStatusPopup() {
    super(/* autoHide = */ false);
    setStyleName("ode-RpcStatusMessage");
    setWidget(label);

    // Re-center the loading message when the window is resized.
    // TODO(halabelson): Replace the deprecated methods
    Window.addWindowResizeListener(new WindowResizeListener() {
      @Override
      public void onWindowResized(int width, int height) {
        positionPopup(getOffsetWidth());
      }
    });

    // Reposition the message to the top of the screen when the
    // window is scrolled
    // TODO(halabelson): get rid of the flashing on vertical scrolling
    Window.addWindowScrollListener(new WindowScrollListener() {
      @Override
      public void onWindowScrolled(int scrollLeft, int scrollTop) {
        positionPopup(getOffsetWidth());
      }
    });

    // Position the popup before showing it to prevent flashing.
    setPopupPositionAndShow(new PopupPanel.PositionCallback() {
      @Override
      public void setPosition(int offsetWidth, int offsetHeight) {
        positionPopup(offsetWidth);
      }
    });
  }

  /**
   * Register a service proxy with the loading popup. The loading popup will
   * listen to the RPCs on the service and show/hide itself automatically.
   *
   * @param service the service to monitor
   */
  public void register(ExtendedServiceProxy<?> service) {
    service.addRpcListener(this);
  }

  /**
   * Unregister a service proxy with the loading popup.
   *
   * @param service the service to monitor
   */
  public void unregister(ExtendedServiceProxy<?> service) {
    service.removeRpcListener(this);
  }

  // RpcListener implementation

  @Override
  public void onStart(String method, Object... params) {
    // TODO(user): This is very primitive in the case of multiple RPCs. The
    // message of the RPC started last succeeds. Its message will stay active
    // until all RPCs have finished or a new RPC starts.
    String message = statusMessages.get(method);
    label.setText(message != null ? message : MESSAGES.defaultRpcMessage());

    // Clear error display
    ErrorReporter.hide();

    countRPCs(+1);
  }

  @Override
  public void onFailure(String method, Throwable caught) {
    countRPCs(-1);
  }

  @Override
  public void onSuccess(String method, Object result) {
    countRPCs(-1);
  }

  private void countRPCs(int i) {
    activeRPCs += i;
    if (activeRPCs > 0) {
      show();
    } else {
      hide();
    }
  }

  private void positionPopup(int offsetWidth) {
    // make sure the popup is on-screen
    // if the top of the window is scrolled off the screen
    setPopupPosition(
        (Window.getClientWidth() - offsetWidth) >> 1,
        Window.getScrollTop());
  }

  private static Map<String, String> initMessages() {
    Map<String, String> msgs = new HashMap<String, String>();

    // RPC methods that show a "Saving..." message
    String saving = MESSAGES.savingRpcMessage();
    msgs.put("newProject", saving);
    msgs.put("save", saving);
    msgs.put("storeProjectSettings", saving);
    msgs.put("storeUserSettings", saving);

    // RPC methods that show a "Copying..." message
    msgs.put("copyProject", MESSAGES.copyingRpcMessage());

    // RPC methods that show a "Deleting..." message
    String deleting = MESSAGES.deletingRpcMessage();
    msgs.put("deleteFile", deleting);
    msgs.put("deleteFiles", deleting);
    msgs.put("deleteProject", deleting);

    // RPC methods that show a "Packaging..." message
    msgs.put("build", MESSAGES.packagingRpcMessage());

    // All other RPC methods will show the default "Loading..." message.

    return msgs;
  }
}