using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;

/// <summary>
/// Editor Class used to search and replace objects with prefabs;
/// </summary>
public class MassReplacer : EditorWindow {

    #region Editor Settings
    //base settings
    private string FilterText;
    private ListItem[] FilteredList;
    private GameObject CopiedPrefab;

    //advanced settings
    private bool doCopyScale = true;
    private bool doCopyRot = true;
    private bool isCaseSensitive = false;
    #endregion Editor Settings


    #region Private Variables
    private Vector2 scrollPosition;
    private string prevFilterText;
    private bool showAdvancedSettings;
    #endregion Private Variables

    #region GUI Functions

    [MenuItem("Tools/Mass Replace %e")]
    static void createWindow()
    {
        MassReplacer window = (MassReplacer)GetWindow(typeof(MassReplacer), true, "Replace", true);
        window.ReFilterList(window.FilterText);
        window.Repaint();
    }

    void OnGUI()
    {
        Event e = Event.current;

        //Base Settings
        EditorGUILayout.LabelField("Base Settings", EditorStyles.boldLabel);
        FilterText = EditorGUILayout.TextField((FilterText == null || FilterText == "") ? "Search..." : FilterText); //If textFiled is empty display "Searching..." else display search filter
        CopiedPrefab = (GameObject)EditorGUILayout.ObjectField(CopiedPrefab, typeof(GameObject), true);

        //Advanced Settings
        GUIStyle BoldFold = new GUIStyle(EditorStyles.foldout); BoldFold.font = EditorStyles.boldFont; //create foldoutstyle with bold text
        showAdvancedSettings = EditorGUILayout.Foldout(showAdvancedSettings, "Advanced Settings", BoldFold);
        if (showAdvancedSettings) {
            doCopyScale = EditorGUILayout.Toggle("Copy Scale", doCopyScale);
            doCopyRot = EditorGUILayout.Toggle("Copy Rotation", doCopyRot);
            isCaseSensitive = EditorGUILayout.Toggle("Case Sensitive Search", isCaseSensitive);
        }
        float advancedSettingHeight = 3 * ((showAdvancedSettings) ? 18 : 0);


        //Start of List
        GUILayout.Box("", GUILayout.Height(1), GUILayout.ExpandWidth(true));
        Rect scrollRect = GUILayoutUtility.GetLastRect();
        scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Width(position.width), GUILayout.Height(position.height - (108 + advancedSettingHeight) ));
        scrollRect.height = position.height - (108 + advancedSettingHeight);

        //Each Item
        foreach (ListItem listItem in FilteredList) {
            GUILayout.BeginHorizontal();
            listItem.isRepplaceable = GUILayout.Toggle(listItem.isRepplaceable, "", GUILayout.MaxWidth(10));
            GUILayout.Label(listItem.gameObject.name);

            Rect tempRect = GUILayoutUtility.GetLastRect();
            tempRect.position -= Vector2.down * (82 + advancedSettingHeight) + scrollPosition;
            if (tempRect.Overlaps(scrollRect))
                listItem.rect = tempRect;

            GUILayout.EndHorizontal();
        }
        GUILayout.EndScrollView(); //end list

        //Buttons at bottom of window
        GUILayout.BeginHorizontal();
        GUI.enabled = (CopiedPrefab != null);
        if (GUILayout.Button("Replace")) {
            replaceFiltedList();
        }
        GUI.enabled = true;
        if (GUILayout.Button("Cancel")) {

        }
        GUILayout.EndHorizontal(); // end buttons

        //Interaction
        //Check if filter is updated;
        if (prevFilterText != FilterText) {
            ReFilterList(FilterText);
        }

        //If clicked window check where clicked happened
        if (e.button == 0 && e.type == EventType.MouseDown)
            OnWindowClick(e.mousePosition);


    }

    /// <summary>
    /// Logic of when the window has been clicked
    /// </summary>
    /// <param name="mousePos">position of mouse when clicked</param>
    /// <returns></returns>
    private void OnWindowClick(Vector2 mousePos)
    {
        //Loops through each asset to see if one has been clicked on
        foreach (ListItem listItem in FilteredList) {
            if (listItem.rect.Contains(mousePos)) {
                Debug.Log("clicked: " + listItem.gameObject.name);
                Selection.activeGameObject = listItem.gameObject;
                break;
            }//end if 
        }//end foreach
    }
    #endregion GUI Functions

    #region Search Functions

    #region Helper Functions

    private void ReFilterList(string filter)
    {
        if (filter == null)
            filter = "";

        StringComparison caseComparer = (isCaseSensitive) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;

        FilteredList = getFilteredList(filter, caseComparer);
        prevFilterText = filter;
        Repaint();
    }
    #endregion Helper Fucntions


    #region Static Functions
    /// <summary>
    /// Returns an array of listItems of gameobjects in scene which contains a string
    /// </summary>
    /// <param name="filter">look for gameobjects containing this string</param>
    /// <returns></returns>
    private static ListItem[] getFilteredList(string filter, StringComparison caseComparer = StringComparison.OrdinalIgnoreCase)
    {
        List<ListItem> retVal = new List<ListItem>();

        object[] obj = FindObjectsOfType(typeof(GameObject));

        foreach (object o in obj) {
            GameObject g = (GameObject)o;


            if (g.name.Contains(filter, caseComparer)) {
                ListItem newItem = new ListItem(g);
                retVal.Add(newItem);
            }
        }
        return retVal.ToArray();
    }
    #endregion Static Functions

    #endregion Search Functions


    #region Replace Fucntions

    private void replaceFiltedList()
    {

        foreach (ListItem listItem in FilteredList) {
            if (!listItem.isRepplaceable || listItem.gameObject.Equals(CopiedPrefab))

                continue;

            GameObject replaceObject = (GameObject)PrefabUtility.InstantiatePrefab(CopiedPrefab);
            replaceObject.transform.parent = listItem.gameObject.transform.parent;
            replaceObject.transform.position = listItem.gameObject.transform.position;
            replaceObject.name = listItem.gameObject.name;
            if (doCopyRot)
                replaceObject.transform.rotation = listItem.gameObject.transform.rotation;
            if (doCopyScale)
                replaceObject.transform.localScale = listItem.gameObject.transform.localScale;

            Undo.RegisterCreatedObjectUndo(replaceObject, "Replaced Objects (" + FilterText + ")");

            Undo.DestroyObjectImmediate(listItem.gameObject);
        }

        ReFilterList(FilterText);

    }



    #endregion Replace Fucntions





    class ListItem {
        public GameObject gameObject;
        public bool isRepplaceable;
        public Rect rect;

        public ListItem(GameObject gameObject)
        {
            this.gameObject = gameObject;
            isRepplaceable = true;
            rect = new Rect();
        }


    }
}

static class MassReplaceOverides {

    public static bool Contains(this string source, string toCheck, StringComparison comp)

    {
        return source != null && toCheck != null && source.IndexOf(toCheck, comp) >= 0;
    }
}
