package gwt.material.design.addins.client.cropper;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerRegistration;
import gwt.material.design.addins.client.MaterialAddins;
import gwt.material.design.addins.client.cropper.constants.Shape;
import gwt.material.design.addins.client.cropper.constants.Type;
import gwt.material.design.addins.client.cropper.events.CropEvent;
import gwt.material.design.addins.client.cropper.events.HasCropEvents;
import gwt.material.design.addins.client.cropper.js.JsCropper;
import gwt.material.design.addins.client.cropper.js.JsCropperDimension;
import gwt.material.design.addins.client.cropper.js.JsCropperOptions;
import gwt.material.design.client.MaterialDesignBase;
import gwt.material.design.client.ui.MaterialImage;
import gwt.material.design.jquery.client.api.Functions;

import static gwt.material.design.addins.client.cropper.js.JsCropper.$;

//@formatter:off
/**
 * A simple Image Cropping addin component.
 * <h3>XML Namespace Declaration</h3>
 * <pre>
 * {@code xmlns:ma='urn:import:gwt.material.design.addins.client'}
 * </pre>
 *
 * <h3>UiBinder Usage:</h3>
 * <pre>
 * {@code <ma:cropper.MaterialImageCropper ui:field="cropper" url="some.png" />}
 *
 * <h3>Java Usage:</h3>
 * <pre>
 * {@code cropper.addCropHandler(event -> MaterialToast.fireToast(event.getResult()));
 *   cropper.crop();
 * }
 * </pre>
 *
 * @author kevzlou7979
 */
//@formatter:on
public class MaterialImageCropper extends MaterialImage implements HasCropEvents {

    static {
        if (MaterialAddins.isDebug()) {
            MaterialDesignBase.injectCss(MaterialImageCropperDebugClientBundle.INSTANCE.imageCropperDebugCss());
            MaterialDesignBase.injectDebugJs(MaterialImageCropperDebugClientBundle.INSTANCE.imageCropperDebugJs());
        } else {
            MaterialDesignBase.injectCss(MaterialImageCropperClientBundle.INSTANCE.imageCropperCss());
            MaterialDesignBase.injectJs(MaterialImageCropperClientBundle.INSTANCE.imageCropperJs());
        }
    }

    private JsCropperOptions options;
    private JsCropper cropper;

    @Override
    protected void initialize() {
        if (options == null) {
            options = getDefaultOptions();
        }

        cropper = $(getElement()).croppie(options);
    }

    /**
     * Get the options of the cropper
     * Defaults to {@link #getDefaultOptions}
     * @return
     */
    public JsCropperOptions getOptions() {
        return options;
    }

    /**
     * Set the options of the cropper
     * See {@link JsCropperOptions} for more details.
     */
    public void setOptions(JsCropperOptions options) {
        this.options = options;

        reinitialize();
    }

    @Override
    public void reinitialize() {
        destroy();
        initialize();
    }

    /**
     * Get the default option for the Cropper
     */
    protected JsCropperOptions getDefaultOptions() {
        JsCropperOptions options = new JsCropperOptions();

        JsCropperDimension viewPort = new JsCropperDimension();
        viewPort.height = 100;
        viewPort.width = 100;
        viewPort.type = Shape.SQUARE.getName();

        JsCropperDimension boundary = new JsCropperDimension();
        boundary.height = 200;
        boundary.width = 200;
        boundary.type = Shape.SQUARE.getName();

        options.viewport = viewPort;
        options.boundary = boundary;
        options.enableZoom = true;
        options.enableOrientation = true;
        options.mouseWheelZoom = true;
        options.showZoomer = true;
        return options;
    }

    /**
     * Cropped the image with {@link Type#BASE64} as the default result type.
     */
    public void crop() {
        crop(Type.BASE64);
    }

    /**
     * Cropped the image with give result type.
     * Make sure you are registering the cropevent which returns
     * the Result Cropped Data.
     */
    public void crop(Type type) {
        cropper.croppie("result", type.getName()).then((param1, param2) -> {
            String result = param1.toString();
            CropEvent.fire(this, result);
            return true;
        });
    }

    /**
     * Cropped the image with given URL and result type
     */
    public void crop(String url, Type type) {
        setUrl(url);
        reinitialize();
        bind(url, () -> crop(type));
    }

    /**
     * Bind an image the cropper. Returns a promise to be resolved when the image has been loaded and the cropper has been initialized.
     * @param url - URL to Image
     * @param callback - Callback when the Promise has been resolved.
     */
    public void bind(String url, Functions.Func callback) {
        cropper.croppie("bind", url).then((result, object) -> {
            callback.call();
            return true;
        }).fail((event, error) -> {
            GWT.log("Error on resolving promise " + error.toString());
            return false;
        });
    }

    /**
     * Destroy the cropper instance and remove it from the DOM
     */
    public void destroy() {
        if (cropper != null) {
            cropper.croppie("destroy");
        } else {
            GWT.log("Image Cropper component is not attached");
        }
    }

    /**
     * Rotate the image by a specified degree amount. Only works with enableOrientation option enabled see {@link JsCropperOptions#enableOrientation}.
     * @param degrees - Valid values 90, 180, 270, -90, -180, -270
     */
    public void rotate(int degrees) {
        cropper.croppie("rotate", degrees);
    }

    /**
     * Set the zoom of a Cropper instance. The value passed in is still restricted to the min/max set by Cropper
     * @param value - a floating point to scale the image within the Cropper. Must be between a min and max value set by Cropper.
     */
    public void setZoom(int value) {
        cropper.croppie("setZoom", value);
    }

    @Override
    public HandlerRegistration addCropHandler(CropEvent.CropHandler handler) {
        return addHandler(handler, CropEvent.TYPE);
    }
}

@@ -4780,141 +4780,8 @@
 ue;%0A
-        %7D).fail((event, error) -%3E %7B%0A            GWT.log(%22Error on resolving promise %22 + error.toString());%0A            return false;%0A
     

Remove failing promise on MaterialImageCropper