package ftp_client;

import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

import javax.swing.Icon;
//import javax.swing.JFileChooser;
import javax.swing.filechooser.FileSystemView;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

// Classe de diverses fonctions statiques
public class Misc {
	/* Read/Write object in a file */
	// Lire un object depuis un fichier
	public static Object readObjectFromFile(final String path){
		try{
			if(!(new File(path).exists())) return null; // Si le fichier n'existe pas, renvoyer null
			FileInputStream fis = new FileInputStream(path);	// Creation du flux d'entree a partir du fichier
			ObjectInputStream ois = new ObjectInputStream(fis);	// Creation du flux de sortie vers un Object
			Object obj = ois.readObject(); // Lecture de l'objet
			ois.close(); // Fermeture du flux de sortie
			fis.close(); // Fermeture du flux d'entree
			return obj; // Retourner l'objet
		}catch(Exception e){ // En cas d'erreur, envoyer un message d'erreur et retourner null
			Message.sendError("Impossible de récupérer les paramètres.");
			return null;
		}
	}
	
	// Ecrire un objet (serializable) dans un fichier
	public static boolean writeFileFromObject(final String path, Object obj){
		try{
			FileOutputStream fos = new FileOutputStream(path);		// Creation du flux de sortie vers un fichier
			ObjectOutputStream oos = new ObjectOutputStream(fos);	// Creation du flux d'entree depuis un objet serializable
			oos.writeObject(obj);	// Ecriture de l'objet
			oos.close(); // Fermeture du flux de sortie
			fos.close(); // Fermeture du flux d'entree
			return true; // Retourner vrai
		}catch(Exception e){ // En cas d'erreur, envoyer un message d'erreur et retourner faux
			Message.sendError("Impossible de sauvegarder les paramètres.");
			return false;
		}
	}
	
	/* Size to String */
	// Fonctions de conversion d'une taille de fichier en chaine de caractere plus lisible pou l'utilisateur
	// Taille informatique (Ki, Mi, Gi)
	/*public static String sizeToString(double size){
		if(size > 1024*1024*1024) return numberToString(size/(1024*1024*1024), 2)+" Gio";
		if(size > 1024*1024) return numberToString(size/(1024*1024), 2)+" Mio";
		if(size > 1024) return numberToString(size/(1024), 2)+" Kio";
		return ((int)size)+" o";
	}	
	public static String sizeToString(long size){
		if(size > 1024*1024*1024) return numberToString(size/(1024*1024*1024.0), 2)+" Gio";
		if(size > 1024*1024) return numberToString(size/(1024*1024.0), 2)+" Mio";
		if(size > 1024) return numberToString(size/(1024.0), 2)+" Kio";
		return size+" o";
	}*/
	// Taille classique (K, M, G)
	public static String sizeToString(double size){
		if(size > 1000000000) return numberToString(size/(1000000000), 2)+" Go";
		if(size > 1000000) return numberToString(size/(1000000), 2)+" Mo";
		if(size > 1000) return numberToString(size/(1000), 2)+" Ko";
		return ((int)size)+" o";
	}	
	public static String sizeToString(long size){
		if(size > 1000000000) return numberToString(size/(1000000000.0), 2)+" Go";
		if(size > 1000000) return numberToString(size/(1000000.0), 2)+" Mo";
		if(size > 1000) return numberToString(size/(1000.0), 2)+" Ko";
		return size+" o";
	}
	
	// Conversion d'un nombre a decimals en chaine de caractere plus lisible pou l'utilisateur
	// On garde n_digits decimals, on rajoute des 0 si necessaire
	public static String numberToString(Number n, int n_digits){
		String str = n.toString();
		int dot = str.indexOf(".")+1;
		if(dot == 0){ str += "."; dot = str.length()-1; }
		str = str.substring(0, Math.min(str.length(), dot+n_digits));
		for(; str.length() < dot+n_digits;) str += "0";
		return str;
	}
	
	/* File Icon from system */
	// Recuperation d'un icone systeme depuis un fichier
	public static Image getSystemImageFromFile(File fFile) {
		ImageData imgData = getImageData(fFile);
		if (imgData != null)
			return new Image(Display.getCurrent(), imgData);
		return null;
	}
	public static ImageData getImageData(File file) {
		try {
			if(!file.exists()) return null; // Si le fichier n'existe pas, quitter
			Icon icon = null;
			// Recuperation de l'icone
			icon = FileSystemView.getFileSystemView().getSystemIcon(file); // Better on Windows
			//icon = new JFileChooser().getIcon(file);				  	   // Better on Linux
			if(icon == null) return null;
			// Conversion de l'icone en BufferedImage
			BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
			icon.paintIcon(null, image.getGraphics(), 0, 0);
			// Conversion de la BufferedImage en ImageData
			return convertToImageData(image);
		} catch (Exception e) {}
		return null;
	}	
	
