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

import android.os.Binder;

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

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

public class XAccountManager extends XHook {
    private Methods mMethod;
    private String mClassName;
    private static final String cClassName = "android.accounts.AccountManager";

    private XAccountManager(Methods method, String restrictionName) {
        super(restrictionName, method.name().replace("Srv_", ""), method.name());
        mMethod = method;
        mClassName = "com.android.server.accounts.AccountManagerService";
    }

    private XAccountManager(Methods method, String restrictionName, String className) {
        super(restrictionName, method.name(), null);
        mMethod = method;
        mClassName = className;
    }

    public String getClassName() {
        return mClassName;
    }

    // @formatter:off

    // public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener, Handler handler, boolean updateImmediately)
    // public String blockingGetAuthToken(Account account, String authTokenType, boolean notifyAuthFailure)
    // public Account[] getAccounts()
    // public Account[] getAccountsByType(String type)
    // public Account[] getAccountsByTypeForPackage(String type, String packageName)
    // public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(final String type, final String[] features, AccountManagerCallback<Account[]> callback, Handler handler)
    // public AuthenticatorDescription[] getAuthenticatorTypes()
    // public AccountManagerFuture<Bundle> getAuthToken(final Account account, final String authTokenType, final Bundle options, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler)
    // public AccountManagerFuture<Bundle> getAuthToken(final Account account, final String authTokenType, final boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler)
    // public AccountManagerFuture<Bundle> getAuthToken(final Account account, final String authTokenType, final Bundle options, final boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler)
    // public AccountManagerFuture<Bundle> getAuthTokenByFeatures(final String accountType, final String authTokenType, final String[] features, final Activity activity, final Bundle addAccountOptions, final Bundle getAuthTokenOptions, final AccountManagerCallback<Bundle> callback, final Handler handler)
    // public AccountManagerFuture<Boolean> hasFeatures(final Account account, final String[] features, AccountManagerCallback<Boolean> callback, Handler handler)
    // public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener)
    // frameworks/base/core/java/android/accounts/AccountManager.java
    // http://developer.android.com/reference/android/accounts/AccountManager.html

    // @formatter:on

    // @formatter:off

    // public android.accounts.Account[] getAccounts(java.lang.String accountType) throws android.os.RemoteException;
    // public android.accounts.Account[] getAccountsAsUser(java.lang.String accountType, int userId) throws android.os.RemoteException;
    // public void getAccountsByFeatures(android.accounts.IAccountManagerResponse response, java.lang.String accountType, java.lang.String[] features) throws android.os.RemoteException;
    // public android.accounts.Account[] getAccountsForPackage(java.lang.String packageName, int uid)
    // public android.accounts.Account[] getSharedAccountsAsUser(int userId) throws android.os.RemoteException;
    // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/com/android/server/accounts/AccountManagerService.java
    // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.0_r1/android/accounts/IAccountManager.java

    // @formatter:on

    // @formatter:off
    private enum Methods {
        addOnAccountsUpdatedListener,
        blockingGetAuthToken,
        getAccounts, getAccountsByType, getAccountsByTypeForPackage, getAccountsByTypeAndFeatures, getAuthenticatorTypes,
        getAuthToken, getAuthTokenByFeatures,
        hasFeatures,
        removeOnAccountsUpdatedListener,

        Srv_getAccounts,
        Srv_getAccountsAsUser,
        Srv_getAccountsByFeatures,
        Srv_getAccountsForPackage,
        Srv_getSharedAccountsAsUser
    }

    ;
    // @formatter:on

    public static List<XHook> getInstances(String className, boolean server) {
        List<XHook> listHook = new ArrayList<XHook>();
        if (!cClassName.equals(className)) {
            if (className == null)
                className = cClassName;

            if (server) {
                listHook.add(new XAccountManager(Methods.Srv_getAccounts, PrivacyManager.cAccounts));
                listHook.add(new XAccountManager(Methods.Srv_getAccountsAsUser, PrivacyManager.cAccounts));
                listHook.add(new XAccountManager(Methods.Srv_getAccountsByFeatures, PrivacyManager.cAccounts));
                listHook.add(new XAccountManager(Methods.Srv_getAccountsForPackage, PrivacyManager.cAccounts));
                listHook.add(new XAccountManager(Methods.Srv_getSharedAccountsAsUser, PrivacyManager.cAccounts));
            } else {
                listHook.add(new XAccountManager(Methods.addOnAccountsUpdatedListener, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.blockingGetAuthToken, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAccounts, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAccountsByType, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAccountsByTypeForPackage, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAccountsByTypeAndFeatures, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAuthenticatorTypes, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAuthToken, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.getAuthTokenByFeatures, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.hasFeatures, PrivacyManager.cAccounts, className));
                listHook.add(new XAccountManager(Methods.removeOnAccountsUpdatedListener, null, className));
            }
        }
        return listHook;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void before(XParam param) throws Throwable {
        switch (mMethod) {
            case addOnAccountsUpdatedListener:
            case blockingGetAuthToken:
            case getAccounts:
            case getAccountsByType:
            case getAccountsByTypeForPackage:
                // Do nothing
            case getAccountsByTypeAndFeatures:
            case getAuthenticatorTypes:
            case getAuthToken:
            case getAuthTokenByFeatures:
            case hasFeatures:
            case removeOnAccountsUpdatedListener:
            case Srv_getAccounts:
            case Srv_getAccountsAsUser:
            case Srv_getAccountsForPackage:
            case Srv_getAccountsByFeatures:
            case Srv_getSharedAccountsAsUser:
                // Do nothing
                break;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void after(XParam param) throws Throwable {
        int uid = Binder.getCallingUid();

        switch (mMethod) {
            case addOnAccountsUpdatedListener:
                // Do nothing
                break;

            case blockingGetAuthToken:

            case getAccounts:


            case getAccountsByType:
            case getAccountsByTypeForPackage:

            case getAccountsByTypeAndFeatures:

            case getAuthenticatorTypes:


            case getAuthToken:


            case getAuthTokenByFeatures:


            case hasFeatures:


            case removeOnAccountsUpdatedListener:
                // Do nothing
                break;

            case Srv_getAccounts:
            case Srv_getAccountsAsUser:
            case Srv_getAccountsForPackage:
            case Srv_getSharedAccountsAsUser:

            case Srv_getAccountsByFeatures:
                // Do nothing
                break;
        }
    }


}
