import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.imageio.ImageIO;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class FileChooserEnBoyOranliSeciliAlan {

	public static JPanel anaPanel = new JPanel();

	public static double oran;
	public static double oranX;
	public static double oranY;

	public static JTextField fieldX;
	public static JTextField fieldY;
	
    private static BufferedImage resim;
    private static Rectangle seciliAlan;
    private static Point seciliAlanBaslangic;

    // Bu site Nic Jackson anısına ücretsiz fotoğraf sunmaktadır.
	// https://littlevisuals.co/  
	
    public FileChooserEnBoyOranliSeciliAlan() throws IOException {

    	resim = ImageIO.read(new File("src/images/geyik.jpg"));
    
    	seciliAlan = new Rectangle(0, 0, 160, 90);  // 16:9 oranli ilk alan
        seciliAlanBaslangic = new Point(0, 0);
        
        JFrame frame = new JFrame("Belirtilen En-Boy Oran ile Seçili Resim Alanını Kaydet | Java Blackboard [144]");
        frame.setLayout(null);
        
        anaPanel.setLayout(null);
        anaPanel.setBackground(new Color(211, 211, 211));
        anaPanel.setBounds(50, 50, 1400, 800);
        
        anaPanel.add(oranPaneli("Geyik"));
        anaPanel.add(resimPaneli());
        
        frame.add(anaPanel);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1500, 900);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
    }
    
    public static BufferedImage resimSec() {
    	
        JFileChooser fileChooser = new JFileChooser();
        
        // ilk parametresi, dosya filtresinin açıklamasını temsil eder.
        // "Yalnız: JPG JPEG PNG", Kullaniciya yönlendirme mesajı.
        FileNameExtensionFilter dosyaTuru = new FileNameExtensionFilter("Yalnız: JPG JPEG PNG", "jpg", "jpeg", "png");
        
        // kullanıcının sadece belirli türde dosyaları seçebilmesini sağlar. 
        fileChooser.setFileFilter(dosyaTuru);

        // null parametresi, pencerenin merkezi konumda açılmasını sağlar.
        int result = fileChooser.showOpenDialog(null);
        
        // bir dosya seçeilirse, bu metodun dönüş değeri APPROVE_OPTION olur
        if (result == JFileChooser.APPROVE_OPTION) {
            
        	File selectedFile = fileChooser.getSelectedFile();
            
        	try {
        		
                return ImageIO.read(selectedFile);
            
        	} catch (IOException e) {
                
        		e.printStackTrace();
                // Hata durumunda null dönebiliriz veya isteğe bağlı olarak hata mesajı gösterebiliriz.
        		System.out.print("Bir hata oldu.");
            }

        // bir dosya seçmez veya pencere kapanırsa, dönüş değeri CANCEL_OPTION olur.
        } else if(result == JFileChooser.CANCEL_OPTION) {
        	
        	try {
    			resim = ImageIO.read(new File("src/images/secimYok.jpg"));
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
            
            return resim;
            
        }
        
        // Kullanıcı dosya seçmezse veya bir hata oluşursa:
        return null;
        
    }

	public static JPanel oranPaneli(String dosyaIsmi) throws IOException {
		
		JPanel panel = new JPanel();
		panel.setLayout(null);
	    panel.setBackground(new Color(125, 125, 125));
		panel.setBounds(0, 0, 280, 50);
	    
		String[] resimDosyalari = {"Geyik", "Vana", "Kapı", "The Pines", "Günbatımı", "Resim seç..."};
		String[] siraliResimDosyalari = resimDosyalari.clone(); // Dizinin kopyasını oluşturuyoruz.
		Arrays.sort(siraliResimDosyalari); // Diziyi sıralandı.
		// Bu şekilde, siraliResimDosyalari dizisi Arrays.sort() metodu kullanılarak 
		// alfabetik olarak sıralanır ve bu sıralanmış dizi 
		// JComboBox içerisinde kullanılabilir. 
		// Ayrıca, clone() metodu ile orijinal dizinin değişmeden kalmasını sağlamış oluruz.

		JComboBox<String> comboResim = new JComboBox<>(siraliResimDosyalari);
		comboResim.setSelectedItem(dosyaIsmi);
		comboResim.setBounds(20, 10, 100, 30);
		
		comboResim.addActionListener(new ActionListener() {
		    @Override
		    public void actionPerformed(ActionEvent e) {
		        
		    	String secilenResimAdi = (String) comboResim.getSelectedItem();

		        if (secilenResimAdi != null) {
		            String dosyaAdi = "";
		            switch (secilenResimAdi) {
		                case "Geyik":
		                    dosyaAdi = "geyik.jpg";
		                    break;
		                case "Vana":
		                    dosyaAdi = "vana.jpeg";
		                    break;
		                case "Kapı":
		                    dosyaAdi = "kapi.jpg";
		                    break;
		                case "The Pines":
		                    dosyaAdi = "the_pines.jpg";
		                    break;
		                case "Günbatımı":
		                    dosyaAdi = "gunbatimi.jpg";
		                    break;
		                case "Resim seç...":
		                	resim = resimSec();
		                	break;
		                default:
		                    // Seçili öğe listede yoksa bir default durumu belirtilebilir.
		                	// Ancak bizde öyle bi durum yok simdilik :)
		                    break;
		            }

		            try {
		            	
		            	if (!(secilenResimAdi.equals("Resim seç..."))) {
		            		resim = ImageIO.read(new File("src/images/" + dosyaAdi));
		            	}
		            	
		            	// Resim JComboBox'tan her değiştiğinde anaPanel'in yenilenmesi gerekiyor.
		                anaPanel.removeAll();
		                anaPanel.add(oranPaneli(secilenResimAdi));
		                anaPanel.add(resimPaneli());
		                
		                anaPanel.revalidate();
		                anaPanel.repaint();
		                
		            } catch (IOException ex) {
		                ex.printStackTrace();
		            }
		        }
		    }
		});

		
		fieldX = new JTextField("16");
		fieldX.setBounds(140, 10, 50, 30);
		
		// JTextField içine sadece rakam girilsin diye düzenleme yapiyoruz.
	    ((AbstractDocument) fieldX.getDocument()).setDocumentFilter(new DocumentFilter() {
	        @Override
	        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
	            // text.matches("\\d*") ifadesi, 
	        	// yalnızca rakamları kabul eden bir regex ifadesidir.
	        	if (text.matches("\\d*")) {
	                super.replace(fb, offset, length, text, attrs);
	            }
	        }
	    });
		
		fieldY = new JTextField("9");
		fieldY.setBounds(210, 10, 50, 30);
	
	    ((AbstractDocument) fieldY.getDocument()).setDocumentFilter(new DocumentFilter() {
	        @Override
	        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
	            if (text.matches("\\d*")) {
	                super.replace(fb, offset, length, text, attrs);
	            }
	        }
	    });
	    
	    
	    panel.add(comboResim);
	    panel.add(fieldX);
	    panel.add(fieldY);
	    
	    return panel;
	}
    
    public static JPanel resimPaneli() {
		
		JPanel resimPanel = new JPanel() {
            
			public void paintComponent(Graphics grafik) {
                
				grafik.drawImage(resim, 0, 0, null);  // resmi orijinal haliyle gostermek için.
			//	grafik.drawImage(resim, 0, 0, 100, 500, null);  // resmi 100x500 olarak yeniden boyutlandimrak için.
                grafik.drawRect(seciliAlan.x, seciliAlan.y, seciliAlan.width, seciliAlan.height);
            
			}
			
        };

        resimPanel.addMouseListener(new MouseInputAdapter() {
            public void mousePressed(MouseEvent event) {
                seciliAlanBaslangic = event.getPoint();
                seciliAlan.setLocation(seciliAlanBaslangic);
            }

            public void mouseReleased(MouseEvent event) {
                kaydet();
                kaydetOran();
            }
        });

        resimPanel.addMouseMotionListener(new MouseInputAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                
            	oranX = Double.parseDouble(fieldX.getText());
            	oranY = Double.parseDouble(fieldY.getText());
            	
            	oran = oranX / oranY;

                int x = seciliAlanBaslangic.x;
                int y = seciliAlanBaslangic.y;
                int width = e.getX() - seciliAlanBaslangic.x;
                int height = e.getY() - seciliAlanBaslangic.y;

                // Sınırları aşmamak için kontroller
                if (x + width > resim.getWidth()) {
                    width = resim.getWidth() - x;
                    height = (int) (width / oran);
                }

                if (y + height > resim.getHeight()) {
                    height = resim.getHeight() - y;
                    width = (int) (height * oran);
                }

                // Oran kontrolleri
                if (Math.abs(height) * oran <= Math.abs(width)) {
                    width = (int) (Math.signum(width) * Math.abs(height) * oran);
                } else {
                    height = (int) (Math.signum(height) * Math.abs(width) / oran);
                }

                seciliAlan.setBounds(x, y, width, height);

                resimPanel.repaint();
            }
        });

        
        resimPanel.setBounds(0, 50, 1166, 768);

        return resimPanel;
        
	}
	
	// En-Boy Oranina göre seçilen alani 
    // 1024 genisligie göre kaydeden metod --->  En-Boy ORAN 16:9   ---->  ÖLÇÜ 1024×...
	private static void kaydetOran() {  
    	
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-d HH-mm-ss");
		Date date = new Date();
		
		int genislik = 1024;
		int yukseklik = (int) ((1024*oranY)/oranX);
    	
    	BufferedImage secilenAlan = resim.getSubimage(seciliAlan.x, seciliAlan.y, seciliAlan.width, seciliAlan.height);
   		
    	BufferedImage scaledImage = new BufferedImage(genislik, yukseklik, secilenAlan.getType());
    	
    	Graphics2D graphics = scaledImage.createGraphics();
    	graphics.drawImage(secilenAlan, 0, 0, genislik, yukseklik, null);
    	graphics.dispose();

    	File kaydedilecekDosya = new File("src/images/secilenAlan-"+dateFormat.format(date)+".jpg");
            	
    	try {
    	    ImageIO.write(scaledImage, "jpg", kaydedilecekDosya);
    //	    System.out.println("Dosya kaydedildi: " + kaydedilecekDosya.getAbsolutePath());
    	} catch (IOException e) {
    	    e.printStackTrace();
    	}
    }
    
    // Mouse ile seçilen alani kaydeder... 
    // Mouse ile belirlenen Orijinal olçüde....
    private static void kaydet() { 
    	
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-d HH-mm-ss");
		Date date = new Date();

    	
    	BufferedImage secilenAlan = resim.getSubimage(seciliAlan.x, seciliAlan.y, seciliAlan.width, seciliAlan.height);

    	Graphics2D graphics = secilenAlan.createGraphics();
    	graphics.drawImage(secilenAlan, 0, 0, seciliAlan.width, seciliAlan.height, null);
    	graphics.dispose();
    	
    	File kaydedilecekDosya = new File("src/images/secilenAlan_"+dateFormat.format(date)+".jpg");
            	
        try {
        
        	ImageIO.write(secilenAlan, "jpg", kaydedilecekDosya);
       //     System.out.println("Dosya kaydedildi: " + kaydedilecekDosya.getAbsolutePath());
        
        } catch (IOException e) {
        
        	e.printStackTrace();
        
        }
    }

    public static void main(String[] args) {
       
    	SwingUtilities.invokeLater(() -> {
    	    
    		try {
				
    			new FileChooserEnBoyOranliSeciliAlan();
			
    		} catch (IOException e) {

				e.printStackTrace();
			}
    		
        });

    }
}

