package guard.api.sensitive.ui.sapiguard.hookedapis;

import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import guard.api.sensitive.ui.sapiguard.XHook;
import guard.api.sensitive.ui.sapiguard.utils.Util;
import guard.api.sensitive.ui.sapiguard.utils.XParam;

public class XContentResolver extends XHook {
	private Methods mMethod;
	private boolean mClient;
	private String mClassName;

	private XContentResolver(Methods method, String restrictionName, String className) {
		super(restrictionName, method.name().replace("Srv_", ""), method.name());
		mMethod = method;
		if (className == null)
			mClassName = "com.android.server.content.ContentService";
		else
			mClassName = className;
	}

	private XContentResolver(Methods method, String restrictionName, boolean client) {
		super(restrictionName, method.name(), null);
		mMethod = method;
		mClient = client;
		mClassName = null;
	}

	public String getClassName() {
		if (mClassName == null)
			return (mClient ? "android.content.ContentProviderClient" : "android.content.ContentResolver");
		else
			return mClassName;
	}

	// @formatter:off

	// public static SyncInfo getCurrentSync()
	// static List<SyncInfo> getCurrentSyncs()
	// static SyncAdapterType[] getSyncAdapterTypes()

	// final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
	// final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode, CancellationSignal cancellationSignal)
	// final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode, CancellationSignal cancellationSignal)
	// final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
	// final InputStream openInputStream(Uri uri)
	// final OutputStream openOutputStream(Uri uri)
	// final OutputStream openOutputStream(Uri uri, String mode)
	// final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, String mimeType, Bundle opts, CancellationSignal cancellationSignal)
	// final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, String mimeType, Bundle opts)

	// AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
	// AssetFileDescriptor openAssetFile(Uri url, String mode)
	// ParcelFileDescriptor openFile(Uri url, String mode)
	// ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)

	// public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder)
	// public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)

	// https://developers.google.com/gmail/android/
	// http://developer.android.com/reference/android/content/ContentResolver.html
	// http://developer.android.com/reference/android/content/ContentProviderClient.html

	// http://developer.android.com/reference/android/provider/Contacts.People.html
	// http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html
	// http://developer.android.com/reference/android/provider/ContactsContract.Data.html
	// http://developer.android.com/reference/android/provider/ContactsContract.PhoneLookup.html
	// http://developer.android.com/reference/android/provider/ContactsContract.Profile.html
	// http://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html

	// frameworks/base/core/java/android/content/ContentResolver.java

	// public List<SyncInfo> getCurrentSyncs()
	// public void registerContentObserver(android.net.Uri uri, boolean notifyForDescendants, android.database.IContentObserver observer, int userHandle)
	// public void unregisterContentObserver(android.database.IContentObserver observer)
	// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/content/ContentService.java
	// public List<android.content.SyncInfo> getCurrentSyncsAsUser(int userId)
	// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.0_r1/android/content/IContentService.java

	// public Bundle call(String method, String request, Bundle args)
	// http://developer.android.com/reference/android/provider/Settings.html
	// http://developer.android.com/reference/android/provider/Settings.Global.html
	// http://developer.android.com/reference/android/provider/Settings.Secure.html
	// http://developer.android.com/reference/android/provider/Settings.System.html
	// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/com/android/providers/settings/SettingsProvider.java

	// @formatter:on

	// @formatter:off
	private enum Methods {
		getCurrentSync, getCurrentSyncs, getSyncAdapterTypes,
		openAssetFile, openFile, openAssetFileDescriptor, openFileDescriptor, openInputStream, openOutputStream, openTypedAssetFileDescriptor,
		query, Srv_call, Srv_query,
		Srv_getCurrentSyncs, Srv_getCurrentSyncsAsUser
	};
	// @formatter:on

	// @formatter:off
	public static List<String> cProviderClassName = Arrays.asList(new String[] {
		"com.android.providers.downloads.DownloadProvider",
		"com.android.providers.calendar.CalendarProvider2",
		"com.android.providers.contacts.CallLogProvider",
		"com.android.providers.contacts.ContactsProvider2",
		"com.google.android.gm.provider.PublicContentProvider",
		"com.google.android.gsf.gservices.GservicesProvider",
		"com.android.providers.telephony.MmsProvider",
		"com.android.providers.telephony.MmsSmsProvider",
		"com.android.providers.telephony.SmsProvider",
		"com.android.providers.telephony.TelephonyProvider",
		"com.android.providers.userdictionary.UserDictionaryProvider",
		"com.android.providers.settings.SettingsProvider",
	});
	// @formatter:on

