/////////////////////////////////////////////////////////////////////////////////////////////////
// GF - Storage
// Game data storage
// Use:
// - have the YourGameDataStructure class serializable ([System.Serializable]) and derived from StrageData
// - implement override YourGameDataStructure.IsValid for versioning or validation
// - call Storage.SaveSlot<YourGameDataStructure>(ref m_gameData, slot)
// - call Storage.LoadSlot<YourGameDataStructure>(ref m_gameData, slot)
// References:
// http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data:_XmlSerializer
/////////////////////////////////////////////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Xml.Serialization;

[System.Serializable]
public class StorageData
{
	public virtual bool IsValid() { return true; }
}

public class Storage
{
    public static bool Save(string data, string fileName)
    {
        bool ok = false;
        string pathName = Application.persistentDataPath + "/" + fileName;
        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(pathName));
        var file = File.CreateText(pathName);
        if (file != null)
        {
            ok = true;
            file.WriteLine(data);
            file.Close();
        }
        return ok;
    }

    public static bool Load(ref string data, string fileName)
    {
        bool ok = false;
        string pathName = Application.persistentDataPath + "/" + fileName;
        if (File.Exists(pathName))
        { 
            var file = File.OpenText(pathName);
            if (file != null)
            {
                data = file.ReadLine();
                if (data == null)
                    data = "";
                ok = true;
            }
            file.Close();
        }
        return ok;
    }

    public static bool SaveSlot<T>(ref T data, int slot) where T : StorageData
	{
		return Save(ref data, "savedgame" + slot + ".sav");
	}

	public static bool LoadSlot<T>(ref T data, int slot) where T : StorageData
	{
		return Load(ref data, "savedgame" + slot + ".sav");
	}

	public static bool Save<T>(ref T data, string fileName) where T : StorageData
    {
		bool ok = false;
		string pathName = Application.persistentDataPath + "/" + fileName;
        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(pathName));
        FileStream file = File.Create(pathName);
		if(file != null)
		{
			ok = true;
			try
			{
				// BinaryFormatter serializer = new BinaryFormatter();
				XmlSerializer serializer = new XmlSerializer(typeof(T));
				serializer.Serialize(file, data);
        		// Debug.Log("save successful");
        	}
			catch(System.Exception e)
        	{
        		Debug.Log("SAVE to file '" + pathName + "' FAILED with EXCEPTION: " + e);
				ok = false;
        	}

        	file.Close();
        }

        return ok;
    }   
     
	public static bool Load<T>(ref T data, string fileName) where T : StorageData /* , new() */
	{
		bool ok = false;
		string pathName = Application.persistentDataPath + "/" + fileName;
		if(File.Exists(pathName))
        {
			FileStream file = File.Open(pathName, FileMode.Open);
			if(file != null)
			{
				try
				{
            		// BinaryFormatter serializer = new BinaryFormatter();
					XmlSerializer serializer = new XmlSerializer(typeof(T));
					data = (T)serializer.Deserialize(file);
            		ok = (data != null) && data.IsValid();
				}
				catch(System.Exception e)
	        	{
					Debug.Log("LOAD from file '" + pathName + "' FAILED with EXCEPTION: " + e);
	        	}

            	file.Close();
            }
        }

		// @NOTE: optional re-construct
		//if(!ok)
    	//	data = new T();
		//	data = default(T);

        return ok;
    }

	public static bool LoadFromText<T>(ref T data, string text) where T : StorageData /* , new() */
 	{
		bool ok = false;
		StringReader stream = new StringReader(text);
		try
		{
	 		var serializer = new XmlSerializer(typeof(T));
			data = (T)serializer.Deserialize(stream);
			ok = (data != null) && data.IsValid();
	 	}
		catch(System.Exception e)
    	{
			Debug.Log("LOAD from text '" + text + "' FAILED with EXCEPTION: " + e);
    	}

    	// @NOTE: optional re-construct
    	//if(!ok)
		//	data = new T();
		//	data = default(T);

    	return ok;
 	}
}
