package de.onyxbits.raccoon.gui;

import java.awt.Event;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultCaret;

import com.akdeniz.googleplaycrawler.GooglePlay.DocV2;

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

/**
 * Displays and handles a single search result.
 * 
 * @author patrick
 * 
 */
public class ResultView extends JPanel implements ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private DocV2 doc;

	private JButton download;

	private JButton gplay;

	private JToggleButton details;

	private JToggleButton permissions;

	private SearchView searchView;

	private JEditorPane entry;

	private HashMap<String, Object> model;

	private static Icon iconNetwork;
	private static Icon iconIap;
	private static Icon iconLocation;
	private static Icon iconMicrophone;
	private static Icon iconPersonal;
	private static Icon iconPhone;
	private static Icon iconCamera;
	private static Icon iconSystem;
	private static Icon iconStorage;
	private static Icon iconLicenseCheck;
	private static Icon iconDownload;

	static {
		Class<?> clazz = new Object().getClass();
		iconNetwork = new ImageIcon(clazz.getResource("/rsrc/badges/wi-fi-outline.png")); //$NON-NLS-1$
		iconIap = new ImageIcon(clazz.getResource("/rsrc/badges/shopping-cart.png")); //$NON-NLS-1$
		iconLocation = new ImageIcon(clazz.getResource("/rsrc/badges/location-outline.png")); //$NON-NLS-1$
		iconMicrophone = new ImageIcon(clazz.getResource("/rsrc/badges/microphone-outline.png")); //$NON-NLS-1$
		iconPersonal = new ImageIcon(clazz.getResource("/rsrc/badges/contacts.png")); //$NON-NLS-1$
		iconPhone = new ImageIcon(clazz.getResource("/rsrc/badges/phone-outline.png")); //$NON-NLS-1$
		iconCamera = new ImageIcon(clazz.getResource("/rsrc/badges/camera-outline.png")); //$NON-NLS-1$
		iconSystem = new ImageIcon(clazz.getResource("/rsrc/badges/spanner-outline.png")); //$NON-NLS-1$
		iconStorage = new ImageIcon(clazz.getResource("/rsrc/badges/folder.png")); //$NON-NLS-1$
		iconLicenseCheck = new ImageIcon(clazz.getResource("/rsrc/badges/key-outline.png")); //$NON-NLS-1$
		iconDownload = new ImageIcon(clazz.getResource("/rsrc/icons/download.png")); //$NON-NLS-1$
	}

	/**
	 * Construct a new app listing
	 * 
	 * @param searchView
	 *          the searchview that will handle button presses.
	 * 
	 * @param doc
	 *          the source from which to draw app info
	 */
	private ResultView(SearchView searchView, DocV2 doc) {
		this.doc = doc;
		this.searchView = searchView;

		model = new HashMap<String, Object>();
		model.put("i18n_installs", Messages.getString("ResultView.1")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_rating", Messages.getString("ResultView.3")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_price", Messages.getString("ResultView.5")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_date", Messages.getString("ResultView.7")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_version", Messages.getString("ResultView.2")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_size", Messages.getString("ResultView.9")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_permissions", Messages.getString("ResultView.27")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_permissions_none", Messages.getString("ResultView.22")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("i18n_changelog", Messages.getString("ResultView.4")); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("title", doc.getTitle()); //$NON-NLS-1$
		model.put("installs", doc.getDetails().getAppDetails().getNumDownloads()); //$NON-NLS-1$
		model.put("rating", String.format("%.2f", doc.getAggregateRating().getStarRating())); //$NON-NLS-1$ //$NON-NLS-2$
		model.put("package", doc.getBackendDocid()); //$NON-NLS-1$
		model.put("author", doc.getCreator()); //$NON-NLS-1$
		model.put("price", doc.getOffer(0).getFormattedAmount()); //$NON-NLS-1$
		model.put("date", doc.getDetails().getAppDetails().getUploadDate()); //$NON-NLS-1$
		model.put("size", Archive.humanReadableByteCount(doc.getDetails().getAppDetails() //$NON-NLS-1$
				.getInstallationSize(), true));
		File icon = SearchWorker.getImageCacheFile(doc.getBackendDocid(), 4);
		if (icon.exists()) {
			model.put("icon", icon.toURI()); //$NON-NLS-1$
		}
		else {
			model.put("icon", getClass().getResource("/rsrc/icons/icon_missing.png").toString());
		}

		JPanel buttons = new JPanel();
		buttons.setLayout(new GridLayout(0, 1, 0, 4));
		buttons.setOpaque(false);
		download = new JButton(Messages.getString("ResultView.25"), iconDownload); //$NON-NLS-1$
		gplay = new JButton(Messages.getString("ResultView.26")); //$NON-NLS-1$
		details = new JToggleButton(Messages.getString("ResultView.6")); //$NON-NLS-1$
		permissions = new JToggleButton(Messages.getString("ResultView.27")); //$NON-NLS-1$
		buttons.add(download);
		buttons.add(gplay);
		buttons.add(details);
		buttons.add(permissions);
		entry = new HypertextPane(TmplTool.transform("app.html", model)); //$NON-NLS-1$
		entry.setMargin(new Insets(10, 10, 10, 10));
		entry.addHyperlinkListener(new BrowseUtil());
		// Keep enclosing scrollpanes steady
		DefaultCaret caret = (DefaultCaret) entry.getCaret();
		caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
		JPanel outer = new JPanel(); // Needed to simplify the layout code.
		outer.setOpaque(false);
		JPanel container = new JPanel();
		container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
		container.setOpaque(false);
		container.add(buttons);
		container.add(Box.createVerticalStrut(10));
		container.add(createBadges(doc.getDetails().getAppDetails().getPermissionList()));
		container.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		outer.add(container);
		JSeparator sep = new JSeparator(JSeparator.VERTICAL);
		sep.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		add(outer);
		add(sep);
		add(entry);
	}

	private JPanel createBadges(List<String> perms) {
		JPanel ret = new JPanel();
		ret.setLayout(new GridLayout(0, 3));
		ret.setOpaque(false);
		String[][] groups = { { "android.permission.INTERNET", //$NON-NLS-1$
				"android.permission.ACCESS_NETWORK_STATE", //$NON-NLS-1$
				"android.permission.CHANGE_NETWORK_STATE", //$NON-NLS-1$
				"android.permission.CHANGE_WIFI_MULTICAST_STATE", //$NON-NLS-1$
				"android.permission.CHANGE_WIFI_STATE", //$NON-NLS-1$
				"android.permission.ACCESS_WIFI_STATE", //$NON-NLS-1$
				"android.permission.BIND_VPN_SERVICE" }, //$NON-NLS-1$
				{ "com.android.vending.BILLING" }, //$NON-NLS-1$
				{ "com.android.vending.CHECK_LICENSE" }, //$NON-NLS-1$
				{ "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION" }, //$NON-NLS-1$ //$NON-NLS-2$
				{ "android.permission.RECORD_AUDIO" }, //$NON-NLS-1$
				{ "android.permission.CAMERA" }, //$NON-NLS-1$
				{ "android.permission.CALL_PHONE", //$NON-NLS-1$
						"android.permission.PROCESS_OUTGOING_CALLS", //$NON-NLS-1$
						"android.permission.READ_CALL_LOG", //$NON-NLS-1$
						"android.permission.READ_PHONE_STATE", //$NON-NLS-1$
						"android.permission.READ_SMS", //$NON-NLS-1$
						"android.permission.RECEIVE_SMS", //$NON-NLS-1$
						"android.permission.SEND_SMS", //$NON-NLS-1$
						"android.permission.USE_SIP", //$NON-NLS-1$
						"android.permission.WRITE_CALL_LOG", //$NON-NLS-1$
						"android.permission.WRITE_SMS" }, //$NON-NLS-1$
				{ "android.permission.BIND_DEVICE_ADMIN", //$NON-NLS-1$
						"android.permission.CHANGE_CONFIGURATION", //$NON-NLS-1$
						"android.permission.DISABLE_KEYGUARD", //$NON-NLS-1$
						"android.permission.EXPAND_STATUS_BAR", //$NON-NLS-1$
						"android.permission.GET_TASKS", //$NON-NLS-1$
						"android.permission.KILL_BACKGROUND_PROCESSES", //$NON-NLS-1$
						"android.permission.MODIFY_AUDIO_SETTINGS", //$NON-NLS-1$
						"android.permission.RECEIVE_BOOT_COMPLETED", //$NON-NLS-1$
						"android.permission.REORDER_TASKS", //$NON-NLS-1$
						"android.permission.SYSTEM_ALERT_WINDOW", //$NON-NLS-1$
						"android.permission.SET_WALLPAPER", //$NON-NLS-1$
						"com.android.launcher.permission.UNINSTALL_SHORTCUT" }, //$NON-NLS-1$
				{ "android.permission.GET_ACCOUNTS", //$NON-NLS-1$
						"android.permission.READ_PHONE_STATE", //$NON-NLS-1$
						"android.permission.GLOBAL_SEARCH", //$NON-NLS-1$
						"android.permission.MANAGE_DOCUMENTS", //$NON-NLS-1$
						"android.permission.READ_CALENDAR", //$NON-NLS-1$
						"android.permission.READ_CALL_LOG", //$NON-NLS-1$
						"android.permission.READ_CONTACTS", //$NON-NLS-1$
						"com.android.browser.permission.READ_HISTORY_BOOKMARKS", //$NON-NLS-1$
						"android.permission.READ_LOGS", //$NON-NLS-1$
						"android.permission.READ_USER_DICTIONARY", //$NON-NLS-1$
						"android.permission.USE_CREDENTIALS", //$NON-NLS-1$
						"android.permission.WRITE_CALENDAR", //$NON-NLS-1$
						"android.permission.WRITE_CALL_LOG", //$NON-NLS-1$
						"android.permission.WRITE_CONTACTS", //$NON-NLS-1$
						"com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", //$NON-NLS-1$
						"android.permission.WRITE_SOCIAL_STREAM", //$NON-NLS-1$
						"android.permission.READ_PROFILE", //$NON-NLS-1$
						"android.permission.USE_CREDENTIALS", //$NON-NLS-1$
						"android.permission.WRITE_USER_DICTIONARY" }, //$NON-NLS-1$
				{ "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" } }; //$NON-NLS-1$ //$NON-NLS-2$
		for (int x = 0; x < groups.length; x++) {
			for (int y = 0; y < groups[x].length; y++) {
				if (x == 0 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconNetwork);
					lbl.setToolTipText(Messages.getString("ResultView.84")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 1 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconIap);
					lbl.setToolTipText(Messages.getString("ResultView.85")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 2 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconLicenseCheck);
					lbl.setToolTipText(Messages.getString("ResultView.0")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 3 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconLocation);
					lbl.setToolTipText(Messages.getString("ResultView.86")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 4 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconMicrophone);
					lbl.setToolTipText(Messages.getString("ResultView.87")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 5 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconCamera);
					lbl.setToolTipText(Messages.getString("ResultView.88")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 6 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconPhone);
					lbl.setToolTipText(Messages.getString("ResultView.89")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 7 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconSystem);
					lbl.setToolTipText(Messages.getString("ResultView.90")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 8 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconPersonal);
					lbl.setToolTipText(Messages.getString("ResultView.91")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
				if (x == 9 && perms.contains(groups[x][y])) {
					JLabel lbl = new JLabel(iconStorage);
					lbl.setToolTipText(Messages.getString("ResultView.92")); //$NON-NLS-1$
					ret.add(lbl);
					break;
				}
			}
		}
		return ret;
	}

	public static ResultView create(SearchView searchView, DocV2 doc) {
		ResultView ret = new ResultView(searchView, doc);
		ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
		ret.download.addActionListener(ret);
		ret.gplay.addActionListener(ret);
		ret.permissions.addActionListener(ret);
		ret.details.addActionListener(ret);
		return ret;
	}

	public void actionPerformed(ActionEvent event) {
		Object src = event.getSource();
		if (src == download) {
			DownloadView d = DownloadView.create(searchView.getArchive(), doc);
			searchView.doDownload(d);
		}
		if (src == details) {
			if ((event.getModifiers() & Event.SHIFT_MASK) == Event.SHIFT_MASK) {
				// This is indented for debugging!
				entry.setContentType("text/plain"); //$NON-NLS-1$
				entry.setText(doc.toString());
			}
			else {
				doToggleDetails();
			}
		}
		if (src == gplay) {
			BrowseUtil.openUrl(doc.getShareUrl());
			SwingUtilities.invokeLater(searchView); // Re - focus
		}
		if (src == permissions) {
			doTogglePermissions();
		}
	}

	private void doTogglePermissions() {
		if (model.containsKey("showpermissions")) { //$NON-NLS-1$
			model.remove("permissions_list"); //$NON-NLS-1$
			model.remove("showpermissions"); //$NON-NLS-1$
		}
		else {
			List<String> perms = doc.getDetails().getAppDetails().getPermissionList();
			if (perms.size() > 0) {
				ArrayList<String> sortMe = new ArrayList<String>(perms);
				Collections.sort(sortMe);
				model.put("permissions_list", sortMe); //$NON-NLS-1$
			}
			model.put("showpermissions", true);
		}
		entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
		SwingUtilities.invokeLater(searchView);
	}

	private void doToggleDetails() {
		if (model.containsKey("description")) { //$NON-NLS-1$
			model.remove("version"); //$NON-NLS-1$
			model.remove("vcode"); //$NON-NLS-1$
			model.remove("email"); //$NON-NLS-1$
			model.remove("website"); //$NON-NLS-1$
			model.remove("description"); //$NON-NLS-1$
			model.remove("changelog"); //$NON-NLS-1$
			entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
			SwingUtilities.invokeLater(searchView);
		}
		else {
			details.setEnabled(false);
			new DetailsWorker(searchView.getArchive(), this, doc.getBackendDocid()).execute();
		}
	}

	protected void updateEntry(DocV2 docV2) {
		details.setEnabled(true);
		doc = docV2;
		model.put("version", doc.getDetails().getAppDetails().getVersionString()); //$NON-NLS-1$
		model.put("vcode", doc.getDetails().getAppDetails().getVersionCode()); //$NON-NLS-1$
		model.put("website", doc.getDetails().getAppDetails().getDeveloperWebsite()); //$NON-NLS-1$
		model.put("email", doc.getDetails().getAppDetails().getDeveloperEmail()); //$NON-NLS-1$
		model.put("description", doc.getDescriptionHtml()); //$NON-NLS-1$
		model.put("changelog", doc.getDetails().getAppDetails().getRecentChangesHtml()); //$NON-NLS-1$
		entry.setText(TmplTool.transform("app.html", model)); //$NON-NLS-1$
		SwingUtilities.invokeLater(searchView);
	}
}