//Copyright (c) 2014 Sang Ki Kwon (Cranberrygame)
//Email: cranberrygame@yahoo.com
//Homepage: http://cranberrygame.github.io
//License: MIT (http://opensource.org/licenses/MIT)
package com.cranberrygame.cordova.plugin.ad.admob;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import android.app.Activity;
import android.util.Log;
//
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.ads.AdListener;

import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.os.Build;
import android.provider.Settings;

import android.os.Handler;
//md5
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
//Util
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.Surface;

//
import android.annotation.TargetApi;
//
import java.lang.reflect.Method;

class Util {

	//ex) Util.alert(cordova.getActivity(),"message");
	public static void alert(Activity activity, String message) {
		AlertDialog ad = new AlertDialog.Builder(activity).create();  
		ad.setCancelable(false); // This blocks the 'BACK' button  
		ad.setMessage(message);  
		ad.setButton("OK", new DialogInterface.OnClickListener() {  
			@Override  
			public void onClick(DialogInterface dialog, int which) {  
				dialog.dismiss();                      
			}  
		});  
		ad.show(); 		
	}
	
	//https://gitshell.com/lvxudong/A530_packages_app_Camera/blob/master/src/com/android/camera/Util.java
	public static int getDisplayRotation(Activity activity) {
	    int rotation = activity.getWindowManager().getDefaultDisplay()
	            .getRotation();
	    switch (rotation) {
	        case Surface.ROTATION_0: return 0;
	        case Surface.ROTATION_90: return 90;
	        case Surface.ROTATION_180: return 180;
	        case Surface.ROTATION_270: return 270;
	    }
	    return 0;
	}

	public static final String md5(final String s) {
        try {
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
            digest.update(s.getBytes());
            byte messageDigest[] = digest.digest();
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < messageDigest.length; i++) {
                String h = Integer.toHexString(0xFF & messageDigest[i]);
                while (h.length() < 2)
                    h = "0" + h;
                hexString.append(h);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
        }
        return "";
    }
}

public class AdmobOverlap implements PluginDelegate {
	protected static final String LOG_TAG = "AdmobOverlap";
	protected Plugin plugin;	
	//
	protected String bannerAdUnit;
	protected String interstitialAdUnit;
	protected boolean isOverlap;
	protected boolean isTest;
	//
	protected String bannerPreviousPosition;	
	protected String bannerPreviousSize;
	protected int lastOrientation;
	//
	protected boolean bannerAdPreload;	
	protected boolean interstitialAdPreload;
	//admob
	protected RelativeLayout bannerViewLayout;
	protected AdView bannerView;
	protected InterstitialAd interstitialView;
	
	public AdmobOverlap(Plugin plugin_) {
		plugin = plugin_;
	}

	public void _setLicenseKey(String email, String licenseKey) {
	}
	
