package IHM;

import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxUI;
import java.awt.*;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;

import Window.Interface;

public class WorkingImage extends JPanel implements Serializable{

    private ImageIcon imageIcon;
    private ArrayList<ImageIcon> images = new ArrayList<>();
    private HashMap<ImageIcon, ArrayList<ImageIcon>> historic_ = new HashMap<>();
    private HashMap<ImageIcon, String> names = new HashMap<>();
    private static WorkingImage instance;
    private double scale;

    public static WorkingImage getInstance() {
        if (instance == null)
            instance = new WorkingImage(null);
        return instance;
    }

    private WorkingImage(Image img) {
        super();
        setImage(img);
        scale = 1;
    }

    public void paintComponent(Graphics g) {
        if (imageIcon == null)
            return;
        Graphics2D blo = (Graphics2D) g;
        blo.scale(scale, scale);
        blo.drawImage(imageIcon.getImage(), 0, 0, null);
    }

    public BufferedImage getImage() {
        if (imageIcon == null)
            return null;
        Image image = imageIcon.getImage();
        if (image == null)
            return  null;
        if (image instanceof BufferedImage)
            return (BufferedImage) image;
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);

        Graphics2D graphics2D = bufferedImage.createGraphics();
        graphics2D.drawImage(image, 0, 0, null);
        graphics2D.dispose();

        return bufferedImage;
    }

    public void setImage(Image img) {
        if (img == null)
            return;
        ArrayList<ImageIcon> tmp = historic_.get(imageIcon);
        if (tmp == null)
            tmp = new ArrayList<>();
        tmp = new ArrayList<>(tmp.subList(0, tmp.indexOf(imageIcon) + 1));
        String name = names.get(imageIcon);
        int pos = images.indexOf(imageIcon);
        images.remove(imageIcon);
        historic_.remove(imageIcon);
        imageIcon = new ImageIcon(img);
        tmp.add(imageIcon);
        historic_.put(imageIcon, tmp);
        images.add(pos, imageIcon);
        names.put(imageIcon, name);


        Dimension blo = new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight());
        setPreferredSize(blo);
        setMaximumSize(blo);
        setSize(blo);
    }

    public void undo() {
        ArrayList<ImageIcon> historic = historic_.get(imageIcon);
        if (historic != null && historic.size() > 0) {
            int i = historic.indexOf(imageIcon);
            if (i <= 0)
                return;
            ImageIcon pop = historic.get(i - 1);
            historic_.put(pop, historic);
            int pos = images.indexOf(imageIcon);
            images.remove(imageIcon);
            imageIcon = pop;
            images.add(pos, imageIcon);
        }
    }

    public void redo() {
        ArrayList<ImageIcon> historic = historic_.get(imageIcon);
        if (historic != null && historic.size() > 0) {
            int i = historic.indexOf(imageIcon);
            if (i >= historic.size() - 1)
                return;
            ImageIcon pop = historic.get(i + 1);

            historic_.put(pop, historic);
            int pos = images.indexOf(imageIcon);
            images.remove(imageIcon);
            imageIcon = pop;
            images.add(pos, imageIcon);
        }
    }

    public void undoAll() {
        ArrayList<ImageIcon> histo = historic_.get(imageIcon);
        int pos = images.indexOf(imageIcon);
        images.remove(imageIcon);
        imageIcon = histo.get(0);
        images.add(pos, imageIcon);
        historic_.put(imageIcon, histo);

    }

    public void redoAll() {
        ArrayList<ImageIcon> histo = historic_.get(imageIcon);
        int pos = images.indexOf(imageIcon);
        images.remove(imageIcon);
        imageIcon = histo.get(histo.size() - 1);
        images.add(pos, imageIcon);
        historic_.put(imageIcon, histo);
    }

    public void getNextImage() {
        if (images.size() == 0)
            return;
        int i = 0;
        if (images.contains(imageIcon))
            i = images.indexOf(imageIcon) + 1;

        imageIcon = images.get(i % images.size());
    }

    public void changeImage(int i) {
        if (i < 0 || i >= images.size())
            return;
        imageIcon = images.get(i);
    }

    public void addImage(ImageIcon img, String name) {
        images.add(img);
        ArrayList<ImageIcon> tmp = new ArrayList<>();
        tmp.add(img);
        historic_.put(img, tmp);
        names.put(img, name);
    }

    public void rmImage(ImageIcon img) {
        images.remove(img);
        historic_.remove(img);
    }

    public ArrayList<ImageIcon> getImages() {
        return images;
    }

    public static void reset() {
        instance = new WorkingImage(null);
    }

    public String getName(ImageIcon img) {
        return names.get(img);
    }

    public void writeToFile(File out) throws IOException {
        FileOutputStream out1 = new FileOutputStream(out);
        ObjectOutputStream write = new ObjectOutputStream(out1);
        write.writeObject(instance);
    }

    public void readFromFile(File in){
        FileInputStream in1 = null;
        try {
            in1 = new FileInputStream(in);
            ObjectInputStream read = new ObjectInputStream(in1);
            instance = (WorkingImage) read.readObject();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public void zoomIn() {
        scale = scale * 2;
        int w = (int) (imageIcon.getIconWidth() * scale + 1);
        int h = (int) (imageIcon.getIconHeight() * scale + 1);
        Dimension blo = new Dimension(w, h);
        setPreferredSize(blo);
        setMaximumSize(blo);
    }
    public void zoomOut() {
        scale = scale / 2;
        int w = (int) (imageIcon.getIconWidth() * scale + 1);
        int h = (int) (imageIcon.getIconHeight() * scale + 1);
        Dimension blo = new Dimension(w, h);
        setPreferredSize(blo);
        setMaximumSize(blo);
    }
}
