package com.unit.util;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

import java.util.concurrent.LinkedBlockingQueue;

public class AdvertisingIdClient {
    private static final String TAG = "AdvertisingIdClient";
    public interface OnGetGaidListener {
        void onGetGaid(String gaid);
    }

    public static String getGaid(Context context){
        AdInfo adInfo = getAdvertisingIdInfo(context);
        if(adInfo == null){
            return null;
        }
        return adInfo.getId();
    }

    public static void getGaid(Context context, OnGetGaidListener listener) {
        AdInfo info = getAdvertisingIdInfo(context);
        if (listener != null) {
            listener.onGetGaid(info != null ? info.advertisingId : "");
        }
    }

    private static AdInfo getAdvertisingIdInfo(Context context) {
        if(context == null){
            Log.e(TAG, "getAdvertisingIdInfo error, context invalid");
            return null;
        }

        if (Looper.myLooper() == Looper.getMainLooper()) {
            Log.e(TAG, "getAdvertisingIdInfo error, cannot be called from the main thread");
            return null;
        }

        AdvertisingConnection connection = null;
        try {
            PackageManager pm = context.getPackageManager();
            pm.getPackageInfo("com.android.vending", 0);

            connection = new AdvertisingConnection();
            Intent intent = new Intent(
                    "com.google.android.gms.ads.identifier.service.START");
            intent.setPackage("com.google.android.gms");
            if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
                AdvertisingInterface adInterface = new AdvertisingInterface(
                        connection.getBinder());
                Log.d(TAG,"GAID:" + adInterface.getId());
                return new AdInfo(adInterface.getId(), adInterface.isLimitAdTrackingEnabled(true));
            }
        } catch (Exception e) {
            Log.e(TAG,"getAdvertisingIdInfo exception,"+e.getMessage());
            return null;
        } finally {
            if (connection != null) {
                context.unbindService(connection);
            }
        }
        return null;
    }

    private static final class AdvertisingConnection implements ServiceConnection {
        boolean retrieved = false;
        private final LinkedBlockingQueue<IBinder> queue = new LinkedBlockingQueue<IBinder>(1);

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                this.queue.put(service);
            } catch (Throwable e) {
                Log.e(TAG, "AdvertisingConnection onServiceConnected exception,"+e.getMessage());
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        IBinder getBinder() throws InterruptedException {
            if (this.retrieved) {
                throw new IllegalStateException();
            }
            this.retrieved = true;
            return this.queue.take();
        }
    }

    private static final class AdvertisingInterface implements IInterface {
        private IBinder binder;

        AdvertisingInterface(IBinder pBinder) {
            binder = pBinder;
        }

        @Override
        public IBinder asBinder() {
            return binder;
        }

        public String getId() throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            String id;
            try {
                data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
                binder.transact(1, data, reply, 0);
                reply.readException();
                id = reply.readString();
            } finally {
                reply.recycle();
                data.recycle();
            }
            return id;
        }

        boolean isLimitAdTrackingEnabled(boolean paramBoolean)
                throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            boolean limitAdTracking;
            try {
                data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
                data.writeInt(paramBoolean ? 1 : 0);
                binder.transact(2, data, reply, 0);
                reply.readException();
                limitAdTracking = 0 != reply.readInt();
            } finally {
                reply.recycle();
                data.recycle();
            }
            return limitAdTracking;
        }
    }

    private static final class AdInfo {
        private final String advertisingId;
        private final boolean limitAdTrackingEnabled;

        AdInfo(String advertisingId, boolean limitAdTrackingEnabled) {
            this.advertisingId = advertisingId;
            this.limitAdTrackingEnabled = limitAdTrackingEnabled;
        }

        public String getId() {
            return this.advertisingId;
        }

        public boolean isLimitAdTrackingEnabled() {
            return this.limitAdTrackingEnabled;
        }
    }

}