	/* BufferedImage to SWT Image */
	// Conversion d'une BufferedImage en ImageData
	// Lecture de la couleur des pixels via getPixel(), et ecriture dans un ImageData via setPixel()
	public static ImageData convertToImageData(BufferedImage bufferedImage) {
		if (bufferedImage.getColorModel() instanceof DirectColorModel) {
			DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
			PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask());
			ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
			WritableRaster raster = bufferedImage.getRaster();
			int[] pixelArray = new int[4];
			for (int y = 0; y < data.height; y++)
				for (int x = 0; x < data.width; x++) {
					raster.getPixel(x, y, pixelArray);
					int pixel;
					if(pixelArray[3] < 100)  pixel = palette.getPixel(new RGB(255, 255, 255));
					else  					 pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2]));
					data.setPixel(x, y, pixel);
				}
			return data;
		} else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
			IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel();
			int size = colorModel.getMapSize();
			byte[] reds = new byte[size];
			byte[] greens = new byte[size];
			byte[] blues = new byte[size];
			colorModel.getReds(reds);
			colorModel.getGreens(greens);
			colorModel.getBlues(blues);
			RGB[] rgbs = new RGB[size];
			for (int i = 0; i < rgbs.length; i++)
				rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
			PaletteData palette = new PaletteData(rgbs);
			ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
			data.transparentPixel = colorModel.getTransparentPixel();
			WritableRaster raster = bufferedImage.getRaster();
			int[] pixelArray = new int[1];
			for (int y = 0; y < data.height; y++)
				for (int x = 0; x < data.width; x++) {
					raster.getPixel(x, y, pixelArray);
					data.setPixel(x, y, pixelArray[0]);
				}
			return data;
		}
		return null;
	}
	/* File Icon from extension */
	// Icone a partir de l'extension du fichier
	public static Image getIconFromName(String fileName) {
		try {
			String extension = ".txt"; // Par defaut, on prend l'icone d'un fichier texte
			// On essaye de recuperer l'extension
			int lastdot = fileName.lastIndexOf(".");
			if(lastdot != -1) extension = fileName.substring(lastdot);
			// On cherche le programme lie
			ImageData imgData = Program.findProgram(extension).getImageData();
			// Si l'ImageData n'est pas null, retourner sa conversion en Image 
			if (imgData != null) return new Image(Display.getCurrent(), imgData);
		} catch (Exception e) {}
		return null;
	}
	
	/* File parent path */
	// Recuperation du dossier parent d'un File depuis son getAbsolutePath() (sans passer par getParentFile())
	public static String getParentPath(File file){
		return file.getAbsolutePath().substring(0, file.getAbsolutePath().length()-file.getName().length());
	}

	/* Make local dir */
	// Creation d'un dossier local
	public static boolean makeDir(File file, String name){
		Message.send("Création du dossier \""+name+"\"");
		String base = "";
		if(file.isDirectory())  base = file.getAbsolutePath();
		else					base = Misc.getParentPath(file);
		boolean ok = (new File(base+File.separator+name).mkdir());
		if(ok)	Message.send("Dossier \""+name+"\" créé");
		else	Message.sendError("Impossible de créer le dossier \""+name+"\"");
		return ok;
	}
	
	/* Show blocking yes/no message box */
	// Fenetre Oui/Non
	static boolean yesno_rtn;
	public static synchronized boolean showYesNo(final Shell shell, final String title, final String message){
		yesno_rtn = false;
		Display.getDefault().syncExec(new Runnable() { // Action synchrone, on attend de finir ce thread avant de reprendre la fonction
	           public void run() {
					MessageBox mb = new MessageBox(shell, SWT.YES | SWT.NO);
			        mb.setText(title);
			        mb.setMessage(message);
			        yesno_rtn = (mb.open() == SWT.YES); // yesno_rtn = true si l'utilisateur repond oui 
	           }
		});
		return yesno_rtn;
	}
	
	/* File/FTPFile modification date */
	// Recuperation de la date de modification d'un FTPFile ou d'un File de base
	public static String getDate(File f){
		if(f instanceof FTPFile) return ((FTPFile)f).getDate();
		return new Date(f.lastModified()).toString();
	}
	
	/* File/FTPFile owner */
	// Recuperation du possesseur d'un FTPFile ou d'un File de base
	public static String getOwner(File f){
		if(f instanceof FTPFile) return ((FTPFile)f).getOwnerGroup();
		return "";
	}
	
	/* Path "beautifulizer" */
	// Rendre un chemin d'acces "plus jolie"
	// Exemple "C:\\dossier\/\dossier2//dossier3/" -> "C:\dossier\dossier2\dossier3\"
	public static String folderSepatator = "\\";
	public static String pathBeautifulizer(String path){
		while(path.contains("//") || path.contains("\\\\") || path.contains("\\/") || path.contains("/\\"))
			path = path.replace("//", folderSepatator).replace("\\\\", folderSepatator)
					   .replace("\\/", folderSepatator).replace("/\\", folderSepatator);
		return path.replace("\\", folderSepatator).replace("/", folderSepatator);
	}
}
