package lu.tudor.santec.gecamed.core.gui.utils;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.ButtonBarBuilder;

/**
 * @author hermenj
 *
 * @version
 * <br>$Log: UpdateChecker.java,v $
 * <br>Revision 1.1  2015-06-26 09:02:59  hermenj
 * <br>*** empty log message ***
 * <br>
 */
public class UpdateChecker {

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(UpdateChecker.class.getName());
	
	public static final String ACTION_CHECK_MANUAL	= "CHECK_MANUAL";
	public static final String ACTION_CHECK_AUTO	= "CHECK_AUTO";
	public static final String ACTION_ACTIVATE 		= "ACTIVATE";
	public static final String ACTION_DEACTIVATE 	= "DEACTIVATE";
	public static final String ACTION_NEW 			= "NEW";
	
	private static String url = "";
	private static String devurl = "";
	private static String version = "";
	private static String info;
	private static String info2;
	private static File clientFile = new File("./servermessage.txt");

	private static int delay = 0;

	
	private Window owner;

	public UpdateChecker(Window owner) {
		this.owner = owner;
	}
	
	public static void setUrl(String urlString) {
		url = urlString;
	}
	
	public static void setDevUrl(String urlString) {
		devurl = urlString;
	}
	
	public static void setVersion(String versionString) {
		version = versionString;
	}
	
	public static void setInfo(String infoString) {
		info = infoString;
	}
	
	public static void setInfo2(String info2String) {
		info2 = info2String;
	}
	
	public static void setClientFile(File pClientFile) {
		clientFile  = pClientFile;
	}
	
	public static void setDelaySec(int delaySec) {
		delay  = delaySec;
	}
	
	public void checkUpdate(final boolean showDialog, final boolean forceDialog, final String action) {
		new Thread() {
			public void run() {
				try {
					if (!forceDialog) {
						Thread.sleep(delay* 1000);
					}
					
					String sentAction = action;
					
					if (! clientFile.exists()) {
						sentAction = ACTION_NEW;
					}
					
					StringBuffer urlString = new StringBuffer(url);
					if (version != null) {
						urlString.append("&version=").append(version);
					}
					if (info != null) {
						urlString.append("&info=").append(info);
					}
					if (info2 != null) {
						urlString.append("&info2=").append(info2);						
					}
					if (sentAction != null) {
						urlString.append("&action=").append(sentAction);						
					}
					String serverMessage = "";
					try {
						serverMessage = getText(urlString.toString());
						serverMessage = "<html>" + serverMessage.substring(serverMessage.indexOf("<body>"), serverMessage.length());						
					} catch (Exception e) {
						logger.warn("Error reading server-side updateinfo file: " + url);
						serverMessage = "";
					}

					String clientMessage = "";
					try {
						if (clientFile.exists()) {
							clientMessage = readFile(clientFile);													
						} else {
							writeFile(serverMessage, clientFile);		
						}
					} catch (Exception e) {
						logger.info("error reading client-side updateinfo file: " + clientFile.getAbsolutePath(), e);
					}

					if (! clientMessage.equals("") && serverMessage.length() > 0 && ! serverMessage.equals(clientMessage) && showDialog) {
						showServerMessage(serverMessage);					
					} else if (forceDialog) {
						showServerMessage(serverMessage);
					} else {
						logger.info("no new updateinfo on server.");
					}
				} catch (Exception e) {
					logger.info("error running update check", e);
				} finally {
					logger.debug("Update check done");
				}
			}
		}.start();
	}
	
	public void showServerMessage(final String message) {
		try {
			final JDialog jd = new JDialog(this.owner, Translatrix.getTranslationString("core.updatemessage"));
			jd.setModal(true);
			jd.setLayout(new BorderLayout());
			final JEditorPane htmlPane = new JEditorPane();
			htmlPane.setContentType("text/html");
			htmlPane.setText(message);
			htmlPane.setEditable(false);
			htmlPane.addHyperlinkListener(new HyperlinkListener() {
				public void hyperlinkUpdate(HyperlinkEvent event) {
					try {
						if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
				            String url = event.getURL().toString();
				            Desktop.getDesktop().browse(URI.create(url));
				        }
					} catch (Exception e2) {
						e2.printStackTrace();
					}
				}
			});
			
			jd.add(new JScrollPane(htmlPane), BorderLayout.CENTER);	
			
			ButtonBarBuilder bb = new ButtonBarBuilder();
			bb.addGlue();
			final JButton dismissButton = new JButton(Translatrix.getTranslationString("core.dontshowagain"));
			final JButton closeButton = new JButton(Translatrix.getTranslationString("core.close"));
		
			ActionListener al = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (e.getSource().equals(dismissButton)) {
						try {
							writeFile(message, clientFile);							
						} catch (Exception e2) {
							e2.printStackTrace();
						}
						jd.setVisible(false);
						jd.dispose();
					} else if (e.getSource().equals(closeButton)) {
						jd.setVisible(false);
						jd.dispose();
					} 
				}
			};
			
			closeButton.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					if (e.getButton() == MouseEvent.BUTTON3) {
						try {
							htmlPane.setPage(new URL(devurl));							
						} catch (Exception e2) {
							e2.printStackTrace();
						}
					}
				}
			});
			
			dismissButton.addActionListener(al);
			bb.addGridded(dismissButton);
			bb.addRelatedGap();
			closeButton.addActionListener(al);
			bb.addGridded(closeButton);
			
			
			jd.add(bb.getPanel(), BorderLayout.SOUTH);
			jd.setSize(600, 500);
			jd.setLocationRelativeTo(this.owner);
			jd.setVisible(true);
		} catch (Exception e) {
			logger.info("Error showing updatemessage Dialog", e);
		}
	}
	
	
	private static String getText(String url) throws Exception {
        URL website = new URL(url);
        URLConnection connection = website.openConnection();
        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                    connection.getInputStream()));

        StringBuilder response = new StringBuilder();
        String inputLine;

        while ((inputLine = in.readLine()) != null) 
            response.append(inputLine);

        in.close();
        return response.toString();
    }
	
	/**
	 * reads the provided file into a byte[]
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String readFile(File file) throws IOException {
		InputStream is = new FileInputStream(file);

		long length = file.length();
		byte[] bytes = new byte[(int) length];

		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		if (offset < bytes.length) {
			is.close();
			throw new IOException("Could not completely read file "	+ file.getName());
		}

		is.close();
		return new String(bytes);
	}

	/**
	 * writes the provided byte[] to the provided file.
	 * 
	 * @param data
	 * @param target
	 * @return
	 * @throws IOException
	 */
	public static boolean writeFile(String data, File target) throws IOException {
		ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
		FileOutputStream fos = null;
		FileChannel channel;

		try {
			fos = new FileOutputStream(target);
			channel = fos.getChannel();
			channel.write(buffer);
		} finally {
			if (fos != null)
				fos.close();
		}

		return true;
	}

//    public static void main(String[] args) throws Exception {
//    	UpdateChecker.setUrl("http://santec.tudor.lu/project/iveu/updatemessage?do=export_html");
//    	UpdateChecker.setVersion("2.02.04");
//    	UpdateChecker.setInfo("");
//    	UpdateChecker udc = new UpdateChecker(null);
//    	udc.checkUpdate(true, true);
//    }
}
