package model.component.visual;

import api.IComponent;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import utility.SingleProperty;
import utility.TwoProperty;

import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.List;

/**
 * Component to hold an imagePath.
 *
 * @author Rhondu Smithwick, Melissa Zhang, Bruna Liborio
 */
public class Sprite implements IComponent {

    private static final String DEFAULT_IMAGE_PATH = "resources/testing/RhonduSmithwick.JPG";

    private final SingleProperty<String> imagePathProperty = new SingleProperty<>("ImagePath", DEFAULT_IMAGE_PATH);
    private final TwoProperty<Double, Double> imageSizeProperty = new TwoProperty<>("ImageWidth", 0.0, "ImageHeight", 0.0);
    private final SingleProperty<Integer> zLevelProperty = new SingleProperty<>("zLevel", 0);
    private transient ImageView imageView;

    public Sprite () {
        this(DEFAULT_IMAGE_PATH);
    }

    /**
     * Construct with no animation.
     *
     * @param imagePath starting value
     */
    public Sprite (String imagePath) { // TODO: place default in resource file
        setImagePath(imagePath);
//        Image image = getImage(imagePath);
//        setImageWidth(image.getWidth());
//        setImageHeight(image.getHeight());
        imageView = createImageView(imagePath);
    }

    /**
     * Construct with starting values.
     *
     * @param imagePath   String path to image
     * @param imageWidth  width of image
     * @param imageHeight height of image
     * @param imagePath   String path to spritesheet
     */
    public Sprite (String imagePath, double imageWidth, double imageHeight) {
        this(imagePath);
        setImageWidth(imageWidth);
        setImageHeight(imageHeight);
    }

    @Deprecated
    public Sprite (String imagePath, double imageWidth, double imageHeight, int zLevel) {
        this(imagePath, imageWidth, imageHeight);
        setZLevel(zLevel);
    }

    /**
     * Get the imagePath property.
     *
     * @return impagePath string property
     */
    public SimpleObjectProperty<String> imagePathProperty () {
        return imagePathProperty.property1();
    }

    public String getImagePath () {
        return imagePathProperty().get();
    }

    public void setImagePath (String imagePath) {
        imagePathProperty().set(imagePath);
        this.imageView = this.createImageView(getImagePath());
        setImageHeight(getImageHeight());
        setImageWidth(getImageWidth());
    }

    public SimpleObjectProperty<Double> imageWidthProperty () {
        return imageSizeProperty.property1();
    }

    public double getImageWidth () {
        return this.imageWidthProperty().get();
    }

    public void setImageWidth (double imageWidth) {
        this.imageWidthProperty().set(imageWidth);
        if (imageView != null) {
            imageView.setFitWidth(getImageWidth());
        }
    }

    public SimpleObjectProperty<Double> imageHeightProperty () {
        return imageSizeProperty.property2();
    }

    public double getImageHeight () {
        return this.imageHeightProperty().get();
    }

    public void setImageHeight (double imageHeight) {
        this.imageHeightProperty().set(imageHeight);
        if (imageView != null) {
            imageView.setFitHeight(getImageHeight());
        }
    }

    @Deprecated
    public SimpleObjectProperty<Integer> zLevelProperty () {
        return this.zLevelProperty.property1();
    }

    @Deprecated
    /**
     * Sets the z-layer order.
     *
     * @param z the z-layer order (1=>send to back, 1=>send to front)
     */
    public void setZLevel (int z) {
        zLevelProperty().set(z);
    }

    @Deprecated
    /**
     * Gets the z-layer order.
     *
     * @return the z-layer order (1=>send to back, 1=>send to front)
     */
    public int getZLevel () {
        return zLevelProperty().get();
    }


    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
    }
    
    private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        this.imageView = this.createImageView(getImagePath());
    }

    private ImageView createImageView (String imagePath) {
        Image image = getImage(imagePath);
        ImageView imageView = new ImageView(image);
        imageView.setPreserveRatio(true);
//        imageView.set
        return imageView;
    }

    private Image getImage (String imagePath) {
        File resource = new File(imagePath);
        return new Image(resource.toURI().toString());
    }

    @Override
    public List<SimpleObjectProperty<?>> getProperties () {
        return Arrays.asList(imagePathProperty(), imageWidthProperty(), imageHeightProperty(), zLevelProperty());
    }

    public ImageView getImageView () {
        return imageView;
    }

}

@@ -96,24 +96,109 @@
 ctProperty;%0A
+import javafx.beans.value.ChangeListener;%0Aimport javafx.beans.value.ObservableValue;%0A
 import javaf
@@ -218,16 +218,16 @@
 .Image;%0A
-
 import j
@@ -1102,16 +1102,70 @@
 ageView;
+%0A    private ChangeListener%3CString%3E imagePathListener;
 %0A%0A    pu
@@ -1424,32 +1424,40 @@
 ath(imagePath);%0A
+        
 //        Image 
@@ -1485,16 +1485,24 @@
 ePath);%0A
+        
 //      
@@ -1536,16 +1536,24 @@
 dth());%0A
+        
 //      
@@ -1581,32 +1581,64 @@
 e.getHeight());%0A
+        addImagePathListener();%0A
         imageVie
@@ -1668,32 +1668,496 @@
 gePath);%0A    %7D%0A%0A
+    private void addImagePathListener () %7B%0A        imagePathListener = (new ChangeListener%3CString%3E() %7B%0A            public void changed (ObservableValue%3C? extends String%3E observable,%0A                                 String oldValue,%0A                                 String newValue) %7B%0A                System.out.println(newValue);%0A                setImagePath(newValue);%0A%0A            %7D%0A        %7D);%0A        imagePathProperty().addListener(imagePathListener);%0A    %7D%0A%0A
     /**%0A     * C
@@ -4771,32 +4771,95 @@
 s IOException %7B%0A
+        imagePathProperty().removeListener(imagePathListener);%0A
         out.defa
@@ -4882,20 +4882,16 @@
 ;%0A    %7D%0A
-    
 %0A    pri
@@ -5277,16 +5277,24 @@
 (true);%0A
+        
 //      

update sprite to change image path when property value changes