#if UNITY_CHANGE1 || UNITY_CHANGE2 || UNITY_CHANGE3 || UNITY_CHANGE4
#warning UNITY_CHANGE has been set manually
#elif UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
#define UNITY_CHANGE1
#elif UNITY_5_0 || UNITY_5_1 || UNITY_5_2
#define UNITY_CHANGE2
#else
#define UNITY_CHANGE3
#endif
#if UNITY_2018_3_OR_NEWER
#define UNITY_CHANGE4
#endif
//use UNITY_CHANGE1 for unity older than "unity 5"
//use UNITY_CHANGE2 for unity 5.0 -> 5.3 
//use UNITY_CHANGE3 for unity 5.3 (fix for new SceneManger system)
//use UNITY_CHANGE4 for unity 2018.3 (Networking system)

using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic;
#if UNITY_CHANGE3
using UnityEngine.SceneManagement;
#endif
#if UNITY_CHANGE4
using UnityEngine.Networking;
#endif


[System.Serializable]
public class Images
{
	public Texture2D clearImage;
	public Texture2D collapseImage;
	public Texture2D clearOnNewSceneImage;
	public Texture2D showTimeImage;
	public Texture2D showSceneImage;
	public Texture2D userImage;
	public Texture2D showMemoryImage;
	public Texture2D softwareImage;
	public Texture2D dateImage;
	public Texture2D showFpsImage;
	public Texture2D infoImage;
    public Texture2D saveLogsImage; 
    public Texture2D searchImage;
    public Texture2D copyImage;
    public Texture2D closeImage;

	public Texture2D buildFromImage;
	public Texture2D systemInfoImage;
	public Texture2D graphicsInfoImage;
	public Texture2D backImage;

	public Texture2D logImage;
	public Texture2D warningImage;
	public Texture2D errorImage;

	public Texture2D barImage;
	public Texture2D button_activeImage;
	public Texture2D even_logImage;
	public Texture2D odd_logImage;
	public Texture2D selectedImage;

	public GUISkin reporterScrollerSkin;
}

//To use Reporter just create reporter from menu (Reporter->Create) at first scene your game start.
//then set the ” Scrip execution order ” in (Edit -> Project Settings ) of Reporter.cs to be the highest.

//Now to view logs all what you have to do is to make a circle gesture using your mouse (click and drag) 
//or your finger (touch and drag) on the screen to show all these logs
//no coding is required 

public class Reporter : MonoBehaviour
{

	public enum _LogType
	{
		Assert    = LogType.Assert,
		Error     = LogType.Error,
		Exception = LogType.Exception,
		Log       = LogType.Log,
		Warning   = LogType.Warning,
	}

	public class Sample
	{
		public float time;
		public byte loadedScene;
		public float memory;
		public float fps;
		public string fpsText;
		public static float MemSize()
		{
			float s = sizeof(float) + sizeof(byte) + sizeof(float) + sizeof(float);
			return s;
		}

		public string GetSceneName()
		{
			if (loadedScene == 255)
				return "AssetBundleScene";

			return scenes[loadedScene];
		}
	}

	List<Sample> samples = new List<Sample>();

	public class Log
	{
		public int count = 1;
		public _LogType logType;
		public string condition;
		public string stacktrace;
		public int sampleId;
		//public string   objectName="" ;//object who send error
		//public string   rootName =""; //root of object send error

		public Log CreateCopy()
		{
			return (Log)this.MemberwiseClone();
		}
		public float GetMemoryUsage()
		{
			return (float)(sizeof(int) +
					sizeof(_LogType) +
					condition.Length * sizeof(char) +
					stacktrace.Length * sizeof(char) +
					sizeof(int));
		}
	}
	//contains all uncollapsed log
	List<Log> logs = new List<Log>();
	//contains all collapsed logs
	List<Log> collapsedLogs = new List<Log>();
	//contain logs which should only appear to user , for example if you switch off show logs + switch off show warnings
	//and your mode is collapse,then this list will contains only collapsed errors
	List<Log> currentLog = new List<Log>();

	//used to check if the new coming logs is already exist or new one
	MultiKeyDictionary<string, string, Log> logsDic = new MultiKeyDictionary<string, string, Log>();
	//to save memory
	Dictionary<string, string> cachedString = new Dictionary<string, string>();

	[HideInInspector]
	//show hide In Game Logs
	public bool show = false;
	//collapse logs
	bool collapse;
	//to decide if you want to clean logs for new loaded scene
	bool clearOnNewSceneLoaded;

	bool showTime;

	bool showScene;

	bool showMemory;

	bool showFps;

	bool showGraph;

	//show or hide logs
	bool showLog = true;
	//show or hide warnings
	bool showWarning = true;
	//show or hide errors
	bool showError = true;

	//total number of logs
	int numOfLogs = 0;
	//total number of warnings
	int numOfLogsWarning = 0;
	//total number of errors
	int numOfLogsError = 0;
	//total number of collapsed logs
	int numOfCollapsedLogs = 0;
	//total number of collapsed warnings
	int numOfCollapsedLogsWarning = 0;
	//total number of collapsed errors
	int numOfCollapsedLogsError = 0;

	//maximum number of allowed logs to view
	//public int maxAllowedLog = 1000 ;

	bool showClearOnNewSceneLoadedButton = true;
	bool showTimeButton = true;
	bool showSceneButton = true;
	bool showMemButton = true;
	bool showFpsButton = true;
	bool showSearchText = true;
    bool showCopyButton = true;
    bool showSaveButton = true;

    string buildDate;
	string logDate;
	float logsMemUsage;
	float graphMemUsage;
	public float TotalMemUsage
	{
		get
		{
			return logsMemUsage + graphMemUsage;
		}
	}
	float gcTotalMemory;
	public string UserData = "";
	//frame rate per second
	public float fps;
	public string fpsText;

	//List<Texture2D> snapshots = new List<Texture2D>() ;

	enum ReportView
	{
		None,
		Logs,
		Info,
		Snapshot,
	}
	ReportView currentView = ReportView.Logs;
	enum DetailView
	{
		None,
		StackTrace,
		Graph,
	}

	//used to check if you have In Game Logs multiple time in different scene
	//only one should work and other should be deleted
	static bool created = false;
	//public delegate void OnLogHandler( string condition, string stack-trace, LogType type );
	//public event OnLogHandler OnLog ;

	public Images images;
	// gui
	GUIContent clearContent;
	GUIContent collapseContent;
	GUIContent clearOnNewSceneContent;
	GUIContent showTimeContent;
	GUIContent showSceneContent;
	GUIContent userContent;
	GUIContent showMemoryContent;
	GUIContent softwareContent;
	GUIContent dateContent;
	GUIContent showFpsContent;
	//GUIContent graphContent;
	GUIContent infoContent;
    GUIContent saveLogsContent;
	GUIContent searchContent;
    GUIContent copyContent;
    GUIContent closeContent;

	GUIContent buildFromContent;
	GUIContent systemInfoContent;
	GUIContent graphicsInfoContent;
	GUIContent backContent;

	//GUIContent cameraContent;

	GUIContent logContent;
	GUIContent warningContent;
	GUIContent errorContent;
	GUIStyle barStyle;
	GUIStyle buttonActiveStyle;

	GUIStyle nonStyle;
	GUIStyle lowerLeftFontStyle;
	GUIStyle backStyle;
	GUIStyle evenLogStyle;
	GUIStyle oddLogStyle;
	GUIStyle logButtonStyle;
	GUIStyle selectedLogStyle;
	GUIStyle selectedLogFontStyle;
	GUIStyle stackLabelStyle;
	GUIStyle scrollerStyle;
	GUIStyle searchStyle;
	GUIStyle sliderBackStyle;
	GUIStyle sliderThumbStyle;
	GUISkin toolbarScrollerSkin;
	GUISkin logScrollerSkin;
	GUISkin graphScrollerSkin;

	public Vector2 size = new Vector2(32, 32);
	public float maxSize = 20;
	public int numOfCircleToShow = 1;
	static string[] scenes;
	string currentScene;
	string filterText = "";

	string deviceModel;
	string deviceType;
	string deviceName;
	string graphicsMemorySize;
#if !UNITY_CHANGE1
	string maxTextureSize;
#endif
	string systemMemorySize;

	void Awake()
	{
		if (!Initialized)
			Initialize();

#if UNITY_CHANGE3
        SceneManager.sceneLoaded += _OnLevelWasLoaded;
#endif
    }

    private void OnDestroy()
    {
#if UNITY_CHANGE3
        SceneManager.sceneLoaded -= _OnLevelWasLoaded;
#endif
    }

