// -*- 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
// TODO(user): reconsider visibilities of the abstract base classes in this package

package com.google.appinventor.client.editor.simple.components;

import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.appinventor.client.output.OdeLog;
import com.google.common.primitives.Ints;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.SimplePanel;

/**
 * Abstract superclass for MockImage and MockImageSprite.
 *
 * @author [email protected] (Liz Looney)
 */
abstract class MockImageBase extends MockVisibleComponent {
  // Property names
  private static final String PROPERTY_NAME_PICTURE = "Picture";
  private static final String PROPERTY_SCALE_PICTURE_TO_FIT = "ScalePictureToFit";
  private static final String PROPERTY_SCALING = "Scaling";

  // Widget for showing the image.
  private final Image image;
  private String picturePropValue;
  private String scalingMode = "0"; // corresponds to Scale proportionally

  MockImageBase(SimpleEditor editor, String type, ImageResource icon) {
    super(editor, type, icon);

    image = new Image();
    image.addErrorHandler(new ErrorHandler() {
      @Override
      public void onError(ErrorEvent event) {
        if (picturePropValue != null && !picturePropValue.isEmpty()) {
          OdeLog.elog("Error occurred while loading image " + picturePropValue);
        }
        refreshForm(true);
      }
    });
    image.addLoadHandler(new LoadHandler() {
      @Override
      public void onLoad(LoadEvent event) {
        refreshForm(true);
        resizeImage();  // resize after the new image occupies the form
      }
    });

    SimplePanel simplePanel = new SimplePanel();
    simplePanel.setStylePrimaryName("ode-SimpleMockComponent");
    simplePanel.addStyleName("imageComponentCenterPanel");
    simplePanel.setWidget(image);
    initComponent(simplePanel);
  }

  /*
   * Sets the image's url to a new value.
   */
  private void setPictureProperty(String text) {
    picturePropValue = text;
    String url = convertImagePropertyValueToUrl(text);
    if (url == null) {
      // text was not recognized as an asset. Just display the icon for this type of component.
      image.setUrl(getIconImage().getUrl());
    } else {
      image.setUrl(url);
    }
  }

  @Override
  public int getPreferredWidth() {
    // The superclass uses getOffsetWidth, which won't work for us.
    // Hide away the current 100% size so we can get at the actual size, otherwise automatic size doesn't work
    String[] style = MockComponentsUtil.clearSizeStyle(image);
    int width = image.getWidth();
    MockComponentsUtil.restoreSizeStyle(image, style);
    return width;
  }

  @Override
  public int getPreferredHeight() {
    // The superclass uses getOffsetHeight, which won't work for us.
    // Hide away the current 100% size so we can get at the actual size, otherwise automatic size doesn't work
    String[] style = MockComponentsUtil.clearSizeStyle(image);
    int height = image.getHeight();
    MockComponentsUtil.restoreSizeStyle(image, style);
    return height;
  }

  /**
   * This resizes the picture according to
   * 1. height and width value of the div tag enclosing the img tag
   * 2. scaling mode. 0 - Scale proportionally, 1 - Scale to fit
   *    which correspond to the choices in ScalingChoicePropertyEditor
   *
   * This should be called whenever a property affecting the size is changed
   */
  private void resizeImage() {
    if (image.getUrl().equals(getIconImage().getUrl())) {
      unclipImage();
      return;
    }

    String width = getElement().getStyle().getWidth();
    String height = getElement().getStyle().getHeight();

    // the situation right after refreshing the page
    if (width.isEmpty() || height.isEmpty()) {
      return;
    }

    int frameWidth = Ints.tryParse(width.substring(0, width.indexOf("px")));
    int frameHeight = Ints.tryParse(height.substring(0, height.indexOf("px")));

    if (scalingMode.equals("0")) {
      float ratio = Math.min(frameWidth / (float) getPreferredWidth(),
          frameHeight / (float) getPreferredHeight());
      int scaledWidth = Double.valueOf(getPreferredWidth() * ratio).intValue();
      int scaledHeight = Double.valueOf(getPreferredHeight() * ratio).intValue();
      image.setSize(scaledWidth + "px", scaledHeight + "px");

    } else if (scalingMode.equals("1")) {
      image.setSize("100%", "100%");

    } else {
      throw new IllegalStateException("Illegal scaling mode: " + scalingMode);
    }
  }

  private void unclipImage() {
    Style style = image.getElement().getStyle();
    style.clearLeft();
    style.clearTop();
    style.clearWidth();
    style.clearHeight();
  }

  // PropertyChangeListener implementation

  @Override
  public void onPropertyChange(String propertyName, String newValue) {
    super.onPropertyChange(propertyName, newValue);

    if (propertyName.equals(PROPERTY_NAME_PICTURE)) {
      setPictureProperty(newValue); // setUrl() triggers onLoad
    } else if (propertyName.equals(PROPERTY_NAME_WIDTH)) {
      resizeImage();
      refreshForm();
    } else if (propertyName.equals(PROPERTY_NAME_HEIGHT)) {
      resizeImage();
      refreshForm();
    } else if (propertyName.equals(PROPERTY_SCALING)) {
      scalingMode = newValue;
      resizeImage();
      refreshForm();
    } else if (propertyName.equals(PROPERTY_SCALE_PICTURE_TO_FIT)) {
      boolean scaleIt = Boolean.parseBoolean(newValue);
      if (scaleIt) {
        scalingMode = "1";
      } else {
        scalingMode = "0";
      }
      resizeImage();
      refreshForm();
    }
  }
}