package de.onyxbits.raccoon.gui;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.prefs.Preferences;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import de.onyxbits.raccoon.App;
import de.onyxbits.raccoon.BrowseUtil;
import de.onyxbits.raccoon.Messages;
import de.onyxbits.raccoon.io.Archive;
import de.onyxbits.raccoon.io.DownloadLogger;

/**
 * The main UI. This class must be started by creating an object and passing it
 * to SwingUtils.invokeLater()
 * 
 * @author patrick
 * 
 */
public class MainActivity extends JFrame implements ActionListener, WindowListener, Runnable {

	private static final long serialVersionUID = 1L;

	/**
	 * Preferences key for storing the last opened archive directory.
	 */
	public static final String LASTARCHIVE = "lastarchive"; //$NON-NLS-1$

	/**
	 * Preferences key for whether or not to fetch icons.
	 */
	public static final String FETCHICONS = "fetchicons"; //$NON-NLS-1$

	private JMenuItem quit;
	private JMenuItem open;
	private JMenuItem search;
	private JMenuItem close;
	private JMenuItem update;
	private JMenuItem exportArchive;
	private JMenuItem importArchive;
	private JMenuItem downloads;
	private JMenuItem contents;
	private JMenuItem newArchive;
	private JRadioButtonMenuItem fetchIcons;

	private JTabbedPane views;
	private ListView downloadList;
	private JScrollPane downloadListScroll;

	private SearchView searchView;

	private Archive archive;
	private static Vector<MainActivity> all = new Vector<MainActivity>();

