using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEngine.Profiling;

public class Debugger : MonoBehaviour
{
    /// <summary>
    /// 是否允许调试
    /// </summary>
    public bool AllowDebugging = true;

    private DebugType _debugType = DebugType.Console;
    private List<LogData> _logInformations = new List<LogData>();
    private int _currentLogIndex = -1;
    private int _infoLogCount = 0;
    private int _warningLogCount = 0;
    private int _errorLogCount = 0;
    private int _fatalLogCount = 0;
    private bool _showInfoLog = true;
    private bool _showWarningLog = true;
    private bool _showErrorLog = true;
    private bool _showFatalLog = true;
    private Vector2 _scrollLogView = Vector2.zero;
    private Vector2 _scrollCurrentLogView = Vector2.zero;
    private Vector2 _scrollSystemView = Vector2.zero;
    private bool _expansion = false;
    private Rect _windowRect = new Rect(0, 0, 100, 60);

    private int _fps = 0;
    private Color _fpsColor = Color.white;
    private int _frameNumber = 0;
    private float _lastShowFPSTime = 0f;

    private void Start()
    {
        DontDestroyOnLoad(this.gameObject);
        if (AllowDebugging)
        {
            Application.logMessageReceived += LogHandler;
        }
    }
    private void Update()
    {
        if (AllowDebugging)
        {
            _frameNumber += 1;
            float time = Time.realtimeSinceStartup - _lastShowFPSTime;
            if (time >= 1)
            {
                _fps = (int)(_frameNumber / time);
                _frameNumber = 0;
                _lastShowFPSTime = Time.realtimeSinceStartup;
            }
        }
    }
    private void OnDestory()
    {
        if (AllowDebugging)
        {
            Application.logMessageReceived -= LogHandler;
        }
    }
    private void LogHandler(string condition, string stackTrace, LogType type)
    {
        LogData log = new LogData();
        log.time = DateTime.Now.ToString("HH:mm:ss");
        log.message = condition;
        log.stackTrace = stackTrace;

        if (type == LogType.Assert)
        {
            log.type = "Fatal";
            _fatalLogCount += 1;
        }
        else if (type == LogType.Exception || type == LogType.Error)
        {
            log.type = "Error";
            _errorLogCount += 1;
        }
        else if (type == LogType.Warning)
        {
            log.type = "Warning";
            _warningLogCount += 1;
        }
        else if (type == LogType.Log)
        {
            log.type = "Info";
            _infoLogCount += 1;
        }

        _logInformations.Add(log);

        if (_warningLogCount > 0)
        {
            _fpsColor = Color.yellow;
        }
        if (_errorLogCount > 0)
        {
            _fpsColor = Color.red;
        }
    }

