﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class FileManager : MonoBehaviour {


	public static bool HasLocalCache(string experienceId)
	{
		return FileExists(GetFilePath(experienceId));
	}

	public static string GetFilePath(string experienceId)
	{
		return Application.persistentDataPath + "/" + experienceId + "/" + experienceId + ".ntar";
	}

	public static string GetParentFolder(string filePath)
	{
		return Path.GetDirectoryName(filePath);
	}

	public static string GetLastChannelDirectoryPath()
	{
		return Application.persistentDataPath + "/last_channel/";
	}

	public static bool FileExists(string path)
	{
		if(path.Contains("."))
		{
			//file 
			if(File.Exists(path))
			{
				// Debug.Log("File exists at " + path);
				return true;
			}
			else
			{
				// Debug.Log("File doesn't exist at " + path);
				return false;
			}
		}
		else
		{
			//directory
			if(Directory.Exists(path))
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	}

	//refactor so SaveFile is generic, SaveExperienceFile grabs specific directory
	public static void SaveFile(string path, byte[] bytes)
	{
		string directoryPath = Path.GetDirectoryName(path);
		Directory.CreateDirectory(directoryPath);
		File.WriteAllBytes(path, bytes);
	}

	public static void SaveTextFile(string path, string fileText)
	{
		CreateDirectoryIfNeeded(path);
		File.WriteAllText(path, fileText);
	}

	public static void SaveImageFile(string path, Texture2D imageToSave)
	{
		CreateDirectoryIfNeeded(path);
		byte[] imageBytes = imageToSave.EncodeToPNG();
		FileManager.SaveFile(path, imageBytes);
	}

	public static void SaveClassToXML(string path, System.Object objectToSave, System.Type objectType)
	{
		Debug.Log("Saving to " + path);
		CreateDirectoryIfNeeded(path);


		var serializer = new XmlSerializer(objectType);
		var stream = new FileStream(path, FileMode.Create);
		serializer.Serialize(stream, objectToSave);
		stream.Close();
	}

	public static System.Object LoadClassFromXML(string path, System.Type objectType)
	{
		XmlSerializer serializer = new XmlSerializer(objectType);
		FileStream fs = new FileStream(path, FileMode.Open);
		return serializer.Deserialize(fs);
	}

	public static void SaveClassToJson(string path, System.Object objectToSave, System.Type objectType)
	{
		CreateDirectoryIfNeeded(path);
		string jsonString = JsonUtility.ToJson (objectToSave);

        using (StreamWriter streamWriter = File.CreateText (path))
        {
            streamWriter.Write (jsonString);
        }
	}

	public static string LoadClassFromJson(string path, System.Type objectType)
	{
		using (StreamReader streamReader = File.OpenText (path))
        {
            return streamReader.ReadToEnd ();
            // return JsonUtility.FromJson<typeof(objectType)> (jsonString); 
        }
	}

	// public static void SaveClassToXML(string path, System.Object objectToSave, System.Type objectType)
	// {
	// 	Debug.Log("Saving to " + path);
	// 	CreateDirectoryIfNeeded(path);


	// 	var serializer = new XmlSerializer(objectType);
	// 	var stream = new FileStream(path, FileMode.Create);
	// 	serializer.Serialize(stream, objectToSave);
	// 	stream.Close();
	// }

	// public static System.Object LoadClassFromXML(string path, System.Type objectType)
	// {
	// 	XmlSerializer serializer = new XmlSerializer(objectType);
	// 	FileStream fs = new FileStream(path, FileMode.Open);
	// 	return serializer.Deserialize(fs);
	// }

	public static string LoadTextFile(string path)
	{
		if(File.Exists(path))
		{
			return File.ReadAllText(path);
		}
		else
		{
			return null;
		}
		
	}

	public static byte[] LoadFileAsBytes(string path)
	{
		return File.ReadAllBytes(path);
	}

	static Texture2D tmpTex;

	public static Texture2D LoadImageFile(string path)
	{
		byte[] imageBytes = FileManager.LoadFileAsBytes(path);
		// if(tmpTex == null)
			tmpTex = new Texture2D(2, 2);
			
		tmpTex.LoadImage(imageBytes);
		return tmpTex;
	}

	public static AssetBundle LoadAssetBundle(string experienceId)
	{
		string filePath = GetFilePath(experienceId);
		return AssetBundle.LoadFromFile(filePath);
	}


	public static void DeleteFile(string path)
	{
		// Debug.Log("Deleting something");
		// string path =  Path.GetDirectoryName(GetFilePath(experienceId));
		if(path.Contains("."))
		{
			//file 
			if(File.Exists(path))
			{
				File.Delete(path);
			}
			else
			{
				Debug.Log("Can't delete file that doesn't exist: " + path);
			}
		}
		else
		{
			//directory
			if(Directory.Exists(path))
			{
				Directory.Delete(path, true);
			}
			else
			{
				Debug.Log("Can't delete directory that doesn't exist: " + path);
			}
		}
	}

	// static readonly string[] SizeSuffixes = 
    //                { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
	public static string SizeSuffix(long value)
	{
		string[] SizeSuffixes = 
                   { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

		int decimalPlaces = 1;
		// if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
		if (value < 0) { return "-" + SizeSuffix(-value); } 
		if (value == 0) { return "0 bytes"; }

		// mag is 0 for bytes, 1 for KB, 2, for MB, etc.
		int mag = (int)Mathf.Log(value, 1024);

		// 1L << (mag * 10) == 2 ^ (10 * mag) 
		// [i.e. the number of bytes in the unit corresponding to mag]
		float adjustedSize = (float)value / (1L << (mag * 10));

		// make adjustment when the value is large enough that
		// it would round up to 1000 or more
		if (System.Math.Round(adjustedSize, decimalPlaces) >= 1000)
		{
			mag += 1;
			adjustedSize /= 1024;
		}

		return string.Format("{0:n" + decimalPlaces + "} {1}", 
			adjustedSize, 
			SizeSuffixes[mag]);
	}

	public static void DeleteExperience(string experienceId)
	{
		// Debug.Log("Deleting something");
		string path =  Path.GetDirectoryName(GetFilePath(experienceId));
		if(path.Contains("."))
		{
			//file 
			if(File.Exists(path))
			{
				File.Delete(path);
			}
			else
			{
				Debug.LogError("Can't delete file that doesn't exist: " + path);
			}
		}
		else
		{
			//directory
			if(Directory.Exists(path))
			{
				Directory.Delete(path, true);
			}
			else
			{
				Debug.LogError("Can't delete directory that doesn't exist: " + path);
			}
		}
	}

	public static bool CreateDirectoryIfNeeded(string path)
	{
		if(path.Contains("/") == false)
			path = path + "/";
		// Debug.Log("Creating directory: " + path);
		string directory = Path.GetDirectoryName(path);		
		
		if(Directory.Exists(directory))
		{
			// Debug.Log("already exists");
			return false;
		}
		else
		{
			// Debug.Log("doiesn't exist, creating");
			Directory.CreateDirectory(directory);
			return true;
		}
	}

}
