package de.robv.android.xposed.mods.appsettings.settings;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.graphics.Color;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.Switch;
import de.robv.android.xposed.mods.appsettings.R;


/**
 * Manages a popup dialog for editing the Permission Revoking settings for a package
 */
public class PermissionSettings {
	private Dialog dialog;

	private OnDismissListener onOkListener;
	private OnDismissListener onCancelListener;

	boolean revokeActive;
	private Set<String> disabledPerms;

	private List<PermissionInfo> permsList = new LinkedList<PermissionInfo>();

	/**
	 * Prepare a dialog for editing the permissions for the supplied package,
	 * with the provided owner activity and initial settings
	 */
	public PermissionSettings(Activity owner, String pkgName, boolean revoking, Set<String> disabledPermissions) throws NameNotFoundException {
		dialog = new Dialog(owner);
		dialog.setContentView(R.layout.permissions_dialog);
		dialog.setTitle("Permissions");
		dialog.setCancelable(true);
		dialog.setOwnerActivity(owner);

		revokeActive = revoking;
		if (disabledPermissions != null)
			disabledPerms = new HashSet<String>(disabledPermissions);
		else
			disabledPerms = new HashSet<String>();

		Switch swtRevoke = (Switch) dialog.findViewById(R.id.swtRevokePerms);
		swtRevoke.setChecked(revokeActive);

		// Load the list of permissions for the package and present them
		loadPermissionsList(pkgName);

		final PermissionsListAdapter appListAdapter = new PermissionsListAdapter(owner, permsList, disabledPerms, true);
		appListAdapter.setCanEdit(revokeActive);
		((ListView) dialog.findViewById(R.id.lstPermissions)).setAdapter(appListAdapter);

		// Track changes to the Revoke checkbox to lock or unlock the list of
		// permissions
		swtRevoke.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				revokeActive = isChecked;
				dialog.findViewById(R.id.lstPermissions).setBackgroundColor(revokeActive ? Color.BLACK : Color.DKGRAY);
				appListAdapter.setCanEdit(revokeActive);
			}
		});
		dialog.findViewById(R.id.lstPermissions).setBackgroundColor(revokeActive ? Color.BLACK : Color.DKGRAY);

		((Button) dialog.findViewById(R.id.btnPermsCancel)).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (onCancelListener != null)
					onCancelListener.onDismiss(PermissionSettings.this);
				dialog.dismiss();
			}
		});
		((Button) dialog.findViewById(R.id.btnPermsOk)).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (onOkListener != null)
					onOkListener.onDismiss(PermissionSettings.this);
				dialog.dismiss();
			}
		});
	}

	/**
	 * Display the editor dialog
	 */
	public void display() {
		dialog.show();
	}

	/**
	 * Register a listener to be invoked when the editor is dismissed with the
	 * Ok button
	 */
	public void setOnOkListener(OnDismissListener listener) {
		onOkListener = listener;
	}

	/**
	 * Register a listener to be invoked when the editor is dismissed with the
	 * Cancel button
	 */
	public void setOnCancelListener(OnDismissListener listener) {
		onCancelListener = listener;
	}

	/**
	 * Get the state of the Active switch
	 */
	public boolean getRevokeActive() {
		return revokeActive;
	}

	/**
	 * Get the list of permissions in the disabled state
	 */
	public Set<String> getDisabledPermissions() {
		return new HashSet<String>(disabledPerms);
	}

	/*
	 * Populate the list of permissions requested by this package
	 */
	@SuppressLint("DefaultLocale")
	private void loadPermissionsList(String pkgName) throws NameNotFoundException {
		permsList.clear();

		PackageManager pm = dialog.getContext().getPackageManager();
		PackageInfo pkgInfo = pm.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS);
		if (pkgInfo.sharedUserId != null) {
			Switch swtRevoke = (Switch) dialog.findViewById(R.id.swtRevokePerms);
			swtRevoke.setEnabled(false);
			swtRevoke.setChecked(false);
			swtRevoke.setText("Shared packages not yet supported");
			swtRevoke.setTextColor(Color.RED);
		}
		String[] permissions = pkgInfo.requestedPermissions;
		if (permissions == null) {
			permissions = new String[0];
		}
		for (String perm : permissions) {
			try {
				permsList.add(pm.getPermissionInfo(perm, 0));
			} catch (NameNotFoundException e) {
				PermissionInfo unknownPerm = new PermissionInfo();
				unknownPerm.name = perm;
				permsList.add(unknownPerm);
			}
		}

		Collections.sort(permsList, new Comparator<PermissionInfo>() {
			@Override
			public int compare(PermissionInfo lhs, PermissionInfo rhs) {
				if (lhs.name == null) {
					return -1;
				} else if (rhs.name == null) {
					return 1;
				} else {
					return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
				}
			}
		});
	}

	/**
	 * Interface for the listeners of Ok/Cancel dismiss actions
	 */
	public static interface OnDismissListener {

		public abstract void onDismiss(PermissionSettings obj);
	}

}

@@ -4690,113 +4690,38 @@
 .set
-Enabled(false);%0D%0A%09%09%09swtRevoke.setChecked(false);%0D%0A%09%09%09swtRevoke.setText(%22Shared packages not yet supported
+Text(%22WARNING: Shared package!
 %22);%0D

Allow revoking permissions to shared package (experimental). WARNING: Revoking permissions on shared packages might create non-obvious problems, since other packages might depend on these and it's not evident from the UI which ones are they.