package com.gizwits.amap;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps2d.CoordinateConverter;
import com.amap.api.maps2d.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeAddress;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.gizwits.amap.utils.GPSUtil;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

/**
 * This class echoes a string called from JavaScript.
 */
public class GizGeofenceTool extends CordovaPlugin  implements AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener{
	public static final int REQUEST_CODE = 0x0ba7c0de;
	private static final int PERMISSION_CODE = 100;
	private CallbackContext callbackContext;
	private String themeInfo;
	private String action;

	private static final int AUTHORIZATION_STATUS_NOT_DETERMINED = 0;
	private static final int AUTHORIZATION_STATUS_DENIED = 2;
	private static final int AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS = 3;

	private static final String KEY_LATITUDE = "latitude";
	private static final String KEY_LONGTITUDE = "longitude";


	@Override
	public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
		this.callbackContext = callbackContext;
		this.action = action;
		if (action.equals("setThemeInfo")) {
			if(args != null && args.length() > 0) {
				JSONObject obj = args.getJSONObject(0);
				if(obj != null) {
					themeInfo = obj.toString();
				}
			}
			return true;
		} else if (action.equals("authorizationStatus")) {
			getAuthorizationStatus();
			return true;
		} else if (action.equals("requestAlwaysAuthorization")) {
			requestAlwaysAuthorization();
			return true;
		} else if (action.equals("getCurrentLocation")) {
			getCurrentLocation();
			return true;
		} else if (action.equals("getAddressInfo")) {
			getAddressInfo(args);
			return true;
		} else if (action.equals("pickAddress")) {
			pickAddress(action, args);
			return true;
		} else if (action.equals("transformFromWGSToGCJ")) {
			transformCoordinate(action, args);
			return true;
		} else if (action.equals("transformFromGCJToWGS")) {
			transformCoordinate(action, args);
			return true;
		} else if (action.equals("transformFromGCJToBaidu")) {
			transformCoordinate(action, args);
			return true;
		} else if (action.equals("transformFromBaiduToGCJ")) {
			transformCoordinate(action, args);
			return true;
		}
		return false;
	}

	public void transformCoordinate(final String action, final JSONArray args) {
		final CordovaPlugin that = this;
		cordova.getThreadPool().execute(new Runnable() {
			public void run() {
				if (args != null && args.length() > 0) {
					JSONObject obj;
					double lat = 0;
					double lon = 0;
					try {
						obj = args.getJSONObject(0);
						lat = obj.getDouble(KEY_LATITUDE);
						lon = obj.getDouble(KEY_LONGTITUDE);
					} catch (JSONException e) {
						Log.i("CordovaLog", e.getLocalizedMessage());
					}
					if (action.equals("transformFromWGSToGCJ")) {
						transformFromWGSToGCJ(lat, lon);
					} else if (action.equals("transformFromGCJToWGS")) {
						transformFromGCJToWGS(lat, lon);
					} else if (action.equals("transformFromGCJToBaidu")) {
						transformFromGCJToBaidu(lat, lon);
					} else if (action.equals("transformFromBaiduToGCJ")) {
						transformFromBaiduToGCJ(lat, lon);
					}
				}
			}
		});
	}

	public void pickAddress(final String action, final JSONArray args) {

		final CordovaPlugin that = this;
		cordova.getThreadPool().execute(new Runnable() {
			public void run() {
				Intent mapIntent = new Intent(that.cordova.getActivity().getBaseContext(), AMapActivity.class);

				// add config as intent extras
				if (args != null && args.length() > 0) {
					JSONObject obj;
					double lat = 0;
					double lon = 0;
					try {
						obj = args.getJSONObject(0);
						lat = obj.getDouble(KEY_LATITUDE);
						lon = obj.getDouble(KEY_LONGTITUDE);
					} catch (JSONException e) {
						Log.i("CordovaLog", e.getLocalizedMessage());
					}
					mapIntent.putExtra(KEY_LATITUDE, lat);
					mapIntent.putExtra(KEY_LONGTITUDE, lon);
					mapIntent.putExtra("action", action);
					mapIntent.putExtra("themeInfo", themeInfo);
				}
				// avoid calling other phonegap apps
				mapIntent.setPackage(that.cordova.getActivity().getApplicationContext().getPackageName());
				that.cordova.startActivityForResult(that, mapIntent, REQUEST_CODE);
			}
		});
	}


	public void getAddressInfo(final JSONArray args) {
		cordova.getThreadPool().execute(new Runnable() {
			public void run() {
				if (args != null && args.length() > 0) {
					JSONObject obj;
					double lat = 0;
					double lon = 0;
					try {
						obj = args.getJSONObject(0);
						lat = obj.getDouble(KEY_LATITUDE);
						lon = obj.getDouble(KEY_LONGTITUDE);
					} catch (JSONException e) {
						Log.i("CordovaLog", e.getLocalizedMessage());
					}
					if (GPSUtil.isInArea(lat, lon)) {
						getGPSAddressInfoFromAMap(lat, lon);
					} else {
						getGPSAdrresInfoFromGoogleMap(lat, lon);
					}
				}
			}
		});
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
		if(callbackContext == null){
			return;
		}
		if (requestCode == REQUEST_CODE ) {
			if (resultCode == Activity.RESULT_OK && intent != null) {
				String code = intent.getStringExtra("result");
				JSONObject jsonObject = null;
				try {
					jsonObject = new JSONObject(code);
				} catch (JSONException e) {
					e.printStackTrace();
				}
				this.callbackContext.success(jsonObject);
			} else if (intent != null){
				String code = intent.getStringExtra("result");
				this.callbackContext.error(code);
			} else {
				// goolge play 服务不可用
				this.callbackContext.error(9);
			}
		}
	}


	/**
	 * This plugin launches an external Activity when the camera is opened, so we
	 * need to implement the save/restore API in case the Activity gets killed
	 * by the OS while it's in the background.
	 */
	public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {
		this.callbackContext = callbackContext;
	}


	/**
	 * 坐标系转换
	 * WGS-84：是国际标准，GPS坐标（Google Earth使用、或者GPS模块）
	 * GCJ-02：中国坐标偏移标准，Google Map、高德、腾讯使用 (火星坐标系)
	 * BD-09 ：百度坐标偏移标准，Baidu Map使用
	 */
	/**
	 * WGS-84 转换为 GCJ-02
	 */
	private void transformFromWGSToGCJ(double lat, double lon) {
		LatLng latLng = new LatLng(lat, lon);
		CoordinateConverter converter = new CoordinateConverter();
		converter.from(CoordinateConverter.CoordType.GPS);
		converter.coord(latLng);
		LatLng desLatLng = converter.convert();
		JSONObject json = new JSONObject();
		try {
			json.put(KEY_LATITUDE, desLatLng.latitude);
			json.put(KEY_LONGTITUDE, desLatLng.longitude);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		if(callbackContext == null){
			return;
		}
		Log.e("jason", "transformFromWGSToGCJ :"+json.toString());
		this.callbackContext.success(json);
	}

	/**
	 * GCJ-02 转换为 WGS-84
	 */
	private void transformFromGCJToWGS(double lat, double lon) {
		if(callbackContext == null){
			return;
		}
		double[] latlon = GPSUtil.gcj02_To_Gps84(lat, lon);
		JSONObject json = new JSONObject();
		try {
			json.put(KEY_LATITUDE, latlon[0]);
			json.put(KEY_LONGTITUDE, latlon[1]);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		Log.e("jason", "transformFromGCJToWGS :"+json.toString());
		this.callbackContext.success(json);
	}

	/**
	 * GCJ-02 转换为 BD-09
	 */
	private void transformFromGCJToBaidu(double lat, double lon) {
		double[] latlon = GPSUtil.gcj02_To_Bd09(lat, lon);
		JSONObject json = new JSONObject();
		try {
			json.put(KEY_LATITUDE, latlon[0]);
			json.put(KEY_LONGTITUDE, latlon[1]);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		if(callbackContext == null){
			return;
		}
		this.callbackContext.success(json);
	}

	/**
	 * BD-09 转换为 GCJ-02
	 */
	private void transformFromBaiduToGCJ(double lat, double lon) {
		LatLng latLng = new LatLng(lat, lon);
		CoordinateConverter converter = new CoordinateConverter();
		converter.from(CoordinateConverter.CoordType.BAIDU);
		converter.coord(latLng);
		LatLng desLatLng = converter.convert();
		JSONObject json = new JSONObject();
		try {
			json.put(KEY_LATITUDE, desLatLng.latitude);
			json.put(KEY_LONGTITUDE, desLatLng.longitude);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		if(callbackContext == null){
			return;
		}
		this.callbackContext.success(json);
	}

	private void getGPSAddressInfoFromAMap(double lat, double lon){
		GeocodeSearch geocodeSearch = new GeocodeSearch(this.cordova.getActivity());
		geocodeSearch.setOnGeocodeSearchListener(this);
		LatLonPoint latLngPoint = new LatLonPoint(lat, lon);
		RegeocodeQuery query = new RegeocodeQuery(latLngPoint, 200, GeocodeSearch.GPS);
		geocodeSearch.getFromLocationAsyn(query);
	}

	private void getGPSAdrresInfoFromGoogleMap(double lat, double lon) {
		if(callbackContext == null){
			return;
		}
		Geocoder geocoder = new Geocoder(this.cordova.getActivity(), Locale.getDefault());
		try {
			List<Address> addresses = geocoder.getFromLocation(lat, lon, 1);
			if (addresses != null && addresses.size() > 0){
				Address addr = addresses.get(0);
				JSONObject json = new JSONObject();
				try {
					JSONArray js = new JSONArray();
					json.put("FormattedAddressLines",js.put(addresses.get(0).getAddressLine(0)));
					json.put("Street", "");
					json.put("Thoroughfare", "");
					json.put("Name", addr.getFeatureName());
					json.put("City", addr.getLocality());
					json.put("Country", addr.getCountryName());
					json.put("State", addr.getAdminArea());
					json.put("SubLocality", addr.getSubLocality());
					json.put("CountryCode", addr.getCountryCode());
				} catch (JSONException e) {
					e.printStackTrace();
				}
				Log.e("地址解析", json.toString());
				this.callbackContext.success(json);
				return;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		this.callbackContext.error(6);
	}


	@Override
	public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int rCode) {
		if(callbackContext == null){
			return;
		}

		if(rCode == 1000) {
			RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
			JSONObject json = new JSONObject();
			try {
				JSONArray js = new JSONArray();
				json.put("FormattedAddressLines",js.put(regeocodeAddress.getFormatAddress()));
//				json.put("Street", regeocodeAddress.getRoads().get(0).getName());
//				json.put("Thoroughfare", regeocodeAddress.getRoads().get(0).getName());
				json.put("Street", "");
				json.put("Thoroughfare", "");
				json.put("Name", regeocodeAddress.getBuilding());
				json.put("City", regeocodeAddress.getCity());
				json.put("Country", regeocodeAddress.getCountry());
				json.put("State", regeocodeAddress.getProvince());
				json.put("SubLocality", regeocodeAddress.getDistrict());
				json.put("CountryCode", "");
			} catch (JSONException e) {
				e.printStackTrace();
			}
			Log.e("jason", "address:"+json.toString());
			this.callbackContext.success(json);
		}else if(rCode == 1008){
			this.callbackContext.error(8);
		}else if(rCode == 1002){
			//key 不正确或过期
			this.callbackContext.error(7);
		}else {
			this.callbackContext.error(6);
		}

	}

	@Override
	public void onGeocodeSearched(GeocodeResult geocodeResult, int rCode) {

	}

	/**
	 * 获取当前定位信息
	 */
	private void getCurrentLocation() {
		AMapLocationClient aMapLocationClient = new AMapLocationClient(this.cordova.getActivity());
		aMapLocationClient.setLocationListener(GizGeofenceTool.this);
		AMapLocationClientOption clientOption = new AMapLocationClientOption();
		clientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
		clientOption.setOnceLocation(true);
		clientOption.setLocationCacheEnable(false);
		aMapLocationClient.setLocationOption(clientOption);
		aMapLocationClient.startLocation();
	}
	/**
	 * 获取位置功能授权状态
	 */
	private void getAuthorizationStatus() {
		if(callbackContext == null){
			return;
		}
		if( cordova.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)){
//			if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
//				this.callbackContext.success(AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS);
//			} else {
				this.callbackContext.success(AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS);
//			}
		} else {
			this.callbackContext.success(AUTHORIZATION_STATUS_NOT_DETERMINED);
		}
	}

	/**
	 * 请求位置信息的权限
	 */
	private void requestAlwaysAuthorization() {
		if(callbackContext == null){
			return;
		}
		if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
			if( !cordova.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)){
				cordova.requestPermission(this, PERMISSION_CODE, Manifest.permission.ACCESS_FINE_LOCATION );
			} else {
				this.callbackContext.success(AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS);
			}
		}else {
			this.callbackContext.success(AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS);
		}
	}

	@Override
	public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
		super.onRequestPermissionResult(requestCode, permissions, grantResults);
		if(callbackContext == null){
			return;
		}
		if(requestCode == PERMISSION_CODE){
			if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
				this.callbackContext.success(AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS);
			}else{
				this.callbackContext.success(AUTHORIZATION_STATUS_DENIED);
			}
		}
	}

	@Override
	public void onLocationChanged(AMapLocation aMapLocation) {
		if(callbackContext == null && !action.equals("getCurrentLocation")){
			return;
		}
//		if (aMapLocation.getErrorCode() == AMapLocation.ERROR_CODE_FAILURE_LOCATION_PERMISSION) {
//			//TODO 没有定位权限
//		}
		transformFromGCJToWGS(aMapLocation.getLatitude(), aMapLocation.getLongitude());
//		JSONObject json = new JSONObject();
//		try {
//			json.put("latitude", aMapLocation.getLatitude());
//			json.put("longitude", aMapLocation.getLongitude());
//		} catch (JSONException e) {
//			e.printStackTrace();
//		}
//		Log.e("jason", "onLocationChanged:"+json.toString());
//		this.callbackContext.success(json);
	}
}
