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

public class SppModelLoader : MonoBehaviour {
	public string modelName;
	public string subFolder = "/";
	public bool iterateParts = false;
	public bool loadOnStart = false;
	public SppDownloadManager downloadManager;
	public SppExplosionBehaviour explosionHandler;
	public SppSelectionBehaviour selectionHandler;
	public GameObject target;
	public GameObject[] messageReceivers;

	private GameObject instanced;
	private List<string> visitedFolders = new List<string> ();
	private  string currentFolder = "";

	private Bounds modelBounds;
	private Bounds elementBounds;

	void Start () {
		if (loadOnStart == true && !string.IsNullOrEmpty (modelName)) {
			string path = SppUtility.BuildModelServerPath (SppConfig.loginData.server, SppConfig.loginData.catalog, modelName, subFolder);
			currentFolder = subFolder;
			visitedFolders.Clear ();
			visitedFolders.Add (currentFolder); // root
			if (downloadManager != null) {
				downloadManager.StopDownload ();
				// info.xml
				string xml = SppUtility.CombinePath(path, "info.xml");
				downloadManager.DownloadFile (gameObject, "InfoDownloaded", xml, true);
				// model 000.gz
				string gz = SppUtility.CombinePath(path, "000.gz");
				downloadManager.DownloadFile (gameObject, "ModelDownloaded", gz, true);
			} else {
				Debug.Log ("No download manager specified!");
			}	
		}
	}

	#region LoadAndNaviagte
	public void Load (string modelName, string subFolder) {
		this.modelName = modelName;
		if (subFolder == "/") {
			visitedFolders.Clear ();
			currentFolder = subFolder;
		} else {
			currentFolder += subFolder;
		}	
		visitedFolders.Add (currentFolder); 

		string path = SppUtility.BuildModelServerPath (SppConfig.loginData.server, SppConfig.loginData.catalog, modelName, currentFolder);
		if (downloadManager != null) {
			downloadManager.StopDownload ();
			// info.xml
			string xml = SppUtility.CombinePath(path, "info.xml");
			downloadManager.DownloadFile (gameObject, "InfoDownloaded", xml, true);
			// model 000.gz
			string gz = SppUtility.CombinePath(path, "000.gz");
			downloadManager.DownloadFile (gameObject, "ModelDownloaded", gz, true);
		} else {
			Debug.Log ("No download manager specified!");
		}	
	}


	public void LoadOffline(string modelName, string subFolder) {
        string offlinePath = SppUtility.BuildModelLocalPath (modelName, subFolder);
        //Debug.Log(offlinePath);
		this.modelName = modelName;
		string xml = offlinePath + "info.xml";
		string gz = offlinePath + "000.gz";
		if (subFolder == "/") {
			visitedFolders.Clear ();
		}
		currentFolder = subFolder;
		visitedFolders.Add (currentFolder); // root
		if (downloadManager != null) {
			downloadManager.StopDownload ();
			// info.xml
			downloadManager.DownloadFile (gameObject, "InfoDownloaded", xml, true);
			// model 000.gz
			downloadManager.DownloadFile (gameObject, "ModelDownloaded", gz, true);

		} else {
			Debug.Log ("No download manager specified!");
		}	
	}

	public void Home() {
		Load (this.modelName, "/");
	}

	public void Back() {
		visitedFolders.RemoveAt (visitedFolders.Count-1);
		currentFolder = visitedFolders[visitedFolders.Count-1];

		string path = SppUtility.BuildModelServerPath (SppConfig.loginData.server, SppConfig.loginData.catalog, modelName, currentFolder);
		if (downloadManager != null) {
			downloadManager.StopDownload ();
			// info.xml
			string xml = SppUtility.CombinePath(path, "info.xml");
			downloadManager.DownloadFile (gameObject, "InfoDownloaded", xml, true);
			// model 000.gz
			string gz = SppUtility.CombinePath(path, "000.gz");
			downloadManager.DownloadFile (gameObject, "ModelDownloaded", gz, true);

		} else {
			Debug.Log ("No download manager specified!");
		}	

	}