	public void _setUp(String bannerAdUnit, String interstitialAdUnit, boolean isOverlap, boolean isTest) {
		this.bannerAdUnit = bannerAdUnit;
		this.interstitialAdUnit = interstitialAdUnit;
		this.isOverlap = isOverlap;
		this.isTest = isTest;			
		
		lastOrientation = -1;		
		handleLayoutChangeOverlap();
		
		//_showBannerAd("bottom-center", "SMART_BANNER");//cocoon.io
		//_showInterstitialAd();//cocoon.io		
	}
	
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	protected void handleLayoutChangeOverlap() {
		//http://stackoverflow.com/questions/24539578/cordova-plugin-listening-to-device-orientation-change-is-it-possible
		//http://developer.android.com/reference/android/view/View.OnLayoutChangeListener.html
		//https://gitshell.com/lvxudong/A530_packages_app_Camera/blob/master/src/com/android/camera/ActivityBase.java
		//plugin.getWebView().addOnLayoutChangeListener(new View.OnLayoutChangeListener(){//only for ~cordova4
		//plugin.getWebView().getRootView().addOnLayoutChangeListener(new View.OnLayoutChangeListener(){//only for ~cordova4
		//plugin.getWebView().getView().addOnLayoutChangeListener(new View.OnLayoutChangeListener(){//only for cordova5~
		getView(plugin.getWebView()).addOnLayoutChangeListener(new View.OnLayoutChangeListener(){
				
			@Override
			public void onLayoutChange(View v, int left, int top, int right, int bottom,
					int oldLeft, int oldTop, int oldRight, int oldBottom) {
				if (left == oldLeft && top == oldTop && right == oldRight
						&& bottom == oldBottom) {
					return;
				}

				Log.d(LOG_TAG, "onLayoutChange");
				//Util.alert(cordova.getActivity(), "onLayoutChange");
				
				int orientation = Util.getDisplayRotation(plugin.getCordova().getActivity());
				if(orientation != lastOrientation) {
					Log.d(LOG_TAG, String.format("orientation: %d", orientation));
					//Util.alert(cordova.getActivity(), String.format("orientation: %d", orientation));
					if (bannerPreviousSize != null && bannerPreviousSize.equals("SMART_BANNER")) {
						Log.d(LOG_TAG, String.format("position: %s, size: %s", bannerPreviousPosition, bannerPreviousSize));
						//Util.alert(cordova.getActivity(), String.format("position: %s, size: %s", position, size));

						//overlap
						//http://stackoverflow.com/questions/11281562/android-admob-resize-on-landscape
						if (bannerView != null) {							
							//if banner is showing
							RelativeLayout bannerViewLayout = (RelativeLayout)bannerView.getParent();
							if (bannerViewLayout != null) {
								//bannerViewLayout.removeView(bannerView);
								//bannerView.destroy();
								//bannerView = null;				
								Log.d(LOG_TAG, String.format("position: %s, size: %s", bannerPreviousPosition, bannerPreviousSize));
								//Util.alert(cordova.getActivity(), String.format("position: %s, size: %s", position, size));

								//http://stackoverflow.com/questions/3072173/how-to-call-a-method-after-a-delay-in-android
								final Handler handler = new Handler();
								handler.postDelayed(new Runnable() {
									@Override
									public void run() {
										_showBannerAd(bannerPreviousPosition, bannerPreviousSize);
									}
								}, 1);//after 1ms
							}
						}						
					}
				}
			
				lastOrientation = orientation;		
			}		    
		});		
    }

	public static View getView(CordovaWebView webView) {	
		if(View.class.isAssignableFrom(CordovaWebView.class)) {
			return (View) webView;
		}
		
		try {
			Method getViewMethod = CordovaWebView.class.getMethod("getView", (Class<?>[]) null);
			if(getViewMethod != null) {
				Object[] args = {};
				return (View) getViewMethod.invoke(webView, args);
			}
		} 
		catch (Exception e) {
		}
		
		return null;
	}
	
	public void _preloadBannerAd() {
		bannerAdPreload = true;

		_hideBannerAd();
		
		loadBannerAd();	            	
	}
	
	private void loadBannerAd() {
	
		if (bannerView == null) {
			//
			bannerView = new AdView(plugin.getCordova().getActivity());//
			//
			bannerView.setAdUnitId(this.bannerAdUnit);
			bannerView.setAdListener(new MyBannerViewListener());		
			//https://developers.google.com/mobile-ads-sdk/docs/admob/android/banner
			if(bannerPreviousSize == null) {
				bannerPreviousSize = "SMART_BANNER";
			}
			if (bannerPreviousSize.equals("BANNER")) {
				bannerView.setAdSize(AdSize.BANNER);//Banner (320x50, Phones and Tablets)
			} 
			else if (bannerPreviousSize.equals("LARGE_BANNER")) {
				bannerView.setAdSize(AdSize.LARGE_BANNER);//Large banner (320x100, Phones and Tablets)
			}
			else if (bannerPreviousSize.equals("MEDIUM_RECTANGLE")) {
				bannerView.setAdSize(AdSize.MEDIUM_RECTANGLE);//Medium rectangle (300x250, Phones and Tablets)
			}
			else if (bannerPreviousSize.equals("FULL_BANNER")) {
				bannerView.setAdSize(AdSize.FULL_BANNER);//Full banner (468x60, Tablets)
			}
			else if (bannerPreviousSize.equals("LEADERBOARD")) {
				bannerView.setAdSize(AdSize.LEADERBOARD);//Leaderboard (728x90, Tablets)
			}
			else if (bannerPreviousSize.equals("SMART_BANNER")) {
				bannerView.setAdSize(AdSize.SMART_BANNER);//Smart banner (Auto size, Phones and Tablets) //https://developers.google.com/mobile-ads-sdk/docs/admob/android/banner#smart
			}
			else {
				bannerView.setAdSize(AdSize.SMART_BANNER);
			}		
		}
			
		//https://developer.android.com/reference/com/google/android/gms/ads/AdRequest.Builder.html
		AdRequest.Builder builder = new AdRequest.Builder();
		if(isTest) {
			builder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); 
			//builder.addTestDevice("INSERT_YOUR_HASHED_DEVICE_ID_HERE");
			//Java code to force all devices to show test ads
			//http://stackoverflow.com/questions/9028852/java-code-to-force-all-devices-to-show-test-ads
			String ANDROID_ID = Settings.Secure.getString(plugin.getCordova().getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
			String deviceId = Util.md5(ANDROID_ID).toUpperCase();
			builder.addTestDevice(deviceId);		
		}
		AdRequest request = builder.build();
		bannerView.loadAd(request);	            	
	}
	