    private void OnGUI()
    {
        if (AllowDebugging)
        {
            if (_expansion)
            {
                _windowRect = GUI.Window(0, _windowRect, ExpansionGUIWindow, "DEBUGGER");
            }
            else
            {
                _windowRect = GUI.Window(0, _windowRect, ShrinkGUIWindow, "DEBUGGER");
            }
        }
    }
    private void ExpansionGUIWindow(int windowId)
    {
        GUI.DragWindow(new Rect(0, 0, 10000, 20));

        #region title
        GUILayout.BeginHorizontal();
        GUI.contentColor = _fpsColor;
        if (GUILayout.Button("FPS:" + _fps, GUILayout.Height(30)))
        {
            _expansion = false;
            _windowRect.width = 100;
            _windowRect.height = 60;
        }
        GUI.contentColor = (_debugType == DebugType.Console ? Color.white : Color.gray);
        if (GUILayout.Button("Console", GUILayout.Height(30)))
        {
            _debugType = DebugType.Console;
        }
        GUI.contentColor = (_debugType == DebugType.Memory ? Color.white : Color.gray);
        if (GUILayout.Button("Memory", GUILayout.Height(30)))
        {
            _debugType = DebugType.Memory;
        }
        GUI.contentColor = (_debugType == DebugType.System ? Color.white : Color.gray);
        if (GUILayout.Button("System", GUILayout.Height(30)))
        {
            _debugType = DebugType.System;
        }
        GUI.contentColor = (_debugType == DebugType.Screen ? Color.white : Color.gray);
        if (GUILayout.Button("Screen", GUILayout.Height(30)))
        {
            _debugType = DebugType.Screen;
        }
        GUI.contentColor = (_debugType == DebugType.Quality ? Color.white : Color.gray);
        if (GUILayout.Button("Quality", GUILayout.Height(30)))
        {
            _debugType = DebugType.Quality;
        }
        GUI.contentColor = (_debugType == DebugType.Environment ? Color.white : Color.gray);
        if (GUILayout.Button("Environment", GUILayout.Height(30)))
        {
            _debugType = DebugType.Environment;
        }
        GUI.contentColor = Color.white;
        GUILayout.EndHorizontal();
        #endregion

        #region console
        if (_debugType == DebugType.Console)
        {
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Clear"))
            {
                _logInformations.Clear();
                _fatalLogCount = 0;
                _warningLogCount = 0;
                _errorLogCount = 0;
                _infoLogCount = 0;
                _currentLogIndex = -1;
                _fpsColor = Color.white;
            }
            GUI.contentColor = (_showInfoLog ? Color.white : Color.gray);
            _showInfoLog = GUILayout.Toggle(_showInfoLog, "Info [" + _infoLogCount + "]");
            GUI.contentColor = (_showWarningLog ? Color.white : Color.gray);
            _showWarningLog = GUILayout.Toggle(_showWarningLog, "Warning [" + _warningLogCount + "]");
            GUI.contentColor = (_showErrorLog ? Color.white : Color.gray);
            _showErrorLog = GUILayout.Toggle(_showErrorLog, "Error [" + _errorLogCount + "]");
            GUI.contentColor = (_showFatalLog ? Color.white : Color.gray);
            _showFatalLog = GUILayout.Toggle(_showFatalLog, "Fatal [" + _fatalLogCount + "]");
            GUI.contentColor = Color.white;
            GUILayout.EndHorizontal();

            _scrollLogView = GUILayout.BeginScrollView(_scrollLogView, "Box", GUILayout.Height(165));
            for (int i = 0; i < _logInformations.Count; i++)
            {
                bool show = false;
                Color color = Color.white;
                switch (_logInformations[i].type)
                {
                    case "Fatal":
                        show = _showFatalLog;
                        color = Color.red;
                        break;
                    case "Error":
                        show = _showErrorLog;
                        color = Color.red;
                        break;
                    case "Info":
                        show = _showInfoLog;
                        color = Color.white;
                        break;
                    case "Warning":
                        show = _showWarningLog;
                        color = Color.yellow;
                        break;
                    default:
                        break;
                }

                if (show)
                {
                    GUILayout.BeginHorizontal();
                    if (GUILayout.Toggle(_currentLogIndex == i, ""))
                    {
                        _currentLogIndex = i;
                    }
                    GUI.contentColor = color;
                    GUILayout.Label("[" + _logInformations[i].type + "] ");
                    GUILayout.Label("[" + _logInformations[i].time + "] ");
                    GUILayout.Label(_logInformations[i].message);
                    GUILayout.FlexibleSpace();
                    GUI.contentColor = Color.white;
                    GUILayout.EndHorizontal();
                }
            }
            GUILayout.EndScrollView();

            _scrollCurrentLogView = GUILayout.BeginScrollView(_scrollCurrentLogView, "Box", GUILayout.Height(100));
            if (_currentLogIndex != -1)
            {
                GUILayout.Label(_logInformations[_currentLogIndex].message + "\r\n\r\n" + _logInformations[_currentLogIndex].stackTrace);
            }
            GUILayout.EndScrollView();
        }
        #endregion

        #region memory
        else if (_debugType == DebugType.Memory)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Memory Information");
            GUILayout.EndHorizontal();

            GUILayout.BeginVertical("Box");
#if UNITY_5
            GUILayout.Label("总内存：" + Profiler.GetTotalReservedMemory() / 1000000 + "MB");
            GUILayout.Label("已占用内存：" + Profiler.GetTotalAllocatedMemory() / 1000000 + "MB");
            GUILayout.Label("空闲中内存：" + Profiler.GetTotalUnusedReservedMemory() / 1000000 + "MB");
            GUILayout.Label("总Mono堆内存：" + Profiler.GetMonoHeapSize() / 1000000 + "MB");
            GUILayout.Label("已占用Mono堆内存：" + Profiler.GetMonoUsedSize() / 1000000 + "MB");
#endif

            GUILayout.Label("总内存：" + Profiler.GetTotalReservedMemoryLong() / 1000000 + "MB");
            GUILayout.Label("已占用内存：" + Profiler.GetTotalAllocatedMemoryLong() / 1000000 + "MB");
            GUILayout.Label("空闲中内存：" + Profiler.GetTotalUnusedReservedMemoryLong() / 1000000 + "MB");
            GUILayout.Label("总Mono堆内存：" + Profiler.GetMonoHeapSizeLong() / 1000000 + "MB");
            GUILayout.Label("已占用Mono堆内存：" + Profiler.GetMonoUsedSizeLong() / 1000000 + "MB");

            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("卸载未使用的资源"))
            {
                Resources.UnloadUnusedAssets();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("使用GC垃圾回收"))
            {
                GC.Collect();
            }
            GUILayout.EndHorizontal();
        }
        #endregion

        #region system
        else if (_debugType == DebugType.System)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("System Information");
            GUILayout.EndHorizontal();

            _scrollSystemView = GUILayout.BeginScrollView(_scrollSystemView, "Box");
            GUILayout.Label("操作系统：" + SystemInfo.operatingSystem);
            GUILayout.Label("系统内存：" + SystemInfo.systemMemorySize + "MB");
            GUILayout.Label("处理器：" + SystemInfo.processorType);
            GUILayout.Label("处理器数量：" + SystemInfo.processorCount);
            GUILayout.Label("显卡：" + SystemInfo.graphicsDeviceName);
            GUILayout.Label("显卡类型：" + SystemInfo.graphicsDeviceType);
            GUILayout.Label("显存：" + SystemInfo.graphicsMemorySize + "MB");
            GUILayout.Label("显卡标识：" + SystemInfo.graphicsDeviceID);
            GUILayout.Label("显卡供应商：" + SystemInfo.graphicsDeviceVendor);
            GUILayout.Label("显卡供应商标识码：" + SystemInfo.graphicsDeviceVendorID);
            GUILayout.Label("设备模式：" + SystemInfo.deviceModel);
            GUILayout.Label("设备名称：" + SystemInfo.deviceName);
            GUILayout.Label("设备类型：" + SystemInfo.deviceType);
            GUILayout.Label("设备标识：" + SystemInfo.deviceUniqueIdentifier);
            GUILayout.EndScrollView();
        }
        #endregion

        #region screen
        else if (_debugType == DebugType.Screen)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Screen Information");
            GUILayout.EndHorizontal();

            GUILayout.BeginVertical("Box");
            GUILayout.Label("DPI：" + Screen.dpi);
            GUILayout.Label("分辨率：" + Screen.currentResolution.ToString());
            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("全屏"))
            {
                Screen.SetResolution(Screen.currentResolution.width, Screen.currentResolution.height, !Screen.fullScreen);
            }
            GUILayout.EndHorizontal();
        }
        #endregion

        #region Quality
        else if (_debugType == DebugType.Quality)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Quality Information");
            GUILayout.EndHorizontal();

            GUILayout.BeginVertical("Box");
            string value = "";
            if (QualitySettings.GetQualityLevel() == 0)
            {
                value = " [最低]";
            }
            else if (QualitySettings.GetQualityLevel() == QualitySettings.names.Length - 1)
            {
                value = " [最高]";
            }

            GUILayout.Label("图形质量：" + QualitySettings.names[QualitySettings.GetQualityLevel()] + value);
            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("降低一级图形质量"))
            {
                QualitySettings.DecreaseLevel();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("提升一级图形质量"))
            {
                QualitySettings.IncreaseLevel();
            }
            GUILayout.EndHorizontal();
        }
        #endregion

        #region Environment
        else if (_debugType == DebugType.Environment)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Environment Information");
            GUILayout.EndHorizontal();

            GUILayout.BeginVertical("Box");
            GUILayout.Label("项目名称：" + Application.productName);
#if UNITY_5
            GUILayout.Label("项目ID：" + Application.bundleIdentifier);
#endif
#if UNITY_7
            GUILayout.Label("项目ID：" + Application.identifier);
#endif
            GUILayout.Label("项目版本：" + Application.version);
            GUILayout.Label("Unity版本：" + Application.unityVersion);
            GUILayout.Label("公司名称：" + Application.companyName);
            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("退出程序"))
            {
                Application.Quit();
            }
            GUILayout.EndHorizontal();
        }
        #endregion
    }
    private void ShrinkGUIWindow(int windowId)
    {
        GUI.DragWindow(new Rect(0, 0, 10000, 20));

        GUI.contentColor = _fpsColor;
        if (GUILayout.Button("FPS:" + _fps, GUILayout.Width(80), GUILayout.Height(30)))
        {
            _expansion = true;
            _windowRect.width = 1200;
            _windowRect.height = 720;
        }
        GUI.contentColor = Color.white;
    }
}
public struct LogData
{
    public string time;
    public string type;
    public string message;
    public string stackTrace;
}
public enum DebugType
{
    Console,
    Memory,
    System,
    Screen,
    Quality,
    Environment
}
