using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;
using System;



//Dive Head Tracking 
// copyright by Shoogee GmbH & Co. KG Refer to LICENCE.txt 


//[ExecuteInEditMode]
public class OpenDiveSensor : MonoBehaviour {
	
	// This is used for rotating the camera with another object
	//for example tilting the camera while going along a racetrack or rollercoaster
	public bool add_rotation_gameobject=false;
	public GameObject rotation_gameobject;

	// mouse emulation
	public bool emulateMouseInEditor=true;
	public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
	public RotationAxes axes = RotationAxes.MouseXAndY;
	public Texture nogyrotexture;

	/// Offset projection for 2 cameras in VR
	private float offset =0.0f;
	private float max_offset=0.002f;
	//public float max_offcenter_warp=0.1f;
	public Camera cameraleft;
	public Camera cameraright;
	
	public float zoom=0.1f;
	private float IPDCorrection=0.0f;
	private float aspectRatio;
	public float znear=0.1f;
	public float zfar=10000.0f;



	private float time_since_last_fullscreen=0;
	private int is_tablet;

	AndroidJavaObject mConfig;
	AndroidJavaObject mWindowManager;


	private float q0,q1,q2,q3;
	private float m0,m1,m2;
	Quaternion rot;
	private bool show_gyro_error_message=false;

	string errormessage;


#if UNITY_EDITOR
	private float sensitivityX = 15F;
	private float sensitivityY = 15F;
	
	private float minimumX = -360F;
	private float maximumX = 360F;
	
	private float minimumY = -90F;
	private float maximumY = 90F;
	
	float rotationY = 0F;




  #elif UNITY_ANDROID
	private static AndroidJavaClass javadivepluginclass;
	private static AndroidJavaClass javaunityplayerclass;
	private static AndroidJavaObject currentactivity;
	private static AndroidJavaObject javadiveplugininstance;



	[DllImport("divesensor")]	private static extern void initialize_sensors();
	[DllImport("divesensor")]	private static extern int get_q(ref float q0,ref float q1,ref float q2,ref float q3);
	[DllImport("divesensor")]	private static extern int get_m(ref float m0,ref float m1,ref float m2);
	[DllImport("divesensor")]	private static extern int get_error();
	[DllImport("divesensor")]   private static extern void dive_command(string command);


   
   #elif UNITY_IPHONE
	[DllImport("__Internal")]	private static extern void initialize_sensors();
	[DllImport("__Internal")]	private static extern float get_q0();
	[DllImport("__Internal")]	private static extern float get_q1();
	[DllImport("__Internal")]	private static extern float get_q2();
	[DllImport("__Internal")]	private static extern float get_q3();
	[DllImport("__Internal")]	private static extern void DiveUpdateGyroData();
    [DllImport("__Internal")]	private static extern int get_q(ref float q0,ref float q1,ref float q2,ref float q3);
	
	
#endif 	


	public static void divecommand(string command){
		#if UNITY_EDITOR
		#elif UNITY_ANDROID
		dive_command(command);
		#elif UNITY_IPHONE
		#endif

	}

	public static void setFullscreen(){
		#if UNITY_EDITOR
		
		#elif UNITY_ANDROID
		String answer;
		answer= javadiveplugininstance.Call<string>("setFullscreen");

		
		#elif UNITY_IPHONE
		
		#endif 	
		
		return;
	}