	public void _showBannerAd(String position, String size) {
	
		if (bannerIsShowingOverlap() && position.equals(bannerPreviousPosition) && size.equals(bannerPreviousSize)) {		
			return;
		}
		
		this.bannerPreviousPosition = position;	
		this.bannerPreviousSize = size;

		if(bannerAdPreload) {
			bannerAdPreload = false;
		}
		else{
			_hideBannerAd();
		
			loadBannerAd();
		}

		addBannerViewOverlap(position, size);
		
		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onBannerAdShown");
		pr.setKeepCallback(true);
		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
		//pr.setKeepCallback(true);
		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);			
	}
	
	protected boolean bannerIsShowingOverlap() {
		boolean bannerIsShowing = false;
		if (bannerView != null) {							
			//if banner is showing
			RelativeLayout bannerViewLayout = (RelativeLayout)bannerView.getParent();
			if (bannerViewLayout != null) {
				bannerIsShowing = true;
			}
		}				
		
		return bannerIsShowing;
	}
	
	protected void addBannerViewOverlap(String position, String size) {
		if(bannerViewLayout == null) {
			bannerViewLayout = new RelativeLayout(plugin.getCordova().getActivity());//	
			RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
			bannerViewLayout.setLayoutParams(params);
			//plugin.getWebView().addView(bannerViewLayout, params);
			//plugin.getWebView().addView(bannerViewLayout);//only for ~cordova4
			//((ViewGroup)plugin.getWebView().getRootView()).addView(bannerViewLayout);//only for ~cordova4
			//((ViewGroup)plugin.getWebView().getView()).addView(bannerViewLayout);//only for cordova5~
			((ViewGroup)getView(plugin.getWebView())).addView(bannerViewLayout);
		}
		
		//http://tigerwoods.tistory.com/11
		//http://developer.android.com/reference/android/widget/RelativeLayout.html
		//http://stackoverflow.com/questions/24900725/admob-banner-poitioning-in-android-on-bottom-of-the-screen-using-no-xml-relative
		RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(AdView.LayoutParams.WRAP_CONTENT, AdView.LayoutParams.WRAP_CONTENT);
		if (position.equals("top-left")) {
			Log.d(LOG_TAG, "top-left");		
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);		
		}
		else if (position.equals("top-center")) {		
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			params.addRule(RelativeLayout.CENTER_HORIZONTAL);
		}
		else if (position.equals("top-right")) {		
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		}
		else if (position.equals("left")) {
			params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
			params.addRule(RelativeLayout.CENTER_VERTICAL);			
		}
		else if (position.equals("center")) {
			params.addRule(RelativeLayout.CENTER_HORIZONTAL);	
			params.addRule(RelativeLayout.CENTER_VERTICAL);	
		}
		else if (position.equals("right")) {	
			params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
			params.addRule(RelativeLayout.CENTER_VERTICAL);	
		}
		else if (position.equals("bottom-left")) {		
			params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);		
			params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);		
		}
		else if (position.equals("bottom-center")) {				
			params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
			params.addRule(RelativeLayout.CENTER_HORIZONTAL);
		}
		else if (position.equals("bottom-right")) {
			params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
			params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		}
		else {		
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			params.addRule(RelativeLayout.CENTER_HORIZONTAL);
		}
		
		//bannerViewLayout.addView(bannerView, params);
		bannerView.setLayoutParams(params);
		bannerViewLayout.addView(bannerView);
	}
	
	public void _reloadBannerAd() {
		loadBannerAd();
	}
	
	public void _hideBannerAd() {
		removeBannerViewOverlap();
		
		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onBannerAdHidden");
		pr.setKeepCallback(true);
		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
		//pr.setKeepCallback(true);
		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);		
	}
	
	protected void removeBannerViewOverlap() {
		if (bannerView == null)
			return;
			
		RelativeLayout bannerViewLayout = (RelativeLayout)bannerView.getParent();
		if (bannerViewLayout != null) {
			bannerViewLayout.removeView(bannerView);
			bannerView.destroy();
			bannerView = null;				
		}
	}
	
	public void _preloadInterstitialAd() {
		interstitialAdPreload = true;

		loadInterstitialAd();
	}
	
	private void loadInterstitialAd() {
		if (interstitialView == null) {
			interstitialView = new InterstitialAd(plugin.getCordova().getActivity());
			//
			interstitialView.setAdUnitId(this.interstitialAdUnit);
			interstitialView.setAdListener(new MyInterstitialViewListener());					
		}		
		
		AdRequest.Builder builder = new AdRequest.Builder();
		if(isTest) {
			builder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); 
			//builder.addTestDevice("INSERT_YOUR_HASHED_DEVICE_ID_HERE");				
			String ANDROID_ID = Settings.Secure.getString(plugin.getCordova().getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
			String deviceId = Util.md5(ANDROID_ID).toUpperCase();
			builder.addTestDevice(deviceId);		
		}
		AdRequest request = builder.build();			
		interstitialView.loadAd(request);		
	}

	public void _showInterstitialAd() {
		if(interstitialAdPreload) {
			interstitialAdPreload = false;

			interstitialView.show();
		}
		else {
			loadInterstitialAd();
		}		
	}
    
   //http://developer.android.com/reference/com/google/android/gms/ads/AdListener.html
    class MyBannerViewListener extends AdListener {

    	public void onAdLoaded() {
    		Log.d(LOG_TAG, "onAdLoaded");

    		if (bannerAdPreload) {
    			PluginResult pr = new PluginResult(PluginResult.Status.OK, "onBannerAdPreloaded");
    			pr.setKeepCallback(true);
    			plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    			//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    			//pr.setKeepCallback(true);
    			//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		}
    		
    		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onBannerAdLoaded");
    		pr.setKeepCallback(true);
    		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    		//pr.setKeepCallback(true);
    		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    	}
    	public void onAdFailedToLoad(int errorCode) {
    		Log.d(LOG_TAG, "onAdFailedToLoad");
    	}
    	public void onAdOpened() {
    		Log.d(LOG_TAG, "onAdOpened");//click and ad opened //onBannerAdShown x
    	}
    	public void onAdClosed() {
    		Log.d(LOG_TAG, "onAdClosed");//onBannerAdHidden x
    	}
    	public void onAdLeftApplication() {
    		Log.d(LOG_TAG, "onAdLeftApplication");
    	}
    }

    class MyInterstitialViewListener extends AdListener {

    	public void onAdLoaded() {
    		Log.d(LOG_TAG, "onAdLoaded");
    		
    		if(interstitialAdPreload) {
    			PluginResult pr = new PluginResult(PluginResult.Status.OK, "onInterstitialAdPreloaded");
    			pr.setKeepCallback(true);
    			plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    			//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    			//pr.setKeepCallback(true);
    			//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		}
    		
    		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onInterstitialAdLoaded");
    		pr.setKeepCallback(true);
    		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    		//pr.setKeepCallback(true);
    		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);		
    		
    		if(!interstitialAdPreload) {
    			interstitialView.show();
    		}	
    	}
		
    	public void onAdFailedToLoad(int errorCode) {
    		Log.d(LOG_TAG, "onAdFailedToLoad");
    	}
		
    	public void onAdLeftApplication() {
    		Log.d(LOG_TAG, "onAdLeftApplication");
    	}
		
    	public void onAdOpened() {
    		Log.d(LOG_TAG, "onAdOpened");
    		
    		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onInterstitialAdShown");
    		pr.setKeepCallback(true);
    		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    		//pr.setKeepCallback(true);
    		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);		
    	}
		
    	public void onAdClosed() {
    		Log.d(LOG_TAG, "onAdClosed");

    		PluginResult pr = new PluginResult(PluginResult.Status.OK, "onInterstitialAdHidden");
    		pr.setKeepCallback(true);
    		plugin.getCallbackContextKeepCallback().sendPluginResult(pr);
    		//PluginResult pr = new PluginResult(PluginResult.Status.ERROR);
    		//pr.setKeepCallback(true);
    		//plugin.getCallbackContextKeepCallback().sendPluginResult(pr);    		
    	}
    }

    public void onPause(boolean multitasking) {
		if (bannerView != null) {
		    bannerView.pause();
		}
    }
      
    public void onResume(boolean multitasking) {
        if (bannerView != null) {
            bannerView.resume();
        }
    }
  	
    public void onDestroy() {
        if (bannerView != null) {
            bannerView.destroy();
        }
    }
}