	public void Next(string subFolder) {
		if (!subFolder.EndsWith ("/")) {
			subFolder += "/";
		}	
		Load (this.modelName, subFolder);
	}

	#endregion

	#region Model
	IEnumerator ProcessModel (SppWebData wd) {
		byte[] data = wd.bytes;
		SppXmlReader.cadRoot.drawCalls = 0;
		SppXmlReader.cadRoot.verts = 0;
		SppXmlReader.cadRoot.tris = 0;

		if (data.Length > 0) {
			if (data [0] == 0x1f && data [1] == 0x8b) {
				// Store buffer to byte[]
				SppBinaryReader.SetBufferFromGZ (data); 
			} else if (data [0] == 83 && data [1] == 80 && data [2] == 80) {
				SppBinaryReader.SetBuffer (data);
			}

			SppBinaryReader.BufferToSceneBegin (SppConfig.basicRotation);

			char lastTag;

			float elapsedTime = 2f;
			while (SppBinaryReader.BufferToSceneIterate (out lastTag)) {
				instanced = SppBinaryReader.rootGameObject;
				elapsedTime += Time.deltaTime;
				if (elapsedTime > 1 && iterateParts) {
					elapsedTime = 0;
					yield return  new WaitForEndOfFrame ();
				}	
			}
			SppBinaryReader.BufferToSceneEnd ();
			instanced = SppBinaryReader.rootGameObject;
			SppCadRootBehaviour cadRoot = instanced.AddComponent<SppCadRootBehaviour> () as SppCadRootBehaviour;
			cadRoot.info = SppXmlReader.cadRoot;
			SppFoldersAndNames foldersAndNames = instanced.AddComponent<SppFoldersAndNames> () as SppFoldersAndNames;
			foldersAndNames.folders = (string[])SppXmlReader.folders.ToArray (typeof(string));
			foldersAndNames.names = (string[])SppXmlReader.names.ToArray (typeof(string));
			SppUtility.CleanUp ();
			instanced.transform.localScale = Vector3.one  * SppConfig.SPP_SCALE; // mm to m

			int i = 0;
			foreach (Transform t in instanced.transform) {
				try {
					string key = SppUtility.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);
				} catch (System.Exception e) {
					Debug.Log (e.Message);
				}
				SppUtility.CleanUp ();

				i++;
			}

			SppXmlReader.cadRoot.drawCalls = SppBinaryReader.totalMeshes;
			SppXmlReader.cadRoot.verts = SppBinaryReader.totalVerts;
			SppXmlReader.cadRoot.tris = SppBinaryReader.totalTris;

			SppBinaryReader.ClearBuffer ();

			instanced.transform.parent = transform;
			SppUtility.CleanUp ();
			SppUtility.CenterModel (instanced, true);
			if (explosionHandler) {
				explosionHandler.Initialize (instanced);
			}
			if (selectionHandler) {
				selectionHandler.Initialize (instanced);
			}

		}

		if (messageReceivers != null) {
			for (int i = 0; i < messageReceivers.Length; i++) {
				if (messageReceivers [i] != null) {
					IModelReady intf = (IModelReady)messageReceivers [i].GetComponent<IModelReady> ();
					if (intf != null) {
						intf.OnModelReady (instanced);
					}
				}	
			}	
		}
		yield return null;
	}

	public int GetVisitedFolderCount() {
		return visitedFolders.Count;
	}	

	#endregion

	#region Callbacks
	// Callbacks for downloadManager
	public void InfoDownloaded(SppWebData wd) {
		if (string.IsNullOrEmpty(wd.error)) {
			// Analyze model info
			SppXmlReader.Parse(wd, visitedFolders.Count == 1);
		} else {	
			Debug.LogError("InfoDownloaded(): " + wd.error + ", url=" + wd.url);
		}	
	}	

	public void ModelDownloaded(SppWebData wd) {
		if (string.IsNullOrEmpty(wd.error)) {
			StartCoroutine (ProcessModel (wd));
		} else {	
			Debug.LogError("ModelDownloaded(): " + wd.error);
		}	
	}	
	#endregion
}