	void Start () {


	




		rot=Quaternion.identity;
	    // Disable screen dimming
     	Screen.sleepTimeout = SleepTimeout.NeverSleep;
		Application.targetFrameRate = 60;






#if UNITY_EDITOR

		if (rigidbody)
			rigidbody.freezeRotation = true;

  #elif UNITY_ANDROID

		// Java part
		javadivepluginclass = new AndroidJavaClass("com.shoogee.divejava.divejava") ;
		javaunityplayerclass= new AndroidJavaClass("com.unity3d.player.UnityPlayer");
		currentactivity = javaunityplayerclass.GetStatic<AndroidJavaObject>("currentActivity");
		javadiveplugininstance = javadivepluginclass.CallStatic<AndroidJavaObject>("instance");
		object[] args={currentactivity};
		javadiveplugininstance.Call<string>("set_activity",args);


		initialize_sensors ();



		String answer;
		answer= javadiveplugininstance.Call<string>("initializeDive");
		answer= javadiveplugininstance.Call<string>("getDeviceType");
		if (answer=="Tablet"){
				is_tablet=1;
			Debug.Log("Dive Unity Tablet Mode activated");
		
		}
		else{
			Debug.Log("Dive Phone Mode activated "+answer);
		}


		answer= javadiveplugininstance.Call<string>("setFullscreen");

		show_gyro_error_message=true;
		Network.logLevel = NetworkLogLevel.Full;


		int err = get_error();
		if (err==0){ errormessage="";
			show_gyro_error_message=false;

		}
		if (err==1){
			show_gyro_error_message=true;
			errormessage="ERROR: Dive needs a Gyroscope and your telephone has none, we are trying to go to Accelerometer compatibility mode. Dont expect too much.";
		}



	#elif UNITY_IPHONE
		initialize_sensors();
#endif

		float tabletcorrection=-0.028f;
		//is_tablet=0;

		if (is_tablet==1)
		{

			Debug.Log ("Is tablet, using tabletcorrection");
			IPDCorrection=tabletcorrection;
		}
		else 
		{
			IPDCorrection=IPDCorrection;

		}

		//setIPDCorrection(IPDCorrection); 


	}


	
	void Update () {
		aspectRatio=(Screen.height*2.0f)/Screen.width;
		setIPDCorrection(IPDCorrection); 

		//Debug.Log ("Divecamera"+cameraleft.aspect+"1/asp "+1/cameraleft.aspect+" Screen Width/Height "+ aspectRatio);




#if UNITY_EDITOR

	#elif UNITY_ANDROID
		time_since_last_fullscreen+=Time.deltaTime;
		
		if (time_since_last_fullscreen >8){
			setFullscreen ();
			time_since_last_fullscreen=0;

			
		}

		get_q(ref q0,ref q1,ref q2,ref q3);
		//get_m(ref m0,ref m1,ref m2);
		rot.x=-q2;rot.y=q3;rot.z=-q1;rot.w=q0;


		
		if (add_rotation_gameobject){
			transform.rotation =rotation_gameobject.transform.rotation* rot;
		}
		else
		{
			transform.rotation = rot;
			if (is_tablet==1)transform.rotation=rot*Quaternion.AngleAxis(90,Vector3.forward);
			
		}



	#elif UNITY_IPHONE
		DiveUpdateGyroData();
		get_q(ref q0,ref q1,ref q2,ref q3);
		rot.x=-q2;
		rot.y=q3;
		rot.z=-q1;
		rot.w=q0;
		transform.rotation = rot;


		
		if (add_rotation_gameobject){
			transform.rotation =rotation_gameobject.transform.rotation* rot;
		}
		else
		{
			transform.rotation = rot;
			if (is_tablet==1)transform.rotation=rot*Quaternion.AngleAxis(90,Vector3.forward);
			
		}


#endif


	


#if UNITY_EDITOR

		if (emulateMouseInEditor){
			

			if (axes == RotationAxes.MouseXAndY)
			{
				float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
				
				rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
				rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
				
				transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
			}
			else if (axes == RotationAxes.MouseX)
			{
				transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0);
			}
			else
			{
				rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
				rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
				
				transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0);
			}
		}
#endif



	}
	
	void OnGUI ()
	{
	
	/*	if (GUI.Button(new Rect(Screen.width/4-150, Screen.height-100, 300,100), "+IPD")){
			Debug.Log("Clicked the button with an image");
			IPDCorrection=IPDCorrection+0.01f;
			setIPDCorrection(IPDCorrection);
		}

		if (GUI.Button(new Rect(Screen.width-Screen.width/4-150, Screen.height-100, 300,100), "-IPD")){
			Debug.Log("Clicked the button with an image");

			IPDCorrection=IPDCorrection-0.01f;
			setIPDCorrection(IPDCorrection);
		}
*/


		if (show_gyro_error_message)
		{

			if(GUI.Button(new Rect(0,0, Screen.width, Screen.height) , "Error: \n\n No Gyro detected \n \n Touch screen to continue anyway")) {
				show_gyro_error_message=false;
			}
			GUI.DrawTexture(new Rect(Screen.width/2-320, Screen.height/2-240, 640, 480), nogyrotexture, ScaleMode.ScaleToFit, true, 0);
			return;

		}




	}




	void setIPDCorrection(float correction) {

		// not using camera nearclipplane value because that leads to problems with field of view in different projects


		cameraleft.projectionMatrix = PerspectiveOffCenter((-zoom+correction)*(znear/0.1f), (zoom+correction)*(znear/0.1f), -zoom*(znear/0.1f)*aspectRatio, zoom*(znear/0.1f)*aspectRatio, znear, zfar);;
		cameraright.projectionMatrix = PerspectiveOffCenter((-zoom-correction)*(znear/0.1f), (zoom-correction)*(znear/0.1f), -zoom*(znear/0.1f)*aspectRatio, zoom*(znear/0.1f)*aspectRatio, znear, zfar);;
		}
	
	static Matrix4x4 PerspectiveOffCenter(float left, float right, float bottom, float top, float near, float far) {
		float x = 2.0F * near / (right - left);
		float y = 2.0F * near / (top - bottom);
		float a = (right + left) / (right - left);
		float b = (top + bottom) / (top - bottom);
		float c = -(far + near) / (far - near);
		float d = -(2.0F * far * near) / (far - near);
		float e = -1.0F;
		Matrix4x4 m = new Matrix4x4();
		m[0, 0] = x;
		m[0, 1] = 0;
		m[0, 2] = a;
		m[0, 3] = 0;
		m[1, 0] = 0;
		m[1, 1] = y;
		m[1, 2] = b;
		m[1, 3] = 0;
		m[2, 0] = 0;
		m[2, 1] = 0;
		m[2, 2] = c;
		m[2, 3] = d;
		m[3, 0] = 0;
		m[3, 1] = 0;
		m[3, 2] = e;
		m[3, 3] = 0;
		return m;
	}
	
}