package ij.plugin;
import ij.*;
import ij.gui.*;
import ij.util.Tools;
import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;


/** This plugin implements the Help/Update ImageJ command. */
public class ImageJ_Updater implements PlugIn {
	private static final String URL = "http://wsr.imagej.net";
	private String notes;

	public void run(String arg) {
		if (arg.equals("menus")) {
			updateMenus();
			return;
		}
		if (IJ.getApplet()!=null)
			return;
		URL url = getClass().getResource("/ij/IJ.class");
		String ij_jar = url == null ? null : url.toString().replaceAll("%20", " ");
		if (ij_jar==null || !ij_jar.startsWith("jar:file:")) {
			error("Could not determine location of ij.jar");
			return;
		}
		int exclamation = ij_jar.indexOf('!');
		ij_jar = ij_jar.substring(9, exclamation);
		if (IJ.debugMode) IJ.log("Updater (jar loc): "+ij_jar);
		File file = new File(ij_jar);
		if (!file.exists()) {
			error("File not found: "+file.getPath());
			return;
		}
		if (!file.canWrite()) {
			String path = file.getPath();
			String msg = "No write access: "+path;
			if (IJ.isMacOSX() && path!=null && path.startsWith("/private/var/folders/")) {
				msg = "ImageJ is in a read-only folder due to Path Randomization.\n"
				+ "To work around this problem, drag ImageJ.app to another\n"
				+ "folder and then (optionally) drag it back.";
			}
			error(msg);
			return;
		}
		String[] list = openUrlAsList(URL+"/jars/list.txt");
		if (list==null || list.length==0) {
			error("Error opening "+URL+"/jars/list.txt");
			return;
		}
		int count = list.length + 2;
		String[] versions = new String[count];
		String[] urls = new String[count];
		versions[0] = list[0];
		urls[0] = URL+"/jars/ij.jar";
		for (int i=1; i<count-2; i++) {
			String version = list[i];
			versions[i] = version.substring(0,version.length()-1); // remove letter
			urls[i] = URL+"/jars/ij"+version.substring(1,2)+version.substring(3,6)+".jar";
		}
		versions[count-2] = "daily build";
		urls[count-2] = URL+"/download/daily-build/ij.jar";
		versions[count-1] = "previous";
		urls[count-1] = URL+"/jars/ij2.jar";
		//for (int i=0; i<count; i++)
		//	IJ.log(i+" "+versions[i]+"  "+urls[i]);
		int choice = showDialog(versions);
		if (choice==-1 || !Commands.closeAll())
			return;
		byte[] jar = null;
		jar = getJar(urls[choice]);
		if (jar==null) {
			error("Unable to download ij.jar from "+urls[choice]);
			return;
		}
		Prefs.savePreferences();
		saveJar(file, jar);
		if (choice<count-2) // force macro Function Finder to download fresh list
			new File(IJ.getDirectory("macros")+"functions.html").delete();
		System.exit(0);
	}

	int showDialog(String[] versions) {
		GenericDialog gd = new GenericDialog("ImageJ Updater");
		gd.addChoice("Upgrade To:", versions, versions[0]);
		String msg = 
			"You are currently running v"+ImageJ.VERSION+ImageJ.BUILD+".\n"+
			" \n"+
			"If you click \"OK\", ImageJ will quit\n"+
			"and you will be running the upgraded\n"+
			"version after you restart ImageJ.\n";
		gd.addMessage(msg);
		gd.showDialog();
		if (gd.wasCanceled())
			return -1;
		else
			return gd.getNextChoiceIndex();
	}

	String openUrlAsString(String address, int maxLines) {
		StringBuffer sb;
		try {
			URL url = new URL(address);
			InputStream in = url.openStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			sb = new StringBuffer();
			int count = 0;
			String line;
			while ((line=br.readLine())!=null && count++<maxLines)
				sb.append (line + "\n");
			in.close ();
		} catch (IOException e) {sb = null;}
			return sb!=null?new String(sb):null;
	}

	byte[] getJar(String address) {
		byte[] data;
		try {
			URL url = new URL(address);
			IJ.showStatus("Connecting to "+IJ.URL2);
			URLConnection uc = url.openConnection();
			int len = uc.getContentLength();
			if (IJ.debugMode) IJ.log("Updater (url): "+ address + " "+ len);
			if (len<=0)
				return null;
			String name = address.contains("daily")?"daily build (":"ij.jar (";
			IJ.showStatus("Downloading "+ name + IJ.d2s((double)len/1048576,1)+"MB)");
			InputStream in = uc.getInputStream();
			data = new byte[len];
			int n = 0;
			while (n < len) {
				int count = in.read(data, n, len - n);
				if (count<0)
					throw new EOFException();
	   			 n += count;
				IJ.showProgress(n, len);
			}
			in.close();
		} catch (IOException e) {
			if (IJ.debugMode) IJ.log(""+e);
			return null;
		}
		if (IJ.debugMode) IJ.wait(6000);
		return data;
	}

	void saveJar(File f, byte[] data) {
		try {
			FileOutputStream out = new FileOutputStream(f);
			out.write(data, 0, data.length);
			out.close();
		} catch (IOException e) {
		}
	}

	String[] openUrlAsList(String address) {
		IJ.showStatus("Connecting to "+IJ.URL2);
		Vector v = new Vector();
		try {
			URL url = new URL(address);
			InputStream in = url.openStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String line;
			while (true) {
				line = br.readLine();
				if (line==null) break;
				if (!line.equals("")) v.addElement(line);
			}
			br.close();
		} catch(Exception e) { }
		String[] lines = new String[v.size()];
		v.copyInto((String[])lines);
		IJ.showStatus("");
		return lines;
	}

	void error(String msg) {
		IJ.error("ImageJ Updater", msg);
	}
	
	void updateMenus() {
		if (IJ.debugMode) {
			long start = System.currentTimeMillis();
			Menus.updateImageJMenus();
			IJ.log("Refresh Menus: "+(System.currentTimeMillis()-start)+" ms");
		} else
			Menus.updateImageJMenus();
	}

}
