using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[System.Serializable]
public class ChangeDeviceOrientationEvent : UnityEvent<DeviceOrientation>　{}

public class DeviceOrientationChecker : MonoBehaviour {

    [SerializeField]
    private CanvasScaler[] canvasScalerArray = default;
    [SerializeField]
    private float[] autoMatchArray = new float[]{ -1.0f, 0.0f };
    [SerializeField]
    private Camera[] cameraArray = default;

	[SerializeField]
    private ChangeDeviceOrientationEvent onChangeDeviceOrientation = default;
	public ChangeDeviceOrientationEvent OnChangeDeviceOrientation {
		get{ return onChangeDeviceOrientation; }
	}
	[SerializeField]
    private ChangeDeviceOrientationEvent onChangeToDeviceOrientationPortrait = default;
	public ChangeDeviceOrientationEvent OnChangeToDeviceOrientationPortrait {
		get{ return onChangeToDeviceOrientationPortrait; }
	}
	[SerializeField]
    private ChangeDeviceOrientationEvent onChangeToDeviceOrientationLandscape = default;
	public ChangeDeviceOrientationEvent OnChangeToDeviceOrientationLandscape {
		get{ return onChangeToDeviceOrientationLandscape; }
	}

	private DeviceOrientation deviceOrientation = DeviceOrientation.Unknown;
	public DeviceOrientation DeviceOrientation {
		get{ return deviceOrientation; }
	}

	private int screenWidth;
	private int screenHeight;

	void Start(){
		if(ScreenExtensions.IsNarrowScreen() && canvasScalerArray.Length > 0){
			for(int i = 0; i < canvasScalerArray.Length; ++i){
				if(autoMatchArray[i] < -0.0f){
					canvasScalerArray[i].matchWidthOrHeight = (812.0f - 145.0f) / 812.0f;
				}else{
					canvasScalerArray[i].matchWidthOrHeight = autoMatchArray[i];
				}
			}
		}
		screenWidth = Screen.width;
		screenHeight = Screen.height;

		deviceOrientation = GetDeviceOrientation(screenWidth, screenHeight);
		InvokeChangeEvent();
	}

	void Update(){
		int currentWidth = Screen.width;
		int currentHeight = Screen.height;
		DeviceOrientation currentDeviceOrientation = GetDeviceOrientation(currentWidth, currentHeight);
		if(deviceOrientation != currentDeviceOrientation || screenWidth != currentWidth || screenHeight != currentHeight){
			screenWidth = currentWidth;
			screenHeight = currentHeight;
			deviceOrientation = currentDeviceOrientation;
			InvokeChangeEvent();
#if UNITY_ANDROID
		}else{
			var currentNativeDeviceOrientation = GetDeviceOrientation(NativeUtils.getWidth(), NativeUtils.getHeight());
			if(currentDeviceOrientation != currentNativeDeviceOrientation){
				if(currentNativeDeviceOrientation == DeviceOrientation.Portrait || currentNativeDeviceOrientation == DeviceOrientation.PortraitUpsideDown){
					NativeUtils.forceOrientationPortrait();
				}else{
					NativeUtils.forceOrientationLandscape();
				}
			}
#endif
		}
	}

	private void InvokeChangeEvent(){
		switch(deviceOrientation){
		case DeviceOrientation.Portrait:
		case DeviceOrientation.PortraitUpsideDown:
			if(ScreenExtensions.IsNarrowScreen()){
				Vector4 size = new Vector4(44, 34, 0, 0);
				Rect rect = new Rect(1.0f - (375.0f - size.z) / 375.0f, 1.0f - (812.0f - size.y) / 812.0f, (375.0f - size.z - size.w) / 375.0f, (812.0f - size.x - size.y) / 812.0f);
				foreach(var camera in cameraArray){
					camera.rect = rect;
				}
#if UNITY_EDITOR
			}else{
				Rect rect = new Rect(0, 0, 1, 1);
				foreach(var camera in cameraArray){
					camera.rect = rect;
				}
#endif
			}
			break;
		case DeviceOrientation.LandscapeLeft:
		case DeviceOrientation.LandscapeRight:
			if(ScreenExtensions.IsNarrowScreen()){
				Vector4 size = new Vector4(0, 0, 64, 64);
				Rect rect = new Rect(1.0f - (812.0f - size.z) / 812.0f, 1.0f - (375.0f - size.y) / 375.0f, (812.0f - size.z - size.w) / 812.0f, (375.0f - size.x - size.y) / 375.0f);
				foreach(var camera in cameraArray){
					camera.rect = rect;
				}
#if UNITY_EDITOR
			}else{
				Rect rect = new Rect(0, 0, 1, 1);
				foreach(var camera in cameraArray){
					camera.rect = rect;
				}
#endif
			}
			break;
		}
		onChangeDeviceOrientation.Invoke(deviceOrientation);
		switch(deviceOrientation){
		case DeviceOrientation.Portrait:
		case DeviceOrientation.PortraitUpsideDown:
			onChangeToDeviceOrientationPortrait.Invoke(deviceOrientation);
			break;
		case DeviceOrientation.LandscapeLeft:
		case DeviceOrientation.LandscapeRight:
			onChangeToDeviceOrientationLandscape.Invoke(deviceOrientation);
			break;
		}
	}

	private DeviceOrientation GetDeviceOrientation(int width, int height){
		DeviceOrientation result = Input.deviceOrientation;
		switch(result){
		case DeviceOrientation.Unknown:
		case DeviceOrientation.FaceUp:
		case DeviceOrientation.FaceDown:
			if(deviceOrientation == DeviceOrientation.Unknown || screenWidth != width || screenHeight != height){
				// 正確にはInput.accelerationを見るのが良いと思うが、基本設定で切っている為ScreenSizeでチェックを行う
				result = width < height ? DeviceOrientation.Portrait : DeviceOrientation.LandscapeLeft;
			}else{
				result = deviceOrientation;
			}
			break;
		case DeviceOrientation.Portrait:
			result = width < height ? DeviceOrientation.Portrait : DeviceOrientation.LandscapeLeft;
			break;
		case DeviceOrientation.PortraitUpsideDown:
			result = width < height ? DeviceOrientation.PortraitUpsideDown : DeviceOrientation.LandscapeLeft;
			break;
		case DeviceOrientation.LandscapeLeft:
			result = width < height ? DeviceOrientation.Portrait : DeviceOrientation.LandscapeLeft;
			break;
		case DeviceOrientation.LandscapeRight:
			result = width < height ? DeviceOrientation.Portrait : DeviceOrientation.LandscapeRight;
			break;
		}
		return result;
	}
}
