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

[ExecuteInEditMode]
class SppImportGZ : EditorWindow
{
	string folderName = "";

	int idx = 0;
	string[] materialNames = new string[] { "MatCap", "Legacy", "PBR" };
	int[] materialIds = { 0, 1, 2 };
	string modelName = "";
    string step;

	[MenuItem ("SPP/Access local files")]
	public static void  ShowWindow ()
	{
		EditorWindow.GetWindow (typeof(SppImportGZ));
	}

	void Awake ()
	{
		folderName = EditorPrefs.GetString ("spp.path", "C:\\");
		idx = EditorPrefs.GetInt ("spp.materialIndex", 0);
    }

    void OnGUI ()
	{
		GUILayout.Label ("Import Settings", EditorStyles.boldLabel);
		idx = EditorGUILayout.IntPopup ("Material type:", idx, materialNames, materialIds);
		EditorGUILayout.Separator ();

		EditorGUILayout.BeginHorizontal ();
        if (GUILayout.Button ("Import", GUILayout.Width (150))) {
			Import (false);
		}
        EditorGUILayout.EndHorizontal ();
	}

	void Import (bool dontSave)
	{
        float t = Time.realtimeSinceStartup;
		SppConfig.basicRotation = Quaternion.identity;
		string parentFolder;
		try {
			parentFolder = GetParentFolderFromPath(folderName);
			modelName = GetModelNameFromPath (folderName);
		} catch (System.Exception e) {
			Debug.Log (e);
			parentFolder = "";
			modelName = "";
		}	
		folderName = EditorUtility.OpenFolderPanel ("Source folder - select model folder", parentFolder, modelName);
		folderName = folderName.Replace (@"\", "/"); // Windows to Linux
		if (folderName.Length > 0) {
			EditorPrefs.SetString ("spp.path", folderName);
			EditorPrefs.SetInt ("spp.materialIndex", idx);

			switch (idx) {
			case 0:
				SppConfig.renderMode = SppConfig.RenderMode.MatCap;
				break;
			case 1:
				SppConfig.renderMode = SppConfig.RenderMode.Legacy;
				break;
			case 2:
				SppConfig.renderMode = SppConfig.RenderMode.PBR;
				break;
			}

			modelName = GetModelNameFromPath (folderName);
			if (modelName.Length == 0) {
				System.Guid g = System.Guid.NewGuid ();
				modelName = g.ToString ();
			}	

			string subFolder = ""; // root
			string importPath = folderName + "/data/" + subFolder;

			ImportFolder (importPath, subFolder, true, dontSave);

		}
        Debug.Log("Total time: " + (Time.realtimeSinceStartup-t).ToString("f2") + " sec(s)");
	}

	// Import info.xml and 000.gz
	#pragma warning disable 168
	private void ImportFolder (string folder, string subFolder,  bool isRoot, bool dontSave)
	{
        EditorUtility.ClearProgressBar();
        EditorUtility.DisplayProgressBar("SPP import", "Processing model data", 0f);
		string xmlName = folder + subFolder + "info.xml";

		SppXmlReader.LoadFromFile (xmlName, isRoot);

		string gzName = folder + subFolder + "000.gz";
		if (SppBinaryReader.LoadGZ (gzName)) {
			if (SppBinaryReader.BufferToScene (SppConfig.basicRotation)) {
				GameObject instanced = SppBinaryReader.rootGameObject;
				instanced.transform.localScale = Vector3.one * SppConfig.SPP_SCALE;
				if (SppXmlReader.loadSuccess == true ) {
					try {
						SppCadRootBehaviour cadRoot = instanced.AddComponent<SppCadRootBehaviour> () as SppCadRootBehaviour;
						cadRoot.info = SppXmlReader.cadRoot;
						if (isRoot) {
							SppFoldersAndNames foldersAndNames = instanced.AddComponent<SppFoldersAndNames> () as SppFoldersAndNames;
							foldersAndNames.folders = (string[])SppXmlReader.folders.ToArray (typeof(string));
							foldersAndNames.names = (string[])SppXmlReader.names.ToArray (typeof(string));

							EditorUtility.SetDirty (foldersAndNames.gameObject);
						}
						int i = 0;

						foreach (Transform t in instanced.transform) {
							try {
								string key = NameFromId (i + 1);
								SppCadChildBehaviour cadChild = t.gameObject.AddComponent<SppCadChildBehaviour> () as SppCadChildBehaviour;
								try {
									(SppXmlReader.cadChildren [i] as SppCadChild).drawCalls = SppBinaryReader.statistics [key].meshCount;
									(SppXmlReader.cadChildren [i] as SppCadChild).tris = SppBinaryReader.statistics [key].triangleCount;
									(SppXmlReader.cadChildren [i] as SppCadChild).verts = SppBinaryReader.statistics [key].vertexCount;
								} catch (System.Exception e) {
									Debug.Log ("mismatched cadChildren and SPPV_bin.statistics at " + i + " (key=" + key + ")");
									Debug.Log (e.Message);
								}
								cadChild.info = (SppXmlReader.cadChildren [i] as SppCadChild);
								EditorUtility.SetDirty (cadChild.gameObject);
							} catch (System.Exception e) {
								Debug.Log (e.Message);
							}
							i++;
						}

						SppXmlReader.cadRoot.drawCalls = SppBinaryReader.totalMeshes;
						SppXmlReader.cadRoot.verts = SppBinaryReader.totalVerts;
						SppXmlReader.cadRoot.tris = SppBinaryReader.totalTris;
					} catch (System.Exception e) {
						Debug.LogWarning (e.Message);
					}	



				}
				if (dontSave == false) {

					string absPath = ProjectPath ();
					string meshFolder;
					absPath += ("/Assets/Imported/" + modelName + subFolder);
					System.IO.Directory.CreateDirectory (absPath); // force folder
					string rawPath;
					if (absPath.EndsWith ("/")) { 
						rawPath = absPath + "Meshes";
						meshFolder = "Meshes/";
					} else {
						rawPath = absPath + "/Meshes";
						meshFolder = "/Meshes/";
					}	
					Debug.Log ("rawPath=" + rawPath);
					System.IO.Directory.CreateDirectory (rawPath); // force folder
                    // save all meshes
                    MeshFilter[] mfs = instanced.GetComponentsInChildren<MeshFilter> ();
                    MeshRenderer[] mrs = instanced.GetComponentsInChildren<MeshRenderer>();
                    int total = mfs.Length + mrs.Length;
                    int current = 0;
                    int meshCount = mfs.Length;
                    int matCount = mrs.Length;
                    int curMesh = 0;
                    int curMat = 0;

                    foreach (MeshFilter mf in mfs) {
                        current++;
                        curMesh++;
                        EditorUtility.DisplayProgressBar("SPP import", "Saving meshes ("+curMesh + " of " + meshCount + ")", (current * 1f) / (total * 1f));
                        Mesh m = mf.sharedMesh;
						string meshPath = "Assets/Imported/" + modelName + subFolder + meshFolder + GetAssetName (mf.gameObject) + ".asset";
						try {
							if (AssetDatabase.Contains (m.GetInstanceID ()) == false) {
								AssetDatabase.CreateAsset (m, meshPath);
							}
						} catch (System.Exception e) {
							// NOP
						}
                    }
                    // save all materials
					foreach (MeshRenderer mr in mrs) {
                        current++;
                        curMat++;
                        EditorUtility.DisplayProgressBar("SPP import", "Saving materials (" + curMat + " of " + matCount + ")", (current * 1f) / (total * 1f));
                        Material m = mr.sharedMaterial;
						string materialPath = "Assets/Imported/" + modelName + subFolder + meshFolder + GetAssetName (mr.gameObject) + ".mat";
						try {
                            if (AssetDatabase.Contains(m.GetInstanceID()) == false)
                            {
                                AssetDatabase.CreateAsset(m, materialPath);
                            }
						} catch (System.Exception e) {
							// NOP
						}
                    }
                    EditorUtility.DisplayProgressBar("SPP import", "Saving prefab", 1f);
                    string localPath = "Assets/Imported/" + modelName + "/" + subFolder + modelName + ".prefab";

					//Object prefab = PrefabUtility.CreateEmptyPrefab (localPath);
					//PrefabUtility.ReplacePrefab (instanced, prefab, ReplacePrefabOptions.ConnectToPrefab);
					PrefabUtility.SaveAsPrefabAsset(instanced, localPath);
                    AssetDatabase.Refresh();
				}
                
				SppBinaryReader.ClearBuffer ();
                SppMaterial.CleanUp();
			}
		}
        EditorUtility.ClearProgressBar();

    }

    string ProjectPath ()
	{
		string s = Application.dataPath;
		if (s.EndsWith ("/Assets/"))
			s = s.Substring (0, s.Length - ("/Assets/").Length);
		else if (s.EndsWith ("/Assets"))
			s = s.Substring (0, s.Length - ("/Assets").Length);

		return s;						
	}

	string GetAssetName (GameObject g)
	{
		return g.transform.parent.name + "_" + g.name;
	}

	string GetModelNameFromPath (string folderPath)
	{
		folderPath = folderPath.Replace (@"\", "/"); // Windows to Linux)
		string[] subfolders = folderPath.Split ('/');

		return subfolders[subfolders.Length-1];

	}

	string GetParentFolderFromPath (string folderPath)
	{
		string s = "";
		folderPath = folderPath.Replace (@"\", "/"); // Windows to Linux)
		string[] subfolders = folderPath.Split ('/');
		for (int i = 0; i < (subfolders.Length - 1); i++) {
			s += subfolders [i] + "/";
		}
		return s;

	}

	string NameFromId (int id)
	{
		string s = "00000" + id.ToString ();
		s = s.Substring (s.Length - 6, 6);
		return s;
	}

}