context: using UnityEngine;
  using System.Collections;
  using System.Collections.Generic;
  using System.IO;
  using System;
  //using Pathfinding;
  
  namespace Pathfinding {
  	public class AstarSerializer {
  	
  		public BinaryWriter writerStream;
  		public BinaryReader readerStream;
  		
  		public AstarPath active;
  		public AstarData astarData;
  		
  		public bool replaceOldGraphs = true;
  		
  		/** Mask for what to save. The first 4 bits in this mask is used, the rest can be used to pass information on what was saved in the file
  		  *Assign values with += or |=, and remove them with -= or &= ~value
  		  * Values should be one bit values (unless you know what you are doing), such as 1 << 20 */
  		public BitMask mask = -1 & ~(SMask.SaveNodes);
  		
  		/** Should version differences be ignored.
  		 * This should not be enabled if you don't know what you are doing.
  		 * It will enable older version of the project to try open files saved with a newer project version */
  		public static bool IgnoreVersionDifferences = false;
  		
  		//public const int SaveNodes = 				1 << 0;
  		//public const int SaveNodeConnections = 		1 << 1;
  		//public const int SaveNodeConnectionCosts = 	1 << 2;
  		//public const int SaveNodePositions = 		1 << 3;
  		
  		/** Serializer mask for what is to be saved in the file */
  		public class SMask {
  			public static int SaveNodes = 					1 << 0;
  			public static int SaveNodeConnections = 		1 << 1;
  			public static int SaveNodeConnectionCosts = 	1 << 2;
  			public static int SaveNodePositions = 			1 << 3;
  			public static int RunLengthEncoding = 			1 << 4;
  			
  			public static string BitName (int i) {
  				switch (i) {
  					case 0: return "Nodes";
  					case 1: return "Node Connections";
  					case 2: return "Node Connection Costs";
  					case 3: return "Node Positions";
  					case 4: return "Run Length Encoding";
  				}
  				return null;
  			}
  		}
  		
  		//public const int SaveSettings = 			1 << 4;
  		
  		public bool onlySaveSettings = false;
  		public bool compress = true;
  		
  		//public string[] graphGUIDReferences;
  		
  		/** The GUIDs of the graphs saved with the file (only set in load) */
  		public string[] loadedGraphGuids;
  		
  		/** The indices to the graphs in the new AstarData. Conversion from loaded indices (newGraphIndex = graphRefGuids[oldGraphIndex]) */
  		public int[] graphRefGuids;
  		
  		public SerializerError error = SerializerError.Nothing;
  		
  		public Dictionary<string,int> anchors;
  		
  		public delegate UnityEngine.Object ReadUnityReference_Editor (AstarSerializer serializer, string name, int instanceID, System.Type type);
  		public delegate void WriteUnityReference_Editor (AstarSerializer serializer, UnityEngine.Object ob);
  		
  		public static ReadUnityReference_Editor readUnityReference_Editor = null;
  		public static WriteUnityReference_Editor writeUnityReference_Editor = null;
  		
  		/** Key, position */
  		public Dictionary<string,int> serializedVariables = new Dictionary<string, int> ();
  		
  		public Hashtable serializedData;
  		/** Prefix to use before variables. Used to avoid name collisions */
  		public string sPrefix = "";
  		public byte prefix = 0;
  		
  		public int counter;
  		public int positionAtCounter = -1;
  		public long positionAtError = -1;
  		
  		public enum SerializerError {
  			Nothing,
  			WrongMagic,
  			WrongVersion,
  			DoesNotExist
  		}
  		
  		public static AstarSerializer GetDeserializer (Version version, AstarPath script) {
  			if (version == AstarPath.Version) {
  				return new AstarSerializer (script);
  			} else if (version > AstarPath.Version) {
  				//Higher version, trying to load
  				return new AstarSerializer (script);
  			} else {
  				//Load older version
  				if (version >= new Version (3,0,7)) {
  					return new AstarSerializer3_07 (script);
  				} else if (version >= new Version (3,0,5)) {
  					return new AstarSerializer3_05 (script);
  				} else if (version >= new Version (3,0,4)) {
  					return new AstarSerializer3_04 (script);
  				} else {
  					return new AstarSerializer3_01 (script);
  				}
  				/*if (version > new Version (3,0,1)) {
  					return new AstarSerializer3_04 (script);
  				} else {
  					return new AstarSerializer3_01 (script);
  				}*/
  			}
  		}
  		
  		protected AstarSerializer () {}
  		
  		public AstarSerializer (AstarPath script) {
  			active = script;
  			astarData = script.astarData;
  			mask = -1;
  			mask -= SMask.SaveNodes;
  		}
  		
  		public void SetUpGraphRefs (NavGraph[] graphs) {
  			graphRefGuids = new int[loadedGraphGuids.Length];
  			
  			for (int i=0;i<loadedGraphGuids.Length;i++) {
  				
  				Pathfinding.Util.Guid guid = new Pathfinding.Util.Guid (loadedGraphGuids[i]);
  				
  				graphRefGuids[i] = -1;
  				
  				for (int j=0;j<graphs.Length;j++) {
  					if (graphs[j].guid == guid) {
  						graphRefGuids[i] = i;
  					}
  				}
  				//graphRefGuids[i] = astarData.GuidToIndex ());
  			}
  		}
  		
  		/** This is intended for quick saving of settings for e.g Undo operations */
  		public void OpenSerialize () {
  			onlySaveSettings = true;
  			MemoryStream fs = new MemoryStream ();
  	        
  	        BinaryWriter stream = new BinaryWriter (fs);
  	        writerStream = stream;
  	        
  			//This will be overwritten by the anchor count in SerializeAnchors
  	        writerStream.Write (0);
  	        anchors = new Dictionary<string,int>();
  			
  			SerializeSerializationInfo ();
  			
  			InitializeSerializeNodes ();
  		}
  		
  		/** Opens a deserialization session.
  		 * This function returns an AstarSerializer,
  		 * it will usually be the same as called on, but when loading from older graphs, it will have been replaced by another one.\n
  		 * Use the returned AstarSerializer from now on */
  		public AstarSerializer OpenDeserialize (byte[] data) {
  			//onlySaveSettings = true;
  			
  			MemoryStream fs = new MemoryStream (data);
  			
  			readerStream = new BinaryReader (fs);
  			
  			DeserializeAnchors ();
  			return DeserializeSerializationInfo ();
  		}
  		
  		public void SerializeSerializationInfo () {
  			AddAnchor ("SerializerSettings");
  			BinaryWriter stream = writerStream;
  			
  			stream.Write (AstarPath.Version.ToString ());
  			stream.Write (astarData.graphs.Length);
  			for (int i=0;i<astarData.graphs.Length;i++) {
  				stream.Write (astarData.graphs[i].guid.ToString ());
  			}
  			stream.Write (mask);
  		}
  		
  		/** Deserializes serialization info. Deserializes Version, mask and #loadedGraphGuids
  		  * \see OpenDeserialize */
  		public AstarSerializer DeserializeSerializationInfo () {
  			if (!MoveToAnchor ("SerializerSettings")) {
  				throw (new System.NullReferenceException ("Anchor SerializerSettings was not found in the data"));
  			}
  			
  			BinaryReader stream = readerStream;
  			
  			System.Version astarVersion = null;
  			
  			try {
  				astarVersion = new Version (stream.ReadString ());
  			}
  			
  			catch (Exception e) {
  				Debug.LogError ("Couldn't parse A* version ");
  				error = SerializerError.WrongVersion;
  				throw new System.FormatException ("Couldn't parse A* version",e);
  			}
  			
  			//System.Version astarVersion2 = AstarPath.Version;
  			
  			AstarSerializer returnSerializer = this;
  			
  			if (!IgnoreVersionDifferences) {
  				if (astarVersion > AstarPath.Version) {
  					Debug.LogError ("Loading graph saved with a newer version of the A* Pathfinding Project, trying to load, but you might get errors.\nFile version: "+astarVersion+" Current A* version: "+AstarPath.Version);
  					//error = SerializerError.WrongVersion;
  					//return;
  				} else if (astarVersion != AstarPath.Version) {
  					Debug.LogWarning ("Loading graphs saved with an older version of the A* Pathfinding Project, trying to load.\nFile version: "+astarVersion+" Current A* version: "+AstarPath.Version);
  					
  					//Select the appropriate deserializer
  					if (astarVersion < new Version (3,0,4)) {
  						returnSerializer = new AstarSerializer3_01 (active);
  					} else if (astarVersion < new Version (3,0,5)) {
  						returnSerializer = new AstarSerializer3_04 (active);
  					} else if (astarVersion < new Version (3,0,6)) {
  						returnSerializer = new AstarSerializer3_05 (active);
  					}
  					
  					//Copy this serializer's loaded values to the new serializer
  					returnSerializer.readerStream = readerStream;
  					returnSerializer.anchors = anchors;
  				}
  			}
  			
  			int count = stream.ReadInt32 ();
  			
  			//@Fix - Look up existing graph first
  			returnSerializer.loadedGraphGuids = new string[count];
  			
  			for (int i=0;i<count;i++) {
  				returnSerializer.loadedGraphGuids[i] = stream.ReadString ();
  				//loadedGraphGuids[i] = i;
  			}
  			
  			
  			returnSerializer.mask = stream.ReadInt32 ();
  			
  			return returnSerializer;
  		}
  		
  		/** Called to serialize a graphs settings. \note Before calling this, setting #sPrefix to something unique for the graph is a good idea to avoid collisions in variable names */
  		public void SerializeSettings (NavGraph graph, AstarPath active) {
  			
  			ISerializableGraph serializeGraph = graph as ISerializableGraph;
  				
  			if (serializeGraph == null) {
  				Debug.LogError ("The graph specified is not serializable, the graph is of type "+graph.GetType());
  				return;
  			}
  	        
  			serializeGraph.SerializeSettings (this);
  		}
  		
  		public void InitializeSerializeNodes () {
  			throw new NotImplementedException ("This function is deprecated");
  		}
  		
  		/** Serializes the nodes in the graph.
  		 * \astarpro */
  		public void SerializeNodes (NavGraph graph, AstarPath active) {
  			if (mask == SMask.SaveNodes) {
  
  				ISerializableGraph serializeGraph = graph as ISerializableGraph;
  				
  				if (serializeGraph == null) {
  					Debug.LogError ("The graph specified is not serializable, the graph is of type "+graph.GetType());
  					return;
  				}
  				
  				if (graph.nodes == null || graph.nodes.Length == 0) {
  					writerStream.Write (0);
  					//Debug.LogWarning ("No nodes to serialize");
  					return;
  				}
  				
  				writerStream.Write (graph.nodes.Length);
  				
  				//writerStream.Write (savingToFile ? 753 : 1337);
  				Debug.Log ("Stored nodes "+" "+writerStream.BaseStream.Position);
  				
  				SizeProfiler.Begin ("Graph specific nodes",writerStream);
  				
  				AddVariableAnchor ("DeserializeGraphNodes");
  				serializeGraph.SerializeNodes (graph.nodes,this);
  				
  				SizeProfiler.End ("Graph specific nodes",writerStream);
  				
  				AddVariableAnchor ("DeserializeNodes");
  				
  				if (mask == SMask.RunLengthEncoding) {
  					
  					SizeProfiler.Begin ("RLE Penalty",writerStream);
  					//Penalties
  					int lastValue = (int)graph.nodes[0].penalty;
  					int lastEntry = 0;
  					
  					for (int i=1;i<graph.nodes.Length;i++) {
  						if (graph.nodes[i].penalty != lastValue || (i-lastEntry) >= byte.MaxValue-1) {
  							writerStream.Write ((byte)(i-lastEntry));
  							writerStream.Write (lastValue);
  							lastValue = (int)graph.nodes[i].penalty;
  							lastEntry = i;
  						}
  					}
  					
  					writerStream.Write ((byte)(graph.nodes.Length-lastEntry));
  					writerStream.Write (lastValue);
  					
  					SizeProfiler.Begin ("RLE Flags",writerStream);
  					
  					//Flags
  					lastValue = graph.nodes[0].flags;
  					lastEntry = 0;
  					
  					for (int i=1;i<graph.nodes.Length;i++) {
  						if (graph.nodes[i].flags != lastValue || (i-lastEntry) >= byte.MaxValue) {
  							writerStream.Write ((byte)(i-lastEntry));
  							writerStream.Write (lastValue);
  
gt: 							lastValue = graph.nodes[i].flags;