
// 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


#if M_UNITY_API
using UnityEngine;
#endif

using System;
using System.Collections;
using System.Collections.Generic;
//using System.Diagnostics;
//using System.Runtime.CompilerServices;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;


//namespace McGuffinsOfflineNetworkWorkshop {

#if M_UNITY_API
    class LogItem {
        public string description; // the string displayed to the user
        public int count; // when the same log message is logged consecutively, rather than store and display multiple copies, we increment this.
        public LogItem(string d) {
            this.description = d;
            this.count = 1;
        }
    }

    // This is used to store an array of message strings, useful for debugging.
    // If the client tries to store the same log message multiple times consecutively,
    // rather than store multiple copies, we increment a counter associated with the first copy.
    public class MLogger {
        public static MLogger Instance = new MLogger();

        // When the number of logged messages exceeds this limit,
        // the older ones are deleted, to simulate scrolling.
        private const int MAX_NUM_ITEMS = 50;

        private List<LogItem> items = new List<LogItem>();
        public bool hasChangedSinceLastRetrieval = true;
        public BooleanWrapper hasSomethingImportantHappened = null;
        public void log( string message, bool isVeryImportant ) {
            if ( isVeryImportant ) {
                if ( hasSomethingImportantHappened != null )
                   hasSomethingImportantHappened.v = true;
                UnityEngine.Debug.Log( message );
            }
            int N = items.Count;
            if (N > 0 && message.Equals(this.items[N - 1].description)) {
                this.items[N - 1].count++;
            }
            else {
                items.Add(new LogItem(message));
                while (items.Count > MLogger.MAX_NUM_ITEMS)
                    items.RemoveAt(0);
            }
            hasChangedSinceLastRetrieval = true;
        }
        // Used by the client to display the contents of the log
        public string generateMultilineString() {
            string s = "";
            for (var i = 0; i < items.Count; i++) {
                s += items[i].description;
                if (items[i].count > 1) s += "(x" + items[i].count + ")";
                s += "\n";
            }
            hasChangedSinceLastRetrieval = false;
            return s;
        }

        static public int maxDebugLevel = 0;
        static public void Log(string message,int debugLevel=0 /*bigger means more detailed*/) {
            if ( debugLevel <= maxDebugLevel )
                Instance.log( message, false );
        }
        static public void Assert(
            bool condition,
            string message = ""
        ) {
            if (!condition) {
                Instance.log( "ASSERTION ERROR:" + message, true );
                if ( message=="" ) {
                    // TODO_0 do a stack trace
                    // Instance.log(/*...*/"");
                }
            }
        }
        static public void Exception(System.Exception ex, string message) {
            Instance.log( "EXCEPTION:" + message + "\n  " + ex.ToString(), true );
            Instance.log( "More info about exception:" + MUtil.fullInfoAboutException(ex), true ); // TODO_1 I don't know if this will help to print out more info
        }
    }
#else
    class MLogger {
        static public int maxDebugLevel = 0;
        static public void Log(string message,int debugLevel=0 /*bigger means more detailed*/) {
            if ( debugLevel <= maxDebugLevel )
            Console.WriteLine(message);
        }
        static public void Assert(bool condition, string message) {
            if (!condition) Console.WriteLine("ASSERTION ERROR:" + message);
        }
        static public void Exception(System.Exception ex, string message) {
            Console.WriteLine("EXCEPTION:" + message + "\n  " + ex.ToString());
            Console.WriteLine("More info about exception:" + MUtil.fullInfoAboutException(ex));
        }
    }
#endif
//}

