/// <summary>
 /// Initializes a new instance of the <see cref="Tango.UUIDUnityHolder"/> class.
 /// </summary>
 public UUIDUnityHolder()
 {
     uuidObject = new UUID();
     uuidMetaData = new Metadata();
     uuidObject.data = IntPtr.Zero;
     uuidName = string.Empty;
 }
        /// <summary>
        /// Save the metadata for this area description.
        /// </summary>
        /// <returns>Returns <c>true</c> if the metadata was successfully saved, <c>false</c> otherwise.</returns>
        /// <param name="metadata">Metadata to save.</param>
        public bool SaveMetadata(Metadata metadata)
        {
            IntPtr rawMetadata = _GetMetadataPtr();
            if (rawMetadata == IntPtr.Zero)
            {
                return false;
            }

            bool anyErrors = false;
            if (!_MetadataSetString(rawMetadata, "name", metadata.m_name))
            {
                anyErrors = true;
            }

            if (!_MetadataSetInt64(rawMetadata, "date_ms_since_epoch",
                                   (metadata.m_dateTime.Ticks - METADATA_EPOCH.Ticks) / DATETIME_TICKS_PER_MS))
            {
                anyErrors = true;
            }

            double[] tform = new double[7];
            tform[0] = metadata.m_transformationPosition[0];
            tform[1] = metadata.m_transformationPosition[1];
            tform[2] = metadata.m_transformationPosition[2];
            tform[3] = metadata.m_transformationRotation[0];
            tform[4] = metadata.m_transformationRotation[1];
            tform[5] = metadata.m_transformationRotation[2];
            tform[6] = metadata.m_transformationRotation[3];
            if (!_MetadataSetDoubleArray(rawMetadata, "transformation", tform))
            {
                anyErrors = true;
            }

            if (!anyErrors)
            {
                int returnValue = AreaDescriptionAPI.TangoService_saveAreaDescriptionMetadata(m_uuid, rawMetadata);
                if (returnValue != Common.ErrorType.TANGO_SUCCESS)
                {
                    Debug.Log("Could not save metadata values.\n" + Environment.StackTrace);
                    anyErrors = true;
                }
            }

            _FreeMetadataPtr(rawMetadata);
            return !anyErrors;
        }
        /// <summary>
        /// Get the metadata for the Area Description.
        /// 
        /// If you want to create a metadata for a not yet saved Area Description, you should instead use the default
        /// constructor.
        /// </summary>
        /// <returns>The metadata, or <c>null</c> if that Area Description does not exist.</returns>
        public Metadata GetMetadata()
        {
            IntPtr rawMetadata = _GetMetadataPtr();
            if (rawMetadata == IntPtr.Zero)
            {
                return null;
            }

            Metadata newData = new Metadata();
            if (!_MetadataGetString(rawMetadata, "name", out newData.m_name))
            {
                newData.m_name = string.Empty;
            }

            Int64 dateMSSinceEpoch;
            if (!_MetadataGetInt64(rawMetadata, "date_ms_since_epoch", out dateMSSinceEpoch))
            {
                dateMSSinceEpoch = 0;
            }
            newData.m_dateTime = new DateTime(METADATA_EPOCH.Ticks + (dateMSSinceEpoch * DATETIME_TICKS_PER_MS));

            double[] tform;
            if (!_MetadataGetDoubleArray(rawMetadata, "transformation", 7, out tform))
            {
                tform[0] = tform[1] = tform[2] = tform[3] = tform[4] = tform[5] = 0;
                tform[6] = 1;
            }
            newData.m_transformationPosition = new double[3] { tform[0], tform[1], tform[2] };
            newData.m_transformationRotation = new double[4] { tform[3], tform[4], tform[5], tform[6] };

            _FreeMetadataPtr(rawMetadata);
            return newData;
        }
        /// <summary>
        /// Save the metadata for this area description.
        /// </summary>
        /// <returns>Returns <c>true</c> if the metadata was successfully saved, <c>false</c> otherwise.</returns>
        /// <param name="metadata">Metadata to save.</param>
        public bool SaveMetadata(Metadata metadata)
        {
#if UNITY_EDITOR
            try
            {
                using (StreamWriter streamWriter = 
                       new StreamWriter(File.Open(EMULATED_ADF_SAVE_PATH + m_uuid + EMULATED_ADF_EXTENSION,
                                                  FileMode.Create)))
                {
                    metadataXmlSerializer.Serialize(streamWriter, metadata);
                }
            }
            catch (IOException ioException)
            {
                Debug.LogError("IO error in Area Description save/load emulation:\n" 
                               + ioException.Message);
                return false;
            }
            
            return true;
#else
            IntPtr rawMetadata = _GetMetadataPtr();
            if (rawMetadata == IntPtr.Zero)
            {
                return false;
            }

            bool anyErrors = false;
            if (!_MetadataSetString(rawMetadata, "name", metadata.m_name))
            {
                anyErrors = true;
            }

            if (!_MetadataSetInt64(rawMetadata, "date_ms_since_epoch",
                                   (metadata.m_dateTime.Ticks - METADATA_EPOCH.Ticks) / DATETIME_TICKS_PER_MS))
            {
                anyErrors = true;
            }

            double[] tform = new double[7];
            tform[0] = metadata.m_transformationPosition[0];
            tform[1] = metadata.m_transformationPosition[1];
            tform[2] = metadata.m_transformationPosition[2];
            tform[3] = metadata.m_transformationRotation[0];
            tform[4] = metadata.m_transformationRotation[1];
            tform[5] = metadata.m_transformationRotation[2];
            tform[6] = metadata.m_transformationRotation[3];
            if (!_MetadataSetDoubleArray(rawMetadata, "transformation", tform))
            {
                anyErrors = true;
            }

            if (!anyErrors)
            {
                int returnValue = AreaDescriptionAPI.TangoService_saveAreaDescriptionMetadata(m_uuid, rawMetadata);
                if (returnValue != Common.ErrorType.TANGO_SUCCESS)
                {
                    Debug.Log("Could not save metadata values.\n" + Environment.StackTrace);
                    anyErrors = true;
                }
            }

            _FreeMetadataPtr(rawMetadata);
            return !anyErrors;
#endif
        }
        /// <summary>
        /// Get the metadata for the Area Description.
        /// 
        /// If you want to create a metadata for a not yet saved Area Description, you should instead use the default
        /// constructor.
        /// </summary>
        /// <returns>The metadata, or <c>null</c> if that Area Description does not exist.</returns>
        public Metadata GetMetadata()
        {
#if UNITY_EDITOR
            Metadata metadata = new Metadata();

            try
            {
                if (!File.Exists(EMULATED_ADF_SAVE_PATH + m_uuid + EMULATED_ADF_EXTENSION))
                {
                    return null;
                }

                using (StreamReader streamReader = 
                       new StreamReader(File.OpenRead(EMULATED_ADF_SAVE_PATH + m_uuid + EMULATED_ADF_EXTENSION)))
                {
                    metadata = (Metadata)metadataXmlSerializer.Deserialize(streamReader);
                }
            }
            catch (IOException ioException)
            {
                Debug.LogError("IO error in Area Description save/load emulation:\n" 
                               + ioException.Message);
                return null;
            }
            catch (System.Xml.XmlException xmlException)
            {
                Debug.LogError("XML error in Area Description save/load emulation"
                               + " (corrupt file contents?); returning blank metadata (for file: "
                               + EMULATED_ADF_SAVE_PATH + m_uuid + EMULATED_ADF_EXTENSION + ")\n" 
                               + "Error: " + xmlException.Message);
            }

            // Make sure there are no fields left atypically uninitialized
            // in emulation even if some fields are missing from or corrupted in XML:
            if (metadata.m_name == null)
            {
                metadata.m_name = string.Empty;
            }

            if (metadata.m_transformationPosition == null)
            {
                metadata.m_transformationPosition = new double[3];
            }

            if (metadata.m_transformationRotation == null)
            {
                metadata.m_transformationRotation = new double[] { 0, 0, 0, 1 };
            }

            return metadata;
#else
            IntPtr rawMetadata = _GetMetadataPtr();
            if (rawMetadata == IntPtr.Zero)
            {
                return null;
            }

            Metadata newData = new Metadata();
            if (!_MetadataGetString(rawMetadata, "name", out newData.m_name))
            {
                newData.m_name = string.Empty;
            }

            Int64 dateMSSinceEpoch;
            if (!_MetadataGetInt64(rawMetadata, "date_ms_since_epoch", out dateMSSinceEpoch))
            {
                dateMSSinceEpoch = 0;
            }

            newData.m_dateTime = new DateTime(METADATA_EPOCH.Ticks + (dateMSSinceEpoch * DATETIME_TICKS_PER_MS));

            double[] tform;
            if (!_MetadataGetDoubleArray(rawMetadata, "transformation", 7, out tform))
            {
                tform[0] = tform[1] = tform[2] = tform[3] = tform[4] = tform[5] = 0;
                tform[6] = 1;
            }

            newData.m_transformationPosition = new double[3] { tform[0], tform[1], tform[2] };
            newData.m_transformationRotation = new double[4] { tform[3], tform[4], tform[5], tform[6] };

            _FreeMetadataPtr(rawMetadata);
            return newData;
#endif
        }
        /// <summary>
        /// Saves the current area description, returning the area description saved.
        /// 
        /// You can only save an area description while connected to the Tango Service and if you have enabled Area
        /// Learning mode. If you loaded an area description before connecting, then calling this method appends any
        /// new learned areas to that area description and returns an area description with the same UUID. If you did
        /// not load an area description, this method creates a new area description and a new UUID for that area
        /// description.
        /// </summary>
        /// <returns>
        /// AreaDescription instance for the newly saved area description if saved successfully, <c>null</c> otherwise.
        /// 
        /// See logcat for details of why a saved failed.
        /// </returns>
        public static AreaDescription SaveCurrent()
        {
#if UNITY_EDITOR
            if (!EmulatedAreaDescriptionHelper.m_usingEmulatedDescriptionFrames)
            {
                Debug.LogError("Error in Area Description save emulation:\nNo current emulated area description.");
                return null;
            }

            // If we don't have an existing UUID, this is a 'new' Area Description, so we'll have to create it.
            if (string.IsNullOrEmpty(EmulatedAreaDescriptionHelper.m_currentUUID))
            {
                // Just use a .net GUID for the UUID.
                string uuid = Guid.NewGuid().ToString();

                EmulatedAreaDescriptionHelper.m_currentUUID = uuid;

                try 
                {
                    Directory.CreateDirectory(EMULATED_ADF_SAVE_PATH);

                    using (StreamWriter streamWriter = 
                           new StreamWriter(File.Open(EMULATED_ADF_SAVE_PATH + uuid + EMULATED_ADF_EXTENSION,
                                                      FileMode.Create)))
                    {
                        Metadata metadata = new Metadata();
                        metadata.m_name = "Unnamed";
                        metadata.m_dateTime = DateTime.Now;
                        metadata.m_transformationPosition = new double[3];
                        metadata.m_transformationRotation = new double[] { 0, 0, 0, 1 };
                        metadataXmlSerializer.Serialize(streamWriter, metadata);
                    }
                }
                catch (IOException ioException)
                {
                    Debug.LogError("IO error in Area Description save/load emulation:\n" 
                                   + ioException.Message);
                    return null;
                }

                return AreaDescription.ForUUID(uuid);
            }
            else
            {
                // Since we don't actually save any description of the area in emulation,
                // if we're using an existing UUID, we don't have to do anything but return it.
                return AreaDescription.ForUUID(EmulatedAreaDescriptionHelper.m_currentUUID);
            }
#else
            byte[] rawUUID = new byte[Common.UUID_LENGTH];
            if (AreaDescriptionAPI.TangoService_saveAreaDescription(rawUUID) != Common.ErrorType.TANGO_SUCCESS)
            {
                Debug.Log("Could not save area description.\n" + Environment.StackTrace);
                return null;
            }

            // Don't want to include the null terminator in the C# string.
            string uuid = Encoding.UTF8.GetString(rawUUID, 0, Common.UUID_LENGTH - 1);

            return AreaDescription.ForUUID(uuid);
#endif
        }