    void OnEnable()
	{
		if (logs.Count == 0)//if recompile while in play mode
			clear();
	}

	void OnDisable()
	{

	}

	void addSample()
	{
		Sample sample = new Sample();
		sample.fps = fps;
		sample.fpsText = fpsText;
#if UNITY_CHANGE3
		sample.loadedScene = (byte)SceneManager.GetActiveScene().buildIndex;
#else
		sample.loadedScene = (byte)Application.loadedLevel;
#endif
		sample.time = Time.realtimeSinceStartup;
		sample.memory = gcTotalMemory;
		samples.Add(sample);

		graphMemUsage = (samples.Count * Sample.MemSize()) / 1024 / 1024;
	}

	public bool Initialized = false;
	public void Initialize()
	{
		if (!created) {
			try {
				gameObject.SendMessage("OnPreStart");
			}
			catch (System.Exception e) {
				Debug.LogException(e);
			}
#if UNITY_CHANGE3
			scenes = new string[ SceneManager.sceneCountInBuildSettings ];
			currentScene = SceneManager.GetActiveScene().name;
#else
			scenes = new string[Application.levelCount];
			currentScene = Application.loadedLevelName;
#endif
			DontDestroyOnLoad(gameObject);
#if UNITY_CHANGE1
			Application.RegisterLogCallback (new Application.LogCallback (CaptureLog));
			Application.RegisterLogCallbackThreaded (new Application.LogCallback (CaptureLogThread));
#else
			//Application.logMessageReceived += CaptureLog ;
			Application.logMessageReceivedThreaded += CaptureLogThread;
#endif
			created = true;
			//addSample();
		}
		else {
			Debug.LogWarning("tow manager is exists delete the second");
			DestroyImmediate(gameObject, true);
			return;
		}


		//initialize gui and styles for gui purpose

		clearContent = new GUIContent("", images.clearImage, "Clear logs");
		collapseContent = new GUIContent("", images.collapseImage, "Collapse logs");
		clearOnNewSceneContent = new GUIContent("", images.clearOnNewSceneImage, "Clear logs on new scene loaded");
		showTimeContent = new GUIContent("", images.showTimeImage, "Show Hide Time");
		showSceneContent = new GUIContent("", images.showSceneImage, "Show Hide Scene");
		showMemoryContent = new GUIContent("", images.showMemoryImage, "Show Hide Memory");
		softwareContent = new GUIContent("", images.softwareImage, "Software");
		dateContent = new GUIContent("", images.dateImage, "Date");
		showFpsContent = new GUIContent("", images.showFpsImage, "Show Hide fps");
		infoContent = new GUIContent("", images.infoImage, "Information about application");
        saveLogsContent = new GUIContent("", images.saveLogsImage, "Save logs to device");
        searchContent = new GUIContent("", images.searchImage, "Search for logs");
        copyContent = new GUIContent("", images.copyImage, "Copy log to clipboard");
        closeContent = new GUIContent("", images.closeImage, "Hide logs");
		userContent = new GUIContent("", images.userImage, "User");

		buildFromContent = new GUIContent("", images.buildFromImage, "Build From");
		systemInfoContent = new GUIContent("", images.systemInfoImage, "System Info");
		graphicsInfoContent = new GUIContent("", images.graphicsInfoImage, "Graphics Info");
		backContent = new GUIContent("", images.backImage, "Back");


		//snapshotContent = new GUIContent("",images.cameraImage,"show or hide logs");
		logContent = new GUIContent("", images.logImage, "show or hide logs");
		warningContent = new GUIContent("", images.warningImage, "show or hide warnings");
		errorContent = new GUIContent("", images.errorImage, "show or hide errors");


		currentView = (ReportView)PlayerPrefs.GetInt("Reporter_currentView", 1);
		show = (PlayerPrefs.GetInt("Reporter_show") == 1) ? true : false;
		collapse = (PlayerPrefs.GetInt("Reporter_collapse") == 1) ? true : false;
		clearOnNewSceneLoaded = (PlayerPrefs.GetInt("Reporter_clearOnNewSceneLoaded") == 1) ? true : false;
		showTime = (PlayerPrefs.GetInt("Reporter_showTime") == 1) ? true : false;
		showScene = (PlayerPrefs.GetInt("Reporter_showScene") == 1) ? true : false;
		showMemory = (PlayerPrefs.GetInt("Reporter_showMemory") == 1) ? true : false;
		showFps = (PlayerPrefs.GetInt("Reporter_showFps") == 1) ? true : false;
		showGraph = (PlayerPrefs.GetInt("Reporter_showGraph") == 1) ? true : false;
		showLog = (PlayerPrefs.GetInt("Reporter_showLog", 1) == 1) ? true : false;
		showWarning = (PlayerPrefs.GetInt("Reporter_showWarning", 1) == 1) ? true : false;
		showError = (PlayerPrefs.GetInt("Reporter_showError", 1) == 1) ? true : false;
		filterText = PlayerPrefs.GetString("Reporter_filterText");
		size.x = size.y = PlayerPrefs.GetFloat("Reporter_size", 32);


		showClearOnNewSceneLoadedButton = (PlayerPrefs.GetInt("Reporter_showClearOnNewSceneLoadedButton", 1) == 1) ? true : false;
		showTimeButton = (PlayerPrefs.GetInt("Reporter_showTimeButton", 1) == 1) ? true : false;
		showSceneButton = (PlayerPrefs.GetInt("Reporter_showSceneButton", 1) == 1) ? true : false;
		showMemButton = (PlayerPrefs.GetInt("Reporter_showMemButton", 1) == 1) ? true : false;
		showFpsButton = (PlayerPrefs.GetInt("Reporter_showFpsButton", 1) == 1) ? true : false;
		showSearchText = (PlayerPrefs.GetInt("Reporter_showSearchText", 1) == 1) ? true : false;
        showCopyButton = (PlayerPrefs.GetInt("Reporter_showCopyButton", 1) == 1) ? true : false;
        showSaveButton = (PlayerPrefs.GetInt("Reporter_showSaveButton", 1) == 1) ? true : false;


        initializeStyle();

		Initialized = true;

		if (show) {
			doShow();
		}

		deviceModel = SystemInfo.deviceModel.ToString();
		deviceType = SystemInfo.deviceType.ToString();
		deviceName = SystemInfo.deviceName.ToString();
		graphicsMemorySize = SystemInfo.graphicsMemorySize.ToString();
#if !UNITY_CHANGE1
		maxTextureSize = SystemInfo.maxTextureSize.ToString();
#endif
		systemMemorySize = SystemInfo.systemMemorySize.ToString();

	}