	public static List<XHook> getPackageInstances(String packageName, ClassLoader loader) {
		if (packageName.startsWith("com.android.browser.provider"))
			try {
				Class.forName("com.android.browser.provider.BrowserProviderProxy", false, loader);
				return getInstances("com.android.browser.provider.BrowserProviderProxy");
			} catch (ClassNotFoundException ignored) {
				try {
					Class.forName("com.android.browser.provider.BrowserProvider2", false, loader);
					return getInstances("com.android.browser.provider.BrowserProvider2");
				} catch (ClassNotFoundException ignored2) {
					Util.log(null, Log.ERROR, "Browser provider not found, package=" + packageName);
					return new ArrayList<XHook>();
				}
			}

		else if (packageName.startsWith("com.android.email.provider"))
			try {
				Class.forName("com.android.email.provider.EmailProvider", false, loader);
				return getInstances("com.android.email.provider.EmailProvider");
			} catch (ClassNotFoundException ignored) {
				Util.log(null, Log.WARN, "E-mail provider not found, package=" + packageName);
				return new ArrayList<XHook>();
			}

		else if (packageName.startsWith("com.google.android.gm.provider"))
			try {
				Class.forName("com.google.android.gm.provider.PublicContentProvider", false, loader);
				return getInstances("com.google.android.gm.provider.PublicContentProvider");
			} catch (ClassNotFoundException ignored) {
				Util.log(null, Log.WARN, "G-mail provider not found, package=" + packageName);
				return new ArrayList<XHook>();
			}

		else {
			List<XHook> listHook = new ArrayList<XHook>();
			for (String className : cProviderClassName)
				if (className.startsWith(packageName))
					listHook.addAll(getInstances(className));
			return listHook;
		}
	}

	private static List<XHook> getInstances(String className) {
		List<XHook> listHook = new ArrayList<XHook>();

		if ("com.android.providers.settings.SettingsProvider".equals(className))
			listHook.add(new XContentResolver(Methods.Srv_call, null, className));
		else
			listHook.add(new XContentResolver(Methods.Srv_query, null, className));

		return listHook;
	}

	public static List<XHook> getInstances(boolean server) {
		List<XHook> listHook = new ArrayList<XHook>();

		if (server) {
			listHook.add(new XContentResolver(Methods.Srv_query, null, "com.android.internal.telephony.IccProvider"));

//			listHook.add(new XContentResolver(Methods.Srv_getCurrentSyncs, PrivacyManager.cAccounts, null));
//			listHook.add(new XContentResolver(Methods.Srv_getCurrentSyncsAsUser, PrivacyManager.cAccounts, null));
		} else {
//			listHook.add(new XContentResolver(Methods.getCurrentSync, PrivacyManager.cAccounts, false));
//			listHook.add(new XContentResolver(Methods.getCurrentSyncs, PrivacyManager.cAccounts, false));
//			listHook.add(new XContentResolver(Methods.getSyncAdapterTypes, PrivacyManager.cAccounts, false));
//
//			listHook.add(new XContentResolver(Methods.openAssetFileDescriptor, PrivacyManager.cStorage, false));
//			listHook.add(new XContentResolver(Methods.openFileDescriptor, PrivacyManager.cStorage, false));
//			listHook.add(new XContentResolver(Methods.openInputStream, PrivacyManager.cStorage, false));
//			listHook.add(new XContentResolver(Methods.openOutputStream, PrivacyManager.cStorage, false));
//			listHook.add(new XContentResolver(Methods.openTypedAssetFileDescriptor, PrivacyManager.cStorage, false));
//
//			listHook.add(new XContentResolver(Methods.openAssetFile, PrivacyManager.cStorage, true));
//			listHook.add(new XContentResolver(Methods.openFile, PrivacyManager.cStorage, true));
//			listHook.add(new XContentResolver(Methods.openTypedAssetFileDescriptor, PrivacyManager.cStorage, true));

			listHook.add(new XContentResolver(Methods.query, null, false));
			listHook.add(new XContentResolver(Methods.query, null, true));
		}

		return listHook;
	}


	@Override
	protected void before(XParam param) throws Throwable {
		switch (mMethod) {
			case query:
			case Srv_query:
				break;
		}
	}

	@Override
	protected void after(XParam param) throws Throwable {

	}


}
