// Only uncomment one of the following:
//#define M_HOLOLENS_CODE_WITH_OR_WITHOUT_HEADSET
//#define M_VIVE_OR_DESKTOP // in this code, distinguish between desktop or headset with GC.isInDesktopMode

#if M_HOLOLENS_CODE_WITH_OR_WITHOUT_HEADSET
#if UNITY_EDITOR // for code running within the unity editor
#define M_HOLOLENS_CODE_WITHOUT_HEADSET // hololens codebase, but running in unity player, without headset (e.g. for debugging network stuff)
#elif WINDOWS_UWP // for code running on the Hololens headset
#define M_HOLOLENS_CODE_WITH_HEADSET
#endif
#endif

#if UNITY_EDITOR || WINDOWS_UWP
#define M_UNITY_API
#endif


using System;
using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;

#if M_UNITY_API
using UnityEngine;
#endif

//namespace McGuffinsOfflineNetworkWorkshop {
    public class MVector3 {
        public float x, y, z;
        public MVector3() { x = y = z = 0; }
        public MVector3( MVector3 other ) {
            x = other.x;
            y = other.y;
            z = other.z;
        }
        public MVector3(float X,float Y,float Z) { x = X; y = Y; z = Z; }
        public void copy(MVector3 other) {
            x = other.x;
            y = other.y;
            z = other.z;
        }

        public float magnitudeSquared() {
            return x * x + y * y + z * z;
        }
        public float magnitude() {
            return (float)Math.Sqrt(x * x + y * y + z * z);
        }
        public MVector3 normalized() {
            float f = magnitudeSquared();
            if (f > 0) f = (float)(1.0 / Math.Sqrt(f));
            return new MVector3(f*x,f*y,f*z);
        }

        // returns the cross-product of the given vectors
        static public MVector3 cross(MVector3 a, MVector3 b) {
            return new MVector3(
                a.y * b.z - a.z * b.y,
                a.z * b.x - a.x * b.z,
                a.x * b.y - a.y * b.x
            );
        }
        static public MVector3 average(MVector3 a,MVector3 b) {
            return new MVector3((a.x+b.x)*0.5f, (a.y + b.y) *0.5f, (a.z + b.z) *0.5f);
        }
        static public MVector3 average(List<MVector3> v) {
            MVector3 a = new MVector3();
            for ( int i = 0; i < v.Count; ++i ) {
                a += v[i];
            }
            a /= v.Count;
            return a;
        }

        public static MVector3 operator -(MVector3 a) {
            return new MVector3(-a.x , -a.y , -a.z);
        }
        public static MVector3 operator +( MVector3 a, MVector3 b ) {
            return new MVector3( a.x+b.x, a.y+b.y, a.z+b.z );
        }
        public static MVector3 operator -(MVector3 a, MVector3 b) {
            return new MVector3(a.x - b.x, a.y - b.y, a.z - b.z);
        }
        public static float operator *(MVector3 a, MVector3 b) {
            return a.x * b.x + a.y * b.y + a.z * b.z;
        }
        public static MVector3 operator *(MVector3 a, float k) {
            return new MVector3(a.x * k, a.y * k, a.z * k);
        }
        public static MVector3 operator *(float k, MVector3 a) {
            return new MVector3(a.x * k, a.y * k, a.z * k);
        }
        public static MVector3 operator /(MVector3 a, float k) {
            return new MVector3(a.x / k, a.y / k, a.z / k);
        }
        public MVector3 choosePerpendicular() {
            float X = Math.Abs(x);
            float Y = Math.Abs(y);
            float Z = Math.Abs(z);

            MVector3 v2 = new MVector3();
            if (X < Y) {
                if (Y < Z) {
                    // X < Y < Z
                    v2 = new MVector3(0, z, -y);
                }
                else if (X < Z) {
                    // X < Z <= Y
                    v2 = new MVector3(0, z, -y);
                }
                else {
                    // Z <= X < Y
                    v2 = new MVector3(y, -x, 0);
                }
            }
            else {
                if (Z < Y) {
                    // Z < Y <= X
                    v2 = new MVector3(y, -x, 0);
                }
                else if (Z < X) {
                    // Y <= Z < X
                    v2 = new MVector3(z, 0, -x);
                }
                else {
                    // Y <= X <= Z
                    v2 = new MVector3(z, 0, -x);
                }
            }
            return v2;
        }

#if M_UNITY_API
        public MVector3(Vector3 unityVector) { x = unityVector.x; y = unityVector.y; z = unityVector.z; }
        public Vector3 asUnityVector3() { return new Vector3(x,y,z); }
#endif

        public string str() {
            return string.Format("{0},{1},{2}",x,y,z);
        }
    }
//}