	void initializeStyle()
	{
		int paddingX = (int)(size.x * 0.2f);
		int paddingY = (int)(size.y * 0.2f);
		nonStyle = new GUIStyle();
		nonStyle.clipping = TextClipping.Clip;
		nonStyle.border = new RectOffset(0, 0, 0, 0);
		nonStyle.normal.background = null;
		nonStyle.fontSize = (int)(size.y / 2);
		nonStyle.alignment = TextAnchor.MiddleCenter;

		lowerLeftFontStyle = new GUIStyle();
		lowerLeftFontStyle.clipping = TextClipping.Clip;
		lowerLeftFontStyle.border = new RectOffset(0, 0, 0, 0);
		lowerLeftFontStyle.normal.background = null;
		lowerLeftFontStyle.fontSize = (int)(size.y / 2);
		lowerLeftFontStyle.fontStyle = FontStyle.Bold;
		lowerLeftFontStyle.alignment = TextAnchor.LowerLeft;


		barStyle = new GUIStyle();
		barStyle.border = new RectOffset(1, 1, 1, 1);
		barStyle.normal.background = images.barImage;
		barStyle.active.background = images.button_activeImage;
		barStyle.alignment = TextAnchor.MiddleCenter;
		barStyle.margin = new RectOffset(1, 1, 1, 1);

		//barStyle.padding = new RectOffset(paddingX,paddingX,paddingY,paddingY); 
		//barStyle.wordWrap = true ;
		barStyle.clipping = TextClipping.Clip;
		barStyle.fontSize = (int)(size.y / 2);


		buttonActiveStyle = new GUIStyle();
		buttonActiveStyle.border = new RectOffset(1, 1, 1, 1);
		buttonActiveStyle.normal.background = images.button_activeImage;
		buttonActiveStyle.alignment = TextAnchor.MiddleCenter;
		buttonActiveStyle.margin = new RectOffset(1, 1, 1, 1);
		//buttonActiveStyle.padding = new RectOffset(4,4,4,4);
		buttonActiveStyle.fontSize = (int)(size.y / 2);

		backStyle = new GUIStyle();
		backStyle.normal.background = images.even_logImage;
		backStyle.clipping = TextClipping.Clip;
		backStyle.fontSize = (int)(size.y / 2);

		evenLogStyle = new GUIStyle();
		evenLogStyle.normal.background = images.even_logImage;
		evenLogStyle.fixedHeight = size.y;
		evenLogStyle.clipping = TextClipping.Clip;
		evenLogStyle.alignment = TextAnchor.UpperLeft;
		evenLogStyle.imagePosition = ImagePosition.ImageLeft;
		evenLogStyle.fontSize = (int)(size.y / 2);
		//evenLogStyle.wordWrap = true;

		oddLogStyle = new GUIStyle();
		oddLogStyle.normal.background = images.odd_logImage;
		oddLogStyle.fixedHeight = size.y;
		oddLogStyle.clipping = TextClipping.Clip;
		oddLogStyle.alignment = TextAnchor.UpperLeft;
		oddLogStyle.imagePosition = ImagePosition.ImageLeft;
		oddLogStyle.fontSize = (int)(size.y / 2);
		//oddLogStyle.wordWrap = true ;

		logButtonStyle = new GUIStyle();
		//logButtonStyle.wordWrap = true;
		logButtonStyle.fixedHeight = size.y;
		logButtonStyle.clipping = TextClipping.Clip;
		logButtonStyle.alignment = TextAnchor.UpperLeft;
		//logButtonStyle.imagePosition = ImagePosition.ImageLeft ;
		//logButtonStyle.wordWrap = true;
		logButtonStyle.fontSize = (int)(size.y / 2);
		logButtonStyle.padding = new RectOffset(paddingX, paddingX, paddingY, paddingY);

		selectedLogStyle = new GUIStyle();
		selectedLogStyle.normal.background = images.selectedImage;
		selectedLogStyle.fixedHeight = size.y;
		selectedLogStyle.clipping = TextClipping.Clip;
		selectedLogStyle.alignment = TextAnchor.UpperLeft;
		selectedLogStyle.normal.textColor = Color.white;
		//selectedLogStyle.wordWrap = true;
		selectedLogStyle.fontSize = (int)(size.y / 2);

		selectedLogFontStyle = new GUIStyle();
		selectedLogFontStyle.normal.background = images.selectedImage;
		selectedLogFontStyle.fixedHeight = size.y;
		selectedLogFontStyle.clipping = TextClipping.Clip;
		selectedLogFontStyle.alignment = TextAnchor.UpperLeft;
		selectedLogFontStyle.normal.textColor = Color.white;
		//selectedLogStyle.wordWrap = true;
		selectedLogFontStyle.fontSize = (int)(size.y / 2);
		selectedLogFontStyle.padding = new RectOffset(paddingX, paddingX, paddingY, paddingY);

		stackLabelStyle = new GUIStyle();
		stackLabelStyle.wordWrap = true;
		stackLabelStyle.fontSize = (int)(size.y / 2);
		stackLabelStyle.padding = new RectOffset(paddingX, paddingX, paddingY, paddingY);

		scrollerStyle = new GUIStyle();
		scrollerStyle.normal.background = images.barImage;

		searchStyle = new GUIStyle();
		searchStyle.clipping = TextClipping.Clip;
		searchStyle.alignment = TextAnchor.LowerCenter;
		searchStyle.fontSize = (int)(size.y / 2);
		searchStyle.wordWrap = true;


		sliderBackStyle = new GUIStyle();
		sliderBackStyle.normal.background = images.barImage;
		sliderBackStyle.fixedHeight = size.y;
		sliderBackStyle.border = new RectOffset(1, 1, 1, 1);

		sliderThumbStyle = new GUIStyle();
		sliderThumbStyle.normal.background = images.selectedImage;
		sliderThumbStyle.fixedWidth = size.x;

		GUISkin skin = images.reporterScrollerSkin;

		toolbarScrollerSkin = (GUISkin)GameObject.Instantiate(skin);
		toolbarScrollerSkin.verticalScrollbar.fixedWidth = 0f;
		toolbarScrollerSkin.horizontalScrollbar.fixedHeight = 0f;
		toolbarScrollerSkin.verticalScrollbarThumb.fixedWidth = 0f;
		toolbarScrollerSkin.horizontalScrollbarThumb.fixedHeight = 0f;

		logScrollerSkin = (GUISkin)GameObject.Instantiate(skin);
		logScrollerSkin.verticalScrollbar.fixedWidth = size.x * 2f;
		logScrollerSkin.horizontalScrollbar.fixedHeight = 0f;
		logScrollerSkin.verticalScrollbarThumb.fixedWidth = size.x * 2f;
		logScrollerSkin.horizontalScrollbarThumb.fixedHeight = 0f;

		graphScrollerSkin = (GUISkin)GameObject.Instantiate(skin);
		graphScrollerSkin.verticalScrollbar.fixedWidth = 0f;
		graphScrollerSkin.horizontalScrollbar.fixedHeight = size.x * 2f;
		graphScrollerSkin.verticalScrollbarThumb.fixedWidth = 0f;
		graphScrollerSkin.horizontalScrollbarThumb.fixedHeight = size.x * 2f;
		//inGameLogsScrollerSkin.verticalScrollbarThumb.fixedWidth = size.x * 2;
		//inGameLogsScrollerSkin.verticalScrollbar.fixedWidth = size.x * 2;
	}

	void Start()
	{
		logDate = System.DateTime.Now.ToString();
		StartCoroutine("readInfo");
	}

	//clear all logs
	void clear()
	{
		logs.Clear();
		collapsedLogs.Clear();
		currentLog.Clear();
		logsDic.Clear();
		//selectedIndex = -1;
		selectedLog = null;
		numOfLogs = 0;
		numOfLogsWarning = 0;
		numOfLogsError = 0;
		numOfCollapsedLogs = 0;
		numOfCollapsedLogsWarning = 0;
		numOfCollapsedLogsError = 0;
		logsMemUsage = 0;
		graphMemUsage = 0;
		samples.Clear();
		System.GC.Collect();
		selectedLog = null;
	}

	Rect screenRect = Rect.zero;
	Rect toolBarRect = Rect.zero;
	Rect logsRect = Rect.zero;
	Rect stackRect = Rect.zero;
	Rect graphRect = Rect.zero;
	Rect graphMinRect = Rect.zero;
	Rect graphMaxRect = Rect.zero;
	Rect buttomRect = Rect.zero ;
	Vector2 stackRectTopLeft;
	Rect detailRect = Rect.zero;

	Vector2 scrollPosition;
	Vector2 scrollPosition2;
	Vector2 toolbarScrollPosition;

	//int 	selectedIndex = -1;
	Log selectedLog;

	float toolbarOldDrag = 0;
	float oldDrag;
	float oldDrag2;
	float oldDrag3;
	int startIndex;

	//calculate what is the currentLog : collapsed or not , hide or view warnings ......
	void calculateCurrentLog()
	{
		bool filter = !string.IsNullOrEmpty(filterText);
		string _filterText = "";
		if (filter)
			_filterText = filterText.ToLower();
		currentLog.Clear();
		if (collapse) {
			for (int i = 0; i < collapsedLogs.Count; i++) {
				Log log = collapsedLogs[i];
				if (log.logType == _LogType.Log && !showLog)
					continue;
				if (log.logType == _LogType.Warning && !showWarning)
					continue;
				if (log.logType == _LogType.Error && !showError)
					continue;
				if (log.logType == _LogType.Assert && !showError)
					continue;
				if (log.logType == _LogType.Exception && !showError)
					continue;

				if (filter) {
					if (log.condition.ToLower().Contains(_filterText))
						currentLog.Add(log);
				}
				else {
					currentLog.Add(log);
				}
			}
		}
		else {
			for (int i = 0; i < logs.Count; i++) {
				Log log = logs[i];
				if (log.logType == _LogType.Log && !showLog)
					continue;
				if (log.logType == _LogType.Warning && !showWarning)
					continue;
				if (log.logType == _LogType.Error && !showError)
					continue;
				if (log.logType == _LogType.Assert && !showError)
					continue;
				if (log.logType == _LogType.Exception && !showError)
					continue;

				if (filter) {
					if (log.condition.ToLower().Contains(_filterText))
						currentLog.Add(log);
				}
				else {
					currentLog.Add(log);
				}
			}
		}

		if (selectedLog != null) {
			int newSelectedIndex = currentLog.IndexOf(selectedLog);
			if (newSelectedIndex == -1) {
				Log collapsedSelected = logsDic[selectedLog.condition][selectedLog.stacktrace];
				newSelectedIndex = currentLog.IndexOf(collapsedSelected);
				if (newSelectedIndex != -1)
					scrollPosition.y = newSelectedIndex * size.y;
			}
			else {
				scrollPosition.y = newSelectedIndex * size.y;
			}
		}
	}