	/**
	 * New GUI
	 * 
	 * @param archive
	 *          the archive to display. This may be null.
	 */
	public MainActivity(Archive archive) {
		this.archive = archive;
		views = new JTabbedPane();
		downloadList = new ListView();

		JMenuBar bar = new JMenuBar();
		JMenu file = new JMenu(Messages.getString("MainActivity.1")); //$NON-NLS-1$
		file.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.0")).getKeyCode()); //$NON-NLS-1$
		quit = new JMenuItem(
				Messages.getString("MainActivity.2"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.22")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		open = new JMenuItem(
				Messages.getString("MainActivity.3"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.23")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		close = new JMenuItem(
				Messages.getString("MainActivity.4"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.24")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		close.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		update = new JMenuItem(
				Messages.getString("MainActivity.5"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.25")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		update.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		update.setEnabled(false);
		newArchive = new JMenuItem(
				Messages.getString("MainActivity.29"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.30")) //$NON-NLS-1$ //$NON-NLS-2$
						.getKeyCode());
		newArchive.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		exportArchive = new JMenuItem(
				Messages.getString("MainActivity.33"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.35")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		importArchive = new JMenuItem(
				Messages.getString("MainActivity.36"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.37")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$

		Preferences prefs = Preferences.userNodeForPackage(getClass());
		fetchIcons = new JRadioButtonMenuItem(
				Messages.getString("MainActivity.34"), prefs.getBoolean(FETCHICONS, true)); //$NON-NLS-1$
		file.add(newArchive);
		file.add(open);
		file.add(new JSeparator());
		file.add(importArchive);
		file.add(exportArchive);
		file.add(update);
		file.add(new JSeparator());
		file.add(close);
		file.add(quit);
		bar.add(file);

		JMenu view = new JMenu(Messages.getString("MainActivity.6")); //$NON-NLS-1$
		view.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.15")).getKeyCode()); //$NON-NLS-1$
		search = new JMenuItem(
				Messages.getString("MainActivity.7"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.26")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		search.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		downloads = new JMenuItem(
				Messages.getString("MainActivity.8"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.27")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		downloads.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Toolkit.getDefaultToolkit()
				.getMenuShortcutKeyMask()));
		view.add(search);
		view.add(downloads);
		view.add(new JSeparator());
		view.add(fetchIcons);
		search.setEnabled(false);
		downloads.setEnabled(false);
		importArchive.setEnabled(false);
		exportArchive.setEnabled(false);
		bar.add(view);

		JMenu help = new JMenu(Messages.getString("MainActivity.9")); //$NON-NLS-1$
		help.setMnemonic(KeyStroke.getKeyStroke(Messages.getString("MainActivity.21")).getKeyCode()); //$NON-NLS-1$
		contents = new JMenuItem(
				Messages.getString("MainActivity.10"), KeyStroke.getKeyStroke(Messages.getString("MainActivity.28")).getKeyCode()); //$NON-NLS-1$ //$NON-NLS-2$
		contents.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
		help.add(contents);
		bar.add(help);

		setJMenuBar(bar);
		setContentPane(views);
	}

	public void run() {
		if (archive == null) {
			Preferences prefs = Preferences.userNodeForPackage(getClass());
			String tmp = prefs.get(MainActivity.LASTARCHIVE, null);
			if (tmp != null) {
				archive = new Archive(new File(tmp));
			}
			else {
				archive = new Archive(new File(App.getDir(App.ARCHIVEDIR),
						Messages.getString("MainActivity.11"))); //$NON-NLS-1$
			}
		}
		newArchive.addActionListener(this);
		open.addActionListener(this);
		quit.addActionListener(this);
		close.addActionListener(this);
		search.addActionListener(this);
		contents.addActionListener(this);
		downloads.addActionListener(this);
		update.addActionListener(this);
		fetchIcons.addActionListener(this);
		exportArchive.addActionListener(this);
		importArchive.addActionListener(this);
		addWindowListener(this);
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		URL img = getClass().getResource("/rsrc/icons/appicon.png"); //$NON-NLS-1$
		setIconImage(new ImageIcon(img, "").getImage()); //$NON-NLS-1$
		doMount(archive);
		pack();
		setSize(1024, 768);
		setVisible(true);
		all.add(this);
	}

	public void actionPerformed(ActionEvent event) {
		Object src = event.getSource();
		if (src == downloads) {
			views.setSelectedIndex(1);
		}
		if (src == search) {
			views.setSelectedIndex(0);
		}
		if (src == newArchive) {
			if (searchView != null) {
				searchView.doMessage(null);
			}
			doNewArchive();
		}
		if (src == quit) {
			if (searchView != null) {
				searchView.doMessage(null);
			}
			doQuit();
		}
		if (src == close) {
			if (searchView != null) {
				searchView.doMessage(null);
			}
			doClose();
		}
		if (src == open) {
			if (searchView != null) {
				searchView.doMessage(null);
			}
			doOpen();
		}
		if (src == contents) {
			if (searchView != null) {
				searchView.doMessage(null);
			}
			BrowseUtil.openUrl(Messages.getString("MainActivity.12")); //$NON-NLS-1$
		}
		if (src == update) {
			views.setSelectedIndex(0);
			searchView.doUpdateSearch();
		}
		if (src == fetchIcons) {
			Preferences prefs = Preferences.userNodeForPackage(getClass());
			prefs.putBoolean(FETCHICONS, fetchIcons.isSelected());
		}
		if (src == exportArchive) {
			searchView.doMessage(null);
			doExport();
		}
		if (src == importArchive) {
			searchView.doMessage(null);
			doImport();
		}
	}

	private void doImport() {
		try {
			String data = (String) Toolkit.getDefaultToolkit().getSystemClipboard()
					.getData(DataFlavor.stringFlavor);
			String prefix = "market://details?id="; //$NON-NLS-1$
			StringTokenizer st = new StringTokenizer(data);
			Vector<String> lst = new Vector<String>();
			int count = 0;
			while (st.hasMoreElements()) {
				// Lets first check the entire clipboard if its content is well formed.
				String url = st.nextToken();
				if (url.startsWith(prefix) && url.length() > prefix.length()) {
					// Let's keep it simple.
					String id = url.substring(prefix.length(), url.length());
					if (!lst.contains(id) && !archive.fileUnder(id, 0).getParentFile().exists()) {
						lst.add(id);
						count++;
					}
				}
			}

			// We got at least one new app id. Ask the user to confirm the list, then
			// create files.
			if (count > 0) {
				JList<String> all = new JList<String>(lst);
				all.addSelectionInterval(0, lst.size() - 1);
				if (JOptionPane
						.showConfirmDialog(
								this,
								new JScrollPane(all),
								Messages.getString("MainActivity.42"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null) == JOptionPane.OK_OPTION) {//$NON-NLS-1$
					int[] sel = all.getSelectedIndices();
					for (int idx : sel) {
						archive.fileUnder(all.getModel().getElementAt(idx), 0).getParentFile().mkdirs();
					}
					searchView.doMessage(Messages.getString("MainActivity.39")); //$NON-NLS-1$
				}
			}
			else {
				// Tell the user that no new items were found.
				searchView.doMessage(Messages.getString("MainActivity.43")); //$NON-NLS-1$
			}
		}
		catch (Exception e) {
			searchView.doMessage(Messages.getString("MainActivity.40")); //$NON-NLS-1$
			// e.printStackTrace();
		}
	}

	private void doExport() {
		List<String> lst = archive.list();
		StringBuilder sb = new StringBuilder();
		for (String s : lst) {
			sb.append("market://details?id="); //$NON-NLS-1$
			sb.append(s);
			sb.append("\n"); //$NON-NLS-1$
		}
		StringSelection stringSelection = new StringSelection(sb.toString());
		Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
		clpbrd.setContents(stringSelection, null);
		searchView.doMessage(Messages.getString("MainActivity.38")); //$NON-NLS-1$
	}

	private void doNewArchive() {
		String res = JOptionPane
				.showInputDialog(
						this,
						Messages.getString("MainActivity.32"), Messages.getString("MainActivity.31"), JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ //$NON-NLS-2$
		if (res != null && res.length() > 0) {
			File file = new File(App.getDir(App.ARCHIVEDIR), res);
			MainActivity ma = new MainActivity(new Archive(file));
			SwingUtilities.invokeLater(ma);
		}
	}

	private void doClose() {
		if (isDownloading()) {
			int result = JOptionPane
					.showConfirmDialog(
							getRootPane(),
							Messages.getString("MainActivity.13"), //$NON-NLS-1$
							Messages.getString("MainActivity.14"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$
			if (result == JOptionPane.NO_OPTION) {
				return;
			}
			for (int i = 0; i < downloadList.getComponentCount(); i++) {
				DownloadView dv = (DownloadView) downloadList.getComponent(i);
				dv.stopWorker();
			}
		}
		all.remove(this);
		setVisible(false);
		if (all.size() == 0) {
			System.exit(0);
		}
	}

	/**
	 * Must be called to connect to an archive.
	 * 
	 * @param archive
	 *          the archive to mount.
	 */
	protected void doMount(Archive archive) {
		this.archive = archive;
		archive.getRoot().mkdirs();
		new DownloadLogger(archive).clear();
		setTitle("Raccoon - " + archive.getRoot().getAbsolutePath()); //$NON-NLS-1$
		views.removeAll();
		if (archive.getAndroidId().length() == 0) {
			views.addTab(Messages.getString("MainActivity.16"), InitView.create(this, archive)); //$NON-NLS-1$
		}
		else {
			searchView = SearchView.create(this, archive);
			update.setEnabled(true);
			views.addTab(Messages.getString("MainActivity.17"), searchView); //$NON-NLS-1$
			views.addChangeListener(searchView);
			search.setEnabled(true);
			downloads.setEnabled(true);
			importArchive.setEnabled(true);
			exportArchive.setEnabled(true);
			downloadListScroll = new JScrollPane();
			downloadListScroll.setViewportView(downloadList);
			downloadListScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
			views.addTab(Messages.getString("MainActivity.18"), downloadListScroll); //$NON-NLS-1$
			Preferences prefs = Preferences.userNodeForPackage(getClass());
			prefs.put(LASTARCHIVE, archive.getRoot().getAbsolutePath());
			SwingUtilities.invokeLater(searchView);
		}
	}

	private void doOpen() {
		JFileChooser chooser = new JFileChooser(App.getDir(App.ARCHIVEDIR));
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		int ret = chooser.showOpenDialog(this);
		if (ret == JFileChooser.APPROVE_OPTION) {
			MainActivity ma = new MainActivity(new Archive(chooser.getSelectedFile()));
			SwingUtilities.invokeLater(ma);
		}
	}

	/**
	 * Trigger a download
	 * 
	 * @param d
	 *          packagename.
	 */
	public void doDownload(DownloadView d) {
		downloadList.add(d);
		d.startWorker();
		views.setSelectedComponent(downloadListScroll);
		Feedback.used(this);
	}

	private boolean isDownloading() {
		for (int i = 0; i < downloadList.getComponentCount(); i++) {
			DownloadView dv = (DownloadView) downloadList.getComponent(i);
			if (dv.isDownloading()) {
				return true;
			}
		}
		return false;
	}

	private void doQuit() {
		boolean ask = false;
		for (MainActivity ma : all) {
			if (ma.isDownloading()) {
				ask = true;
				break;
			}
		}

		if (ask) {
			int result = JOptionPane
					.showConfirmDialog(
							getRootPane(),
							Messages.getString("MainActivity.19"), //$NON-NLS-1$
							Messages.getString("MainActivity.20"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$
			if (result == JOptionPane.NO_OPTION) {
				return;
			}
		}
		for (MainActivity ma : all) {
			for (int i = 0; i < ma.downloadList.getComponentCount(); i++) {
				DownloadView dv = (DownloadView) ma.downloadList.getComponent(i);
				dv.stopWorker();
			}
		}
		System.exit(0);
	}

	public void windowClosing(WindowEvent arg0) {
		doClose();
	}

	public void windowActivated(WindowEvent arg0) {
	}

	public void windowClosed(WindowEvent arg0) {
	}

	public void windowDeactivated(WindowEvent arg0) {
	}

	public void windowDeiconified(WindowEvent arg0) {
	}

	public void windowIconified(WindowEvent arg0) {
	}

	public void windowOpened(WindowEvent arg0) {
	}

}