package charactermanaj.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import charactermanaj.model.AppConfig;
import charactermanaj.util.DesktopUtilities;
import charactermanaj.util.ErrorMessageHelper;
import charactermanaj.util.LocalizedResourceTextLoader;


/**
 * Aboutボックスを表示する.
 * @author seraphy
 */
public class AboutBox {
	
	private JFrame parent;
	
	public AboutBox(JFrame parent) {
		if (parent == null) {
			throw new IllegalArgumentException();
		}
		this.parent = parent;
	}

	/**
	 * Aboutボックスを表示する.
	 */
	public void showAboutBox() {

		final JTabbedPane tabs = new JTabbedPane();
		tabs.setPreferredSize(new Dimension(400, 300));

		final JPanel aboutPanel = createAboutPanel();
		final JSysInfoPanel sysInfoPanel = createSysInfoPanel();
		
		tabs.addTab("About", aboutPanel);
		tabs.addTab("System", sysInfoPanel);

		tabs.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				if (tabs.getSelectedIndex() == 1) {
					gc();
					sysInfoPanel.setText(getSysInfoText());
				}
			}
		});
		
		JOptionPane.showMessageDialog(parent, tabs, "About", JOptionPane.INFORMATION_MESSAGE);
	}
	
	protected JPanel createAboutPanel() {
		String message = LocalizedResourceTextLoader.getInstance().getText("appinfo/about.html", Charset.forName("MS932"));

		JPanel aboutPanel = new JPanel(new BorderLayout());
		JEditorPane editorPane = new JEditorPane();
		editorPane.addHyperlinkListener(new HyperlinkListener() {
			public void hyperlinkUpdate(HyperlinkEvent e) {
				if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
					URL url = e.getURL();
					try {
						if (!DesktopUtilities.browse(url.toURI())) {
							JOptionPane.showMessageDialog(parent, url.toString());
						}

					} catch (Exception ex) {
						ErrorMessageHelper.showErrorDialog(parent, ex);
					}
				}
			}
		});
		editorPane.setEditable(false);
		editorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
		editorPane.setContentType("text/html");
		editorPane.setText(message);
		editorPane.setSelectionStart(0);
		editorPane.setSelectionEnd(0);
		aboutPanel.add(new JScrollPane(editorPane), BorderLayout.CENTER);
		
		return aboutPanel;
	}
	
	protected JSysInfoPanel createSysInfoPanel() {
		return new JSysInfoPanel();
	}
	
	protected String getSysInfoText() {
		long freeMem, totalMem, maxMem;
		Runtime rt = Runtime.getRuntime();
		gc();
		totalMem = rt.totalMemory() / 1024;
		freeMem = rt.freeMemory() / 1024;
		maxMem = rt.maxMemory() / 1024;
		
		DecimalFormat decimalFmt = new DecimalFormat("#,###,##0");
		
		StringBuilder buf = new StringBuilder();
		buf.append("<html>");
		buf.append("<h2>Runtime Information</h2>");
		buf.append("<table border=\"0\">");
		buf.append("<tr><td>Max Memory:</td><td>" + decimalFmt.format(maxMem) + " KiB</td></tr>");
		buf.append("<tr><td>Total Memory:</td><td>" + decimalFmt.format(totalMem) + " KiB</td></tr>");
		buf.append("<tr><td>Free Memory:</td><td>" + decimalFmt.format(freeMem) + " KiB</td></tr>");
		buf.append("</table>");
		
		AppConfig appConfig = AppConfig.getInstance();
		
		buf.append("<h2>Character Database</h2>");
		buf.append("<table border=\"1\">");
		buf.append("<tr><td>System</td><td>" + appConfig.getSystemCharactersDir() + "</td></tr>");
		buf.append("<tr><td>User</td><td>" + appConfig.getUserCharactersDir() + "</td></tr>");
		buf.append("</table>");
		
		buf.append("<h2>System Properties</h2><table border=\"1\">");
		try {
			Properties sysprops = System.getProperties();
			Enumeration<?> enmKey = sysprops.keys();
			TreeMap<String, String> propMap = new TreeMap<String, String>(); // プロパティキーのアルファベッド順にソート
			while (enmKey.hasMoreElements()) {
				String key = (String) enmKey.nextElement();
				String value = sysprops.getProperty(key);
				propMap.put(key, value == null ? "null" : value);
			}
			for (Map.Entry<String, String> entry : propMap.entrySet()) {
				buf.append("<tr>");
				buf.append("<td>" + escape(entry.getKey()) + "</td><td>" + escape(entry.getValue()) + "</td>");
				buf.append("</tr>");
			}
			buf.append("</table>");
		} catch (Exception ex) {
			buf.append(escape(ex.toString()));
		}
		
		buf.append("<h2>System Environments</h2>");
		try {
			TreeMap<String, String> envMap = new TreeMap<String, String>(); // 環境変数名のアルファベット順にソート
			envMap.putAll(System.getenv());
			buf.append("<table border=\"1\">");
			for (Map.Entry<String, String> entry : envMap.entrySet()) {
				buf.append("<tr>");
				buf.append("<td>" + escape(entry.getKey()) + "</td><td>" + escape(entry.getValue()) + "</td>");
				buf.append("</tr>");
			}
			buf.append("</table>");
		} catch (Exception ex) {
			buf.append(escape(ex.toString()));
		}
		
		buf.append("</html>");
		return buf.toString();
	}
	
	protected String escape(String value) {
		if (value == null) {
			return null;
		}
		value = value.replace("&", "&amp;");
		value = value.replace("<", "&lt;");
		value = value.replace(">", "&gt;");
		return value;
	}
	
	protected void gc() {
		for (int idx = 0; idx < 3; idx++) {
			System.gc();
			try {
				Thread.sleep(100);
			} catch (InterruptedException ex) {
				// do nothing.
			}
		}
	}
}

class JSysInfoPanel extends JPanel {

	private static final long serialVersionUID = 1L;

	private JEditorPane editorPane;
	
	public JSysInfoPanel() {
		super(new BorderLayout());
		
		editorPane = new JEditorPane();
		editorPane.setEditable(false);
		editorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
		editorPane.setContentType("text/html");
		editorPane.setText("");
		
		JButton btnSave = new JButton("save");
		btnSave.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				onSave();
			}
		});
		JPanel btnPanel = new JPanel(new BorderLayout());
		btnPanel.add(btnSave, BorderLayout.EAST);
		
		add(new JScrollPane(editorPane), BorderLayout.CENTER);
		add(btnPanel, BorderLayout.SOUTH);
	}
	
	public void setText(String message) {
		editorPane.setText(message);
		editorPane.setSelectionStart(0);
		editorPane.setSelectionEnd(0);
	}
	
	protected void onSave() {
		JFileChooser chooser = new JFileChooser();
		chooser.setSelectedFile(new File("sysinfo.html"));
		if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) {
			return;
		}
		File file = chooser.getSelectedFile();
		try {
			FileOutputStream os = new FileOutputStream(file);
			try {
				Writer wr = new OutputStreamWriter(os, Charset.forName("UTF-8"));
				wr.write(editorPane.getText());
				wr.flush();
			} finally {
				os.close();
			}
			
		} catch (Exception ex) {
			ErrorMessageHelper.showErrorDialog(this, ex);
		}
	}
	
}