	Rect countRect = Rect.zero;
	Rect timeRect = Rect.zero;
	Rect timeLabelRect = Rect.zero;
	Rect sceneRect = Rect.zero;
	Rect sceneLabelRect = Rect.zero;
	Rect memoryRect = Rect.zero;
	Rect memoryLabelRect = Rect.zero;
	Rect fpsRect = Rect.zero;
	Rect fpsLabelRect = Rect.zero;
	GUIContent tempContent = new GUIContent();


	Vector2 infoScrollPosition;
	Vector2 oldInfoDrag;
	void DrawInfo()
	{

		GUILayout.BeginArea(screenRect, backStyle);

		Vector2 drag = getDrag();
		if ((drag.x != 0) && (downPos != Vector2.zero)) {
			infoScrollPosition.x -= (drag.x - oldInfoDrag.x);
		}
		if ((drag.y != 0) && (downPos != Vector2.zero)) {
			infoScrollPosition.y += (drag.y - oldInfoDrag.y);
		}
		oldInfoDrag = drag;

		GUI.skin = toolbarScrollerSkin;
		infoScrollPosition = GUILayout.BeginScrollView(infoScrollPosition);
		GUILayout.Space(size.x);
		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(buildFromContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(buildDate, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(systemInfoContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(deviceModel, nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(deviceType, nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(deviceName, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(graphicsInfoContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(SystemInfo.graphicsDeviceName, nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(graphicsMemorySize, nonStyle, GUILayout.Height(size.y));
#if !UNITY_CHANGE1
		GUILayout.Space(size.x);
		GUILayout.Label(maxTextureSize, nonStyle, GUILayout.Height(size.y));
#endif
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Space(size.x);
		GUILayout.Space(size.x);
		GUILayout.Label("Screen Width " + Screen.width, nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label("Screen Height " + Screen.height, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(showMemoryContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(systemMemorySize + " mb", nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Space(size.x);
		GUILayout.Space(size.x);
		GUILayout.Label("Mem Usage Of Logs " + logsMemUsage.ToString("0.000") + " mb", nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		//GUILayout.Label( "Mem Usage Of Graph " + graphMemUsage.ToString("0.000")  + " mb", nonStyle , GUILayout.Height(size.y));
		//GUILayout.Space( size.x);
		GUILayout.Label("GC Memory " + gcTotalMemory.ToString("0.000") + " mb", nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(softwareContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(SystemInfo.operatingSystem, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();


		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(dateContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(System.DateTime.Now.ToString(), nonStyle, GUILayout.Height(size.y));
		GUILayout.Label(" - Application Started At " + logDate, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(showTimeContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(Time.realtimeSinceStartup.ToString("000"), nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(showFpsContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(fpsText, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(userContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(UserData, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(showSceneContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label(currentScene, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Box(showSceneContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.Label("Unity Version = " + Application.unityVersion, nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		/*GUILayout.BeginHorizontal();
		GUILayout.Space( size.x);
		GUILayout.Box( graphContent ,nonStyle ,  GUILayout.Width(size.x) , GUILayout.Height(size.y));
		GUILayout.Space( size.x);
		GUILayout.Label( "frame " + samples.Count , nonStyle , GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();*/

		drawInfo_enableDisableToolBarButtons();

		GUILayout.FlexibleSpace();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Label("Size = " + size.x.ToString("0.0"), nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		float _size = GUILayout.HorizontalSlider(size.x, 16, 64, sliderBackStyle, sliderThumbStyle, GUILayout.Width(Screen.width * 0.5f));
		if (size.x != _size) {
			size.x = size.y = _size;
			initializeStyle();
		}
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		if (GUILayout.Button(backContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			currentView = ReportView.Logs;
		}
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();



		GUILayout.EndScrollView();

		GUILayout.EndArea();
	}


	void drawInfo_enableDisableToolBarButtons()
	{
		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);
		GUILayout.Label("Hide or Show tool bar buttons", nonStyle, GUILayout.Height(size.y));
		GUILayout.Space(size.x);
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Space(size.x);

		if (GUILayout.Button(clearOnNewSceneContent, (showClearOnNewSceneLoadedButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showClearOnNewSceneLoadedButton = !showClearOnNewSceneLoadedButton;
		}

		if (GUILayout.Button(showTimeContent, (showTimeButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showTimeButton = !showTimeButton;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label(tempRect, Time.realtimeSinceStartup.ToString("0.0"), lowerLeftFontStyle);
		if (GUILayout.Button(showSceneContent, (showSceneButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showSceneButton = !showSceneButton;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label(tempRect, currentScene, lowerLeftFontStyle);
		if (GUILayout.Button(showMemoryContent, (showMemButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showMemButton = !showMemButton;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label(tempRect, gcTotalMemory.ToString("0.0"), lowerLeftFontStyle);

		if (GUILayout.Button(showFpsContent, (showFpsButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showFpsButton = !showFpsButton;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label(tempRect, fpsText, lowerLeftFontStyle);
		/*if( GUILayout.Button( graphContent , (showGraph)?buttonActiveStyle:barStyle , GUILayout.Width(size.x*2) ,GUILayout.Height(size.y*2)))
		{
			showGraph = !showGraph ;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label( tempRect , samples.Count.ToString() , lowerLeftFontStyle );*/
		if (GUILayout.Button(searchContent, (showSearchText) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showSearchText = !showSearchText;
		}
        if (GUILayout.Button(copyContent, (showCopyButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2)))
        {
            showCopyButton = !showCopyButton;
        }
        if (GUILayout.Button(saveLogsContent, (showSaveButton) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2)))
        {
            showSaveButton = !showSaveButton;
        }
        tempRect = GUILayoutUtility.GetLastRect();
		GUI.TextField(tempRect, filterText, searchStyle);


		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();
	}

	void DrawReport()
	{
		screenRect.x = 0f;
		screenRect.y = 0f;
		screenRect.width = Screen.width;
		screenRect.height = Screen.height;
		GUILayout.BeginArea(screenRect, backStyle);
		GUILayout.BeginVertical();
		GUILayout.FlexibleSpace();

		GUILayout.BeginHorizontal();
		GUILayout.FlexibleSpace();
		/*GUILayout.Box( cameraContent ,nonStyle ,  GUILayout.Width(size.x) , GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();*/
		GUILayout.Label("Select Photo", nonStyle, GUILayout.Height(size.y));
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.Label("Coming Soon", nonStyle, GUILayout.Height(size.y));
		GUILayout.EndHorizontal();

		GUILayout.BeginHorizontal();
		GUILayout.FlexibleSpace();
		if (GUILayout.Button(backContent, barStyle, GUILayout.Width(size.x), GUILayout.Height(size.y))) {
			currentView = ReportView.Logs;
		}
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();

		GUILayout.FlexibleSpace();
		GUILayout.EndVertical();
		GUILayout.EndArea();
	}

	void drawToolBar()
	{

		toolBarRect.x = 0f;
		toolBarRect.y = 0f;
		toolBarRect.width = Screen.width;
		toolBarRect.height = size.y * 2f;

		//toolbarScrollerSkin.verticalScrollbar.fixedWidth = 0f;
		//toolbarScrollerSkin.horizontalScrollbar.fixedHeight= 0f  ;

		GUI.skin = toolbarScrollerSkin;
		Vector2 drag = getDrag();
		if ((drag.x != 0) && (downPos != Vector2.zero) && (downPos.y > Screen.height - size.y * 2f)) {
			toolbarScrollPosition.x -= (drag.x - toolbarOldDrag);
		}
		toolbarOldDrag = drag.x;
		GUILayout.BeginArea(toolBarRect);
		toolbarScrollPosition = GUILayout.BeginScrollView(toolbarScrollPosition);
		GUILayout.BeginHorizontal(barStyle);

		if (GUILayout.Button(clearContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			clear();
		}
		if (GUILayout.Button(collapseContent, (collapse) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			collapse = !collapse;
			calculateCurrentLog();
		}
		if (showClearOnNewSceneLoadedButton && GUILayout.Button(clearOnNewSceneContent, (clearOnNewSceneLoaded) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			clearOnNewSceneLoaded = !clearOnNewSceneLoaded;
		}

		if (showTimeButton && GUILayout.Button(showTimeContent, (showTime) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showTime = !showTime;
		}
		if (showSceneButton) {
			tempRect = GUILayoutUtility.GetLastRect();
			GUI.Label(tempRect, Time.realtimeSinceStartup.ToString("0.0"), lowerLeftFontStyle);
			if (GUILayout.Button(showSceneContent, (showScene) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
				showScene = !showScene;
			}
			tempRect = GUILayoutUtility.GetLastRect();
			GUI.Label(tempRect, currentScene, lowerLeftFontStyle);
		}
		if (showMemButton) {
			if (GUILayout.Button(showMemoryContent, (showMemory) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
				showMemory = !showMemory;
			}
			tempRect = GUILayoutUtility.GetLastRect();
			GUI.Label(tempRect, gcTotalMemory.ToString("0.0"), lowerLeftFontStyle);
		}
		if (showFpsButton) {
			if (GUILayout.Button(showFpsContent, (showFps) ? buttonActiveStyle : barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
				showFps = !showFps;
			}
			tempRect = GUILayoutUtility.GetLastRect();
			GUI.Label(tempRect, fpsText, lowerLeftFontStyle);
		}
		/*if( GUILayout.Button( graphContent , (showGraph)?buttonActiveStyle:barStyle , GUILayout.Width(size.x*2) ,GUILayout.Height(size.y*2)))
		{
			showGraph = !showGraph ;
		}
		tempRect = GUILayoutUtility.GetLastRect();
		GUI.Label( tempRect , samples.Count.ToString() , lowerLeftFontStyle );*/

		if (showSearchText) {
			GUILayout.Box(searchContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2));
			tempRect = GUILayoutUtility.GetLastRect();
			string newFilterText = GUI.TextField(tempRect, filterText, searchStyle);
			if (newFilterText != filterText) {
				filterText = newFilterText;
				calculateCurrentLog();
			}
		}

        if (showCopyButton)
        {
            if (GUILayout.Button(copyContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2)))
            {
                if (selectedLog == null)
                    GUIUtility.systemCopyBuffer = "No log selected";
                else
                    GUIUtility.systemCopyBuffer = selectedLog.condition + System.Environment.NewLine + System.Environment.NewLine  + selectedLog.stacktrace;
            }
        }

        if (showSaveButton)
        {
            if (GUILayout.Button(saveLogsContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2)))
            {
                SaveLogsToDevice();
            }
        }

        if (GUILayout.Button(infoContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			currentView = ReportView.Info;
		}
       


        GUILayout.FlexibleSpace();


		string logsText = " ";
		if (collapse) {
			logsText += numOfCollapsedLogs;
		}
		else {
			logsText += numOfLogs;
		}
		string logsWarningText = " ";
		if (collapse) {
			logsWarningText += numOfCollapsedLogsWarning;
		}
		else {
			logsWarningText += numOfLogsWarning;
		}
		string logsErrorText = " ";
		if (collapse) {
			logsErrorText += numOfCollapsedLogsError;
		}
		else {
			logsErrorText += numOfLogsError;
		}

		GUILayout.BeginHorizontal((showLog) ? buttonActiveStyle : barStyle);
		if (GUILayout.Button(logContent, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showLog = !showLog;
			calculateCurrentLog();
		}
		if (GUILayout.Button(logsText, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showLog = !showLog;
			calculateCurrentLog();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((showWarning) ? buttonActiveStyle : barStyle);
		if (GUILayout.Button(warningContent, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showWarning = !showWarning;
			calculateCurrentLog();
		}
		if (GUILayout.Button(logsWarningText, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showWarning = !showWarning;
			calculateCurrentLog();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal((showError) ? buttonActiveStyle : nonStyle);
		if (GUILayout.Button(errorContent, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showError = !showError;
			calculateCurrentLog();
		}
		if (GUILayout.Button(logsErrorText, nonStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			showError = !showError;
			calculateCurrentLog();
		}
		GUILayout.EndHorizontal();

		if (GUILayout.Button(closeContent, barStyle, GUILayout.Width(size.x * 2), GUILayout.Height(size.y * 2))) {
			show = false;
			ReporterGUI gui = gameObject.GetComponent<ReporterGUI>();
			DestroyImmediate(gui);

			try {
				gameObject.SendMessage("OnHideReporter");
			}
			catch (System.Exception e) {
				Debug.LogException(e);
			}
		}


		GUILayout.EndHorizontal();

		GUILayout.EndScrollView();

		GUILayout.EndArea();
	}


	Rect tempRect;
	void DrawLogs()
	{

		GUILayout.BeginArea(logsRect, backStyle);

		GUI.skin = logScrollerSkin;
		//setStartPos();
		Vector2 drag = getDrag();

		if (drag.y != 0 && logsRect.Contains(new Vector2(downPos.x, Screen.height - downPos.y))) {
			scrollPosition.y += (drag.y - oldDrag);
		}
		scrollPosition = GUILayout.BeginScrollView(scrollPosition);

		oldDrag = drag.y;


		int totalVisibleCount = (int)(Screen.height * 0.75f / size.y);
		int totalCount = currentLog.Count;
		/*if( totalCount < 100 )
			inGameLogsScrollerSkin.verticalScrollbarThumb.fixedHeight = 0;
		else 
			inGameLogsScrollerSkin.verticalScrollbarThumb.fixedHeight = 64;*/

		totalVisibleCount = Mathf.Min(totalVisibleCount, totalCount - startIndex);
		int index = 0;
		int beforeHeight = (int)(startIndex * size.y);
		//selectedIndex = Mathf.Clamp( selectedIndex , -1 , totalCount -1);
		if (beforeHeight > 0) {
			//fill invisible gap before scroller to make proper scroller pos
			GUILayout.BeginHorizontal(GUILayout.Height(beforeHeight));
			GUILayout.Label("---");
			GUILayout.EndHorizontal();
		}

		int endIndex = startIndex + totalVisibleCount;
		endIndex = Mathf.Clamp(endIndex, 0, totalCount);
		bool scrollerVisible = (totalVisibleCount < totalCount);
		for (int i = startIndex; (startIndex + index) < endIndex; i++) {

			if (i >= currentLog.Count)
				break;
			Log log = currentLog[i];

			if (log.logType == _LogType.Log && !showLog)
				continue;
			if (log.logType == _LogType.Warning && !showWarning)
				continue;
			if (log.logType == _LogType.Error && !showError)
				continue;
			if (log.logType == _LogType.Assert && !showError)
				continue;
			if (log.logType == _LogType.Exception && !showError)
				continue;

			if (index >= totalVisibleCount) {
				break;
			}

			GUIContent content = null;
			if (log.logType == _LogType.Log)
				content = logContent;
			else if (log.logType == _LogType.Warning)
				content = warningContent;
			else
				content = errorContent;
			//content.text = log.condition ;

			GUIStyle currentLogStyle = ((startIndex + index) % 2 == 0) ? evenLogStyle : oddLogStyle;
			if (log == selectedLog) {
				//selectedLog = log ;
				currentLogStyle = selectedLogStyle;
			}
			else {
			}

			tempContent.text = log.count.ToString();
			float w = 0f;
			if (collapse)
				w = barStyle.CalcSize(tempContent).x + 3;
			countRect.x = Screen.width - w;
			countRect.y = size.y * i;
			if (beforeHeight > 0)
				countRect.y += 8;//i will check later why
			countRect.width = w;
			countRect.height = size.y;

			if (scrollerVisible)
				countRect.x -= size.x * 2;

			Sample sample = samples[log.sampleId];
			fpsRect = countRect;
			if (showFps) {
				tempContent.text = sample.fpsText;
				w = currentLogStyle.CalcSize(tempContent).x + size.x;
				fpsRect.x -= w;
				fpsRect.width = size.x;
				fpsLabelRect = fpsRect;
				fpsLabelRect.x += size.x;
				fpsLabelRect.width = w - size.x;
			}


			memoryRect = fpsRect;
			if (showMemory) {
				tempContent.text = sample.memory.ToString("0.000");
				w = currentLogStyle.CalcSize(tempContent).x + size.x;
				memoryRect.x -= w;
				memoryRect.width = size.x;
				memoryLabelRect = memoryRect;
				memoryLabelRect.x += size.x;
				memoryLabelRect.width = w - size.x;
			}
			sceneRect = memoryRect;
			if (showScene) {

				tempContent.text = sample.GetSceneName();
				w = currentLogStyle.CalcSize(tempContent).x + size.x;
				sceneRect.x -= w;
				sceneRect.width = size.x;
				sceneLabelRect = sceneRect;
				sceneLabelRect.x += size.x;
				sceneLabelRect.width = w - size.x;
			}
			timeRect = sceneRect;
			if (showTime) {
				tempContent.text = sample.time.ToString("0.000");
				w = currentLogStyle.CalcSize(tempContent).x + size.x;
				timeRect.x -= w;
				timeRect.width = size.x;
				timeLabelRect = timeRect;
				timeLabelRect.x += size.x;
				timeLabelRect.width = w - size.x;
			}



			GUILayout.BeginHorizontal(currentLogStyle);
			if (log == selectedLog) {
				GUILayout.Box(content, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
				GUILayout.Label(log.condition, selectedLogFontStyle);
				//GUILayout.FlexibleSpace();
				if (showTime) {
					GUI.Box(timeRect, showTimeContent, currentLogStyle);
					GUI.Label(timeLabelRect, sample.time.ToString("0.000"), currentLogStyle);
				}
				if (showScene) {
					GUI.Box(sceneRect, showSceneContent, currentLogStyle);
					GUI.Label(sceneLabelRect, sample.GetSceneName(), currentLogStyle);
				}
				if (showMemory) {
					GUI.Box(memoryRect, showMemoryContent, currentLogStyle);
					GUI.Label(memoryLabelRect, sample.memory.ToString("0.000") + " mb", currentLogStyle);
				}
				if (showFps) {
					GUI.Box(fpsRect, showFpsContent, currentLogStyle);
					GUI.Label(fpsLabelRect, sample.fpsText, currentLogStyle);
				}


			}
			else {
				if (GUILayout.Button(content, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y))) {
					//selectedIndex = startIndex + index ;
					selectedLog = log;
				}
				if (GUILayout.Button(log.condition, logButtonStyle)) {
					//selectedIndex = startIndex + index ;
					selectedLog = log;
				}
				//GUILayout.FlexibleSpace();
				if (showTime) {
					GUI.Box(timeRect, showTimeContent, currentLogStyle);
					GUI.Label(timeLabelRect, sample.time.ToString("0.000"), currentLogStyle);
				}
				if (showScene) {
					GUI.Box(sceneRect, showSceneContent, currentLogStyle);
					GUI.Label(sceneLabelRect, sample.GetSceneName(), currentLogStyle);
				}
				if (showMemory) {
					GUI.Box(memoryRect, showMemoryContent, currentLogStyle);
					GUI.Label(memoryLabelRect, sample.memory.ToString("0.000") + " mb", currentLogStyle);
				}
				if (showFps) {
					GUI.Box(fpsRect, showFpsContent, currentLogStyle);
					GUI.Label(fpsLabelRect, sample.fpsText, currentLogStyle);
				}
			}
			if (collapse)
				GUI.Label(countRect, log.count.ToString(), barStyle);
			GUILayout.EndHorizontal();
			index++;
		}

		int afterHeight = (int)((totalCount - (startIndex + totalVisibleCount)) * size.y);
		if (afterHeight > 0) {
			//fill invisible gap after scroller to make proper scroller pos
			GUILayout.BeginHorizontal(GUILayout.Height(afterHeight));
			GUILayout.Label(" ");
			GUILayout.EndHorizontal();
		}

		GUILayout.EndScrollView();
		GUILayout.EndArea();

		buttomRect.x = 0f;
		buttomRect.y = Screen.height - size.y;
		buttomRect.width = Screen.width;
		buttomRect.height = size.y;

		if (showGraph)
			drawGraph();
		else
			drawStack();
	}


	float graphSize = 4f;
	int startFrame = 0;
	int currentFrame = 0;
	Vector3 tempVector1;
	Vector3 tempVector2;
	Vector2 graphScrollerPos;
	float maxFpsValue;
	float minFpsValue;
	float maxMemoryValue;
	float minMemoryValue;

	void drawGraph()
	{

		graphRect = stackRect;
		graphRect.height = Screen.height * 0.25f;//- size.y ;



		//startFrame = samples.Count - (int)(Screen.width / graphSize) ;
		//if( startFrame < 0 ) startFrame = 0 ;
		GUI.skin = graphScrollerSkin;

		Vector2 drag = getDrag();
		if (graphRect.Contains(new Vector2(downPos.x, Screen.height - downPos.y))) {
			if (drag.x != 0) {
				graphScrollerPos.x -= drag.x - oldDrag3;
				graphScrollerPos.x = Mathf.Max(0, graphScrollerPos.x);
			}

			Vector2 p = downPos;
			if (p != Vector2.zero) {
				currentFrame = startFrame + (int)(p.x / graphSize);
			}
		}

		oldDrag3 = drag.x;
		GUILayout.BeginArea(graphRect, backStyle);

		graphScrollerPos = GUILayout.BeginScrollView(graphScrollerPos);
		startFrame = (int)(graphScrollerPos.x / graphSize);
		if (graphScrollerPos.x >= (samples.Count * graphSize - Screen.width))
			graphScrollerPos.x += graphSize;

		GUILayout.Label(" ", GUILayout.Width(samples.Count * graphSize));
		GUILayout.EndScrollView();
		GUILayout.EndArea();
		maxFpsValue = 0;
		minFpsValue = 100000;
		maxMemoryValue = 0;
		minMemoryValue = 100000;
		for (int i = 0; i < Screen.width / graphSize; i++) {
			int index = startFrame + i;
			if (index >= samples.Count)
				break;
			Sample s = samples[index];
			if (maxFpsValue < s.fps) maxFpsValue = s.fps;
			if (minFpsValue > s.fps) minFpsValue = s.fps;
			if (maxMemoryValue < s.memory) maxMemoryValue = s.memory;
			if (minMemoryValue > s.memory) minMemoryValue = s.memory;
		}

		//GUI.BeginGroup(graphRect);


		if (currentFrame != -1 && currentFrame < samples.Count) {
			Sample selectedSample = samples[currentFrame];
			GUILayout.BeginArea(buttomRect, backStyle);
			GUILayout.BeginHorizontal();

			GUILayout.Box(showTimeContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.time.ToString("0.0"), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showSceneContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.GetSceneName(), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showMemoryContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.memory.ToString("0.000"), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showFpsContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.fpsText, nonStyle);
			GUILayout.Space(size.x);

			/*GUILayout.Box( graphContent ,nonStyle, GUILayout.Width(size.x) ,GUILayout.Height(size.y));
			GUILayout.Label( currentFrame.ToString() ,nonStyle  );*/
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.EndArea();
		}

		graphMaxRect = stackRect;
		graphMaxRect.height = size.y;
		GUILayout.BeginArea(graphMaxRect);
		GUILayout.BeginHorizontal();

		GUILayout.Box(showMemoryContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Label(maxMemoryValue.ToString("0.000"), nonStyle);

		GUILayout.Box(showFpsContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
		GUILayout.Label(maxFpsValue.ToString("0.000"), nonStyle);
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();
		GUILayout.EndArea();

		graphMinRect = stackRect;
		graphMinRect.y = stackRect.y + stackRect.height - size.y;
		graphMinRect.height = size.y;
		GUILayout.BeginArea(graphMinRect);
		GUILayout.BeginHorizontal();

		GUILayout.Box(showMemoryContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));

		GUILayout.Label(minMemoryValue.ToString("0.000"), nonStyle);


		GUILayout.Box(showFpsContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));

		GUILayout.Label(minFpsValue.ToString("0.000"), nonStyle);
		GUILayout.FlexibleSpace();
		GUILayout.EndHorizontal();
		GUILayout.EndArea();

		//GUI.EndGroup();
	}

	void drawStack()
	{

		if (selectedLog != null) {
			Vector2 drag = getDrag();
			if (drag.y != 0 && stackRect.Contains(new Vector2(downPos.x, Screen.height - downPos.y))) {
				scrollPosition2.y += drag.y - oldDrag2;
			}
			oldDrag2 = drag.y;



			GUILayout.BeginArea(stackRect, backStyle);
			scrollPosition2 = GUILayout.BeginScrollView(scrollPosition2);
			Sample selectedSample = null;
			try {
				selectedSample = samples[selectedLog.sampleId];
			}
			catch (System.Exception e) {
				Debug.LogException(e);
			}

			GUILayout.BeginHorizontal();
			GUILayout.Label(selectedLog.condition, stackLabelStyle);
			GUILayout.EndHorizontal();
			GUILayout.Space(size.y * 0.25f);
			GUILayout.BeginHorizontal();
			GUILayout.Label(selectedLog.stacktrace, stackLabelStyle);
			GUILayout.EndHorizontal();
			GUILayout.Space(size.y);
			GUILayout.EndScrollView();
			GUILayout.EndArea();


			GUILayout.BeginArea(buttomRect, backStyle);
			GUILayout.BeginHorizontal();

			GUILayout.Box(showTimeContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.time.ToString("0.000"), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showSceneContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.GetSceneName(), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showMemoryContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.memory.ToString("0.000"), nonStyle);
			GUILayout.Space(size.x);

			GUILayout.Box(showFpsContent, nonStyle, GUILayout.Width(size.x), GUILayout.Height(size.y));
			GUILayout.Label(selectedSample.fpsText, nonStyle);
			/*GUILayout.Space( size.x );
			GUILayout.Box( graphContent ,nonStyle, GUILayout.Width(size.x) ,GUILayout.Height(size.y));
			GUILayout.Label( selectedLog.sampleId.ToString() ,nonStyle  );*/
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.EndArea();



		}
		else {
			GUILayout.BeginArea(stackRect, backStyle);
			GUILayout.EndArea();
			GUILayout.BeginArea(buttomRect, backStyle);
			GUILayout.EndArea();
		}

	}


	public void OnGUIDraw()
	{

		if (!show) {
			return;
		}

		screenRect.x = 0;
		screenRect.y = 0;
		screenRect.width = Screen.width;
		screenRect.height = Screen.height;

		getDownPos();


		logsRect.x = 0f;
		logsRect.y = size.y * 2f;
		logsRect.width = Screen.width;
		logsRect.height = Screen.height * 0.75f - size.y * 2f;

		stackRectTopLeft.x = 0f;
		stackRect.x = 0f;
		stackRectTopLeft.y = Screen.height * 0.75f;
		stackRect.y = Screen.height * 0.75f;
		stackRect.width = Screen.width;
		stackRect.height = Screen.height * 0.25f - size.y;



		detailRect.x = 0f;
		detailRect.y = Screen.height - size.y * 3;
		detailRect.width = Screen.width;
		detailRect.height = size.y * 3;

		if (currentView == ReportView.Info)
			DrawInfo();
		else if (currentView == ReportView.Logs) {
			drawToolBar();
			DrawLogs();
		}


	}

	List<Vector2> gestureDetector = new List<Vector2>();
	Vector2 gestureSum = Vector2.zero;
	float gestureLength = 0;
	int gestureCount = 0;
	bool isGestureDone()
	{
		if (Application.platform == RuntimePlatform.Android ||
			Application.platform == RuntimePlatform.IPhonePlayer) {
			if (Input.touches.Length != 1) {
				gestureDetector.Clear();
				gestureCount = 0;
			}
			else {
				if (Input.touches[0].phase == TouchPhase.Canceled || Input.touches[0].phase == TouchPhase.Ended)
					gestureDetector.Clear();
				else if (Input.touches[0].phase == TouchPhase.Moved) {
					Vector2 p = Input.touches[0].position;
					if (gestureDetector.Count == 0 || (p - gestureDetector[gestureDetector.Count - 1]).magnitude > 10)
						gestureDetector.Add(p);
				}
			}
		}
		else {
			if (Input.GetMouseButtonUp(0)) {
				gestureDetector.Clear();
				gestureCount = 0;
			}
			else {
				if (Input.GetMouseButton(0)) {
					Vector2 p = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
					if (gestureDetector.Count == 0 || (p - gestureDetector[gestureDetector.Count - 1]).magnitude > 10)
						gestureDetector.Add(p);
				}
			}
		}

		if (gestureDetector.Count < 10)
			return false;

		gestureSum = Vector2.zero;
		gestureLength = 0;
		Vector2 prevDelta = Vector2.zero;
		for (int i = 0; i < gestureDetector.Count - 2; i++) {

			Vector2 delta = gestureDetector[i + 1] - gestureDetector[i];
			float deltaLength = delta.magnitude;
			gestureSum += delta;
			gestureLength += deltaLength;

			float dot = Vector2.Dot(delta, prevDelta);
			if (dot < 0f) {
				gestureDetector.Clear();
				gestureCount = 0;
				return false;
			}

			prevDelta = delta;
		}

		int gestureBase = (Screen.width + Screen.height) / 4;

		if (gestureLength > gestureBase && gestureSum.magnitude < gestureBase / 2) {
			gestureDetector.Clear();
			gestureCount++;
			if (gestureCount >= numOfCircleToShow)
				return true;
		}

		return false;
	}

	float lastClickTime = -1;
	bool isDoubleClickDone()
	{
		if (Application.platform == RuntimePlatform.Android ||
		   Application.platform == RuntimePlatform.IPhonePlayer) {
			if (Input.touches.Length != 1) {
				lastClickTime = -1;
			}
			else {
				if (Input.touches[0].phase == TouchPhase.Began) {
					if (lastClickTime == -1)
						lastClickTime = Time.realtimeSinceStartup;
					else if (Time.realtimeSinceStartup - lastClickTime < 0.2f) {
						lastClickTime = -1;
						return true;
					}
					else {
						lastClickTime = Time.realtimeSinceStartup;
					}
				}
			}
		}
		else {
			if (Input.GetMouseButtonDown(0)) {
				if (lastClickTime == -1)
					lastClickTime = Time.realtimeSinceStartup;
				else if (Time.realtimeSinceStartup - lastClickTime < 0.2f) {
					lastClickTime = -1;
					return true;
				}
				else {
					lastClickTime = Time.realtimeSinceStartup;
				}
			}
		}
		return false;
	}

	//calculate  pos of first click on screen
	Vector2 startPos;

	Vector2 downPos;
	Vector2 getDownPos()
	{
		if (Application.platform == RuntimePlatform.Android ||
		   Application.platform == RuntimePlatform.IPhonePlayer) {

			if (Input.touches.Length == 1 && Input.touches[0].phase == TouchPhase.Began) {
				downPos = Input.touches[0].position;
				return downPos;
			}
		}
		else {
			if (Input.GetMouseButtonDown(0)) {
				downPos.x = Input.mousePosition.x;
				downPos.y = Input.mousePosition.y;
				return downPos;
			}
		}

		return Vector2.zero;
	}
	//calculate drag amount , this is used for scrolling

	Vector2 mousePosition;
	Vector2 getDrag()
	{

		if (Application.platform == RuntimePlatform.Android ||
			Application.platform == RuntimePlatform.IPhonePlayer) {
			if (Input.touches.Length != 1) {
				return Vector2.zero;
			}
			return Input.touches[0].position - downPos;
		}
		else {
			if (Input.GetMouseButton(0)) {
				mousePosition = Input.mousePosition;
				return mousePosition - downPos;
			}
			else {
				return Vector2.zero;
			}
		}
	}

	//calculate the start index of visible log
	void calculateStartIndex()
	{
		startIndex = (int)(scrollPosition.y / size.y);
		startIndex = Mathf.Clamp(startIndex, 0, currentLog.Count);
	}

	// For FPS Counter
	private int frames = 0;
	private bool firstTime = true;
	private float lastUpdate = 0f;
	private const int requiredFrames = 10;
	private const float updateInterval = 0.25f;

#if UNITY_CHANGE1
	float lastUpdate2 = 0;
#endif

	void doShow()
	{
		show = true;
		currentView = ReportView.Logs;
		gameObject.AddComponent<ReporterGUI>();


		try {
			gameObject.SendMessage("OnShowReporter");
		}
		catch (System.Exception e) {
			Debug.LogException(e);
		}
	}

	void Update()
	{
		fpsText = fps.ToString("0.000");
		gcTotalMemory = (((float)System.GC.GetTotalMemory(false)) / 1024 / 1024);
		//addSample();

#if UNITY_CHANGE3
		int sceneIndex = SceneManager.GetActiveScene().buildIndex ;
		if( sceneIndex != -1 && string.IsNullOrEmpty( scenes[sceneIndex] ))
			scenes[ SceneManager.GetActiveScene().buildIndex ] = SceneManager.GetActiveScene().name ;
#else
		int sceneIndex = Application.loadedLevel;
		if (sceneIndex != -1 && string.IsNullOrEmpty(scenes[Application.loadedLevel]))
			scenes[Application.loadedLevel] = Application.loadedLevelName;
#endif

		calculateStartIndex();
		if (!show && isGestureDone()) {
			doShow();
		}


		if (threadedLogs.Count > 0) {
			lock (threadedLogs) {
				for (int i = 0; i < threadedLogs.Count; i++) {
					Log l = threadedLogs[i];
					AddLog(l.condition, l.stacktrace, (LogType)l.logType);
				}
				threadedLogs.Clear();
			}
		}

#if UNITY_CHANGE1
		float elapsed2 = Time.realtimeSinceStartup - lastUpdate2;
		if (elapsed2 > 1) {
			lastUpdate2 = Time.realtimeSinceStartup;
			//be sure no body else take control of log 
			Application.RegisterLogCallback (new Application.LogCallback (CaptureLog));
			Application.RegisterLogCallbackThreaded (new Application.LogCallback (CaptureLogThread));
		}
#endif

		// FPS Counter
		if (firstTime) {
			firstTime = false;
			lastUpdate = Time.realtimeSinceStartup;
			frames = 0;
			return;
		}
		frames++;
		float dt = Time.realtimeSinceStartup - lastUpdate;
		if (dt > updateInterval && frames > requiredFrames) {
			fps = (float)frames / dt;
			lastUpdate = Time.realtimeSinceStartup;
			frames = 0;
		}
	}


	void CaptureLog(string condition, string stacktrace, LogType type)
	{
		AddLog(condition, stacktrace, type);
	}

	void AddLog(string condition, string stacktrace, LogType type)
	{
		float memUsage = 0f;
		string _condition = "";
		if (cachedString.ContainsKey(condition)) {
			_condition = cachedString[condition];
		}
		else {
			_condition = condition;
			cachedString.Add(_condition, _condition);
			memUsage += (string.IsNullOrEmpty(_condition) ? 0 : _condition.Length * sizeof(char));
			memUsage += System.IntPtr.Size;
		}
		string _stacktrace = "";
		if (cachedString.ContainsKey(stacktrace)) {
			_stacktrace = cachedString[stacktrace];
		}
		else {
			_stacktrace = stacktrace;
			cachedString.Add(_stacktrace, _stacktrace);
			memUsage += (string.IsNullOrEmpty(_stacktrace) ? 0 : _stacktrace.Length * sizeof(char));
			memUsage += System.IntPtr.Size;
		}
		bool newLogAdded = false;

		addSample();
		Log log = new Log() { logType = (_LogType)type, condition = _condition, stacktrace = _stacktrace, sampleId = samples.Count - 1 };
		memUsage += log.GetMemoryUsage();
		//memUsage += samples.Count * 13 ;

		logsMemUsage += memUsage / 1024 / 1024;

		if (TotalMemUsage > maxSize) {
			clear();
			Debug.Log("Memory Usage Reach" + maxSize + " mb So It is Cleared");
			return;
		}

		bool isNew = false;
		//string key = _condition;// + "_!_" + _stacktrace ;
		if (logsDic.ContainsKey(_condition, stacktrace)) {
			isNew = false;
			logsDic[_condition][stacktrace].count++;
		}
		else {
			isNew = true;
			collapsedLogs.Add(log);
			logsDic[_condition][stacktrace] = log;

			if (type == LogType.Log)
				numOfCollapsedLogs++;
			else if (type == LogType.Warning)
				numOfCollapsedLogsWarning++;
			else
				numOfCollapsedLogsError++;
		}

		if (type == LogType.Log)
			numOfLogs++;
		else if (type == LogType.Warning)
			numOfLogsWarning++;
		else
			numOfLogsError++;


		logs.Add(log);
		if (!collapse || isNew) {
			bool skip = false;
			if (log.logType == _LogType.Log && !showLog)
				skip = true;
			if (log.logType == _LogType.Warning && !showWarning)
				skip = true;
			if (log.logType == _LogType.Error && !showError)
				skip = true;
			if (log.logType == _LogType.Assert && !showError)
				skip = true;
			if (log.logType == _LogType.Exception && !showError)
				skip = true;

			if (!skip) {
				if (string.IsNullOrEmpty(filterText) || log.condition.ToLower().Contains(filterText.ToLower())) {
					currentLog.Add(log);
					newLogAdded = true;
				}
			}
		}

		if (newLogAdded) {
			calculateStartIndex();
			int totalCount = currentLog.Count;
			int totalVisibleCount = (int)(Screen.height * 0.75f / size.y);
			if (startIndex >= (totalCount - totalVisibleCount))
				scrollPosition.y += size.y;
		}

		try {
			gameObject.SendMessage("OnLog", log);
		}
		catch (System.Exception e) {
			Debug.LogException(e);
		}
	}

	List<Log> threadedLogs = new List<Log>();
	void CaptureLogThread(string condition, string stacktrace, LogType type)
	{
		Log log = new Log() { condition = condition, stacktrace = stacktrace, logType = (_LogType)type };
		lock (threadedLogs) {
			threadedLogs.Add(log);
		}
	}

#if !UNITY_CHANGE3
    class Scene
    {
    }
    class LoadSceneMode
    {
    }
    void OnLevelWasLoaded()
    {
        _OnLevelWasLoaded( null );
    }
#endif
    //new scene is loaded
    void _OnLevelWasLoaded( Scene _null1 , LoadSceneMode _null2 )
	{
		if (clearOnNewSceneLoaded)
			clear();

#if UNITY_CHANGE3
		currentScene = SceneManager.GetActiveScene().name ;
		Debug.Log( "Scene " + SceneManager.GetActiveScene().name + " is loaded");
#else
		currentScene = Application.loadedLevelName;
		Debug.Log("Scene " + Application.loadedLevelName + " is loaded");
#endif
	}

	//save user config
	void OnApplicationQuit()
	{
		PlayerPrefs.SetInt("Reporter_currentView", (int)currentView);
		PlayerPrefs.SetInt("Reporter_show", (show == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_collapse", (collapse == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_clearOnNewSceneLoaded", (clearOnNewSceneLoaded == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showTime", (showTime == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showScene", (showScene == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showMemory", (showMemory == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showFps", (showFps == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showGraph", (showGraph == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showLog", (showLog == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showWarning", (showWarning == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showError", (showError == true) ? 1 : 0);
		PlayerPrefs.SetString("Reporter_filterText", filterText);
		PlayerPrefs.SetFloat("Reporter_size", size.x);

		PlayerPrefs.SetInt("Reporter_showClearOnNewSceneLoadedButton", (showClearOnNewSceneLoadedButton == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showTimeButton", (showTimeButton == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showSceneButton", (showSceneButton == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showMemButton", (showMemButton == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showFpsButton", (showFpsButton == true) ? 1 : 0);
		PlayerPrefs.SetInt("Reporter_showSearchText", (showSearchText == true) ? 1 : 0);

		PlayerPrefs.Save();
	}

	//read build information 
	IEnumerator readInfo()
	{
		string prefFile = "build_info"; 
		string url = prefFile; 

		if (prefFile.IndexOf("://") == -1) {
			string streamingAssetsPath = Application.streamingAssetsPath;
			if (streamingAssetsPath == "")
				streamingAssetsPath = Application.dataPath + "/StreamingAssets/";
			url = System.IO.Path.Combine(streamingAssetsPath, prefFile);
		}

		//if (Application.platform != RuntimePlatform.OSXWebPlayer && Application.platform != RuntimePlatform.WindowsWebPlayer)
			if (!url.Contains("://"))
				url = "file://" + url;


		// float startTime = Time.realtimeSinceStartup;
#if UNITY_CHANGE4
		UnityWebRequest www = UnityWebRequest.Get(url);
		yield return www.SendWebRequest();
#else
		WWW www = new WWW(url);
		yield return www;
#endif

		if (!string.IsNullOrEmpty(www.error)) {
			Debug.LogError(www.error);
		}
		else {
#if UNITY_CHANGE4
			buildDate = www.downloadHandler.text;
#else
			buildDate = www.text;
#endif
		}

		yield break;
	}

    private void SaveLogsToDevice()
    {
        string filePath = Application.persistentDataPath + "/logs.txt";
        List<string> fileContentsList = new List<string>();
        Debug.Log("Saving logs to " + filePath);
        File.Delete(filePath);
        for (int i = 0; i < logs.Count; i++)
        {
            fileContentsList.Add(logs[i].logType + "\n" + logs[i].condition + "\n" + logs[i].stacktrace);
        }
        File.WriteAllLines(filePath, fileContentsList.ToArray());
    }
}


