/// <summary>
 ///     Traverses the variable structure with the specified path.
 ///     Path components can be either strings representing keys in a dictionary,
 ///     or integers representing indices in a list.
 /// </summary>
 public override object ObjectForKeyPathComponents(object[] pathComponents)
 {
     return(VarCache.GetMergedValueFromComponentArray(pathComponents));
 }
        public override void Update()
        {
            object newValue = VarCache.GetMergedValueFromComponentArray(NameComponents);

            if (newValue == null)
            {
                newValue = GetDefaultValue();
            }

            if (Kind == Constants.Kinds.FILE)
            {
                if (VarCache.IsSilent)
                {
                    return;
                }

                string newFile = newValue.ToString();
                if (string.IsNullOrEmpty(newFile))
                {
                    return;
                }

                string url = null;
                if (VarCache.FileAttributes != null && VarCache.FileAttributes.ContainsKey(newFile))
                {
                    IDictionary <string, object> currentFile =
                        (VarCache.FileAttributes[newFile] as IDictionary <string, object>)
                        [string.Empty] as IDictionary <string, object>;
                    if (currentFile.ContainsKey(Constants.Keys.URL))
                    {
                        url = GetResourceURL(newFile);
                    }
                }

                // Download new file if the file is different than:
                // - the current file for the varible
                // - the file currently being downloaded for the variable
                // - there is no file value and realtime updating is enabled
                // Do not download and update if realtime updating is disabled
                // Wait until the file is downloaded from the server
                if (currentlyDownloadingFile != newFile && !string.IsNullOrEmpty(url) &&
                    ((newFile != FileName && realtimeAssetUpdating && fileReady) ||
                     (Value == null && realtimeAssetUpdating)))
                {
                    currentlyDownloadingFile = newFile;
                    FileName  = newFile;
                    fileReady = false;

                    void OnFileResponse(object file)
                    {
                        _value = (T)file;
                        if (newFile == FileName && !fileReady)
                        {
                            fileReady = true;
                            OnValueChanged();
                            currentlyDownloadingFile = null;
                        }
                    }

                    void OnFileError(Exception ex)
                    {
                        if (newFile == FileName && !fileReady)
                        {
                            string errorMessage = $"Error downloading AssetBundle \"{Name}\" with \"{FileName}\". {ex}";
                            LeanplumNative.CompatibilityLayer.LogError(errorMessage);
                            currentlyDownloadingFile = null;
                        }
                    }

                    Leanplum.FileTransferManager.DownloadAssetResource(url, OnFileResponse, OnFileError);
                }
            }
            else
            {
                if (Json.Serialize(newValue) != Json.Serialize(Value))
                {
                    try
                    {
                        if (newValue is IDictionary || newValue is IList)
                        {
                            // If the value is a container, copy all the values from the newValue container to Value.
                            Util.FillInValues(newValue, Value);
                        }
                        else
                        {
                            _value = (T)Convert.ChangeType(newValue, typeof(T));
                        }

                        if (VarCache.IsSilent)
                        {
                            return;
                        }

                        OnValueChanged();
                    }
                    catch (Exception ex)
                    {
                        Util.MaybeThrow(new LeanplumException("Error parsing values from server. " + ex.ToString()));
                        return;
                    }
                }
            }
        }
        public override void Update()
        {
            object newValue = VarCache.GetMergedValueFromComponentArray(NameComponents);

            if (newValue == null)
            {
                newValue = GetDefaultValue();
            }

            if (Kind == Constants.Kinds.FILE)
            {
                if (VarCache.IsSilent)
                {
                    return;
                }
                string newFile = newValue.ToString();
                string url     = null;

                if (String.IsNullOrEmpty(newFile))
                {
                    return;
                }

                if (VarCache.FileAttributes != null && VarCache.FileAttributes.ContainsKey(newFile))
                {
                    IDictionary <string, object> currentFile =
                        (VarCache.FileAttributes[newFile] as IDictionary <string, object>)
                        [String.Empty] as IDictionary <string, object>;
                    if (currentFile.ContainsKey(Constants.Keys.URL))
                    {
                        url = ((VarCache.FileAttributes[newFile] as IDictionary <string, object>)
                               [String.Empty] as IDictionary <string, object>)[Constants.Keys.URL] as string;
                    }
                }

                // Update if the file is different from what we currently have and if we have started downloading it
                // already. Also update if we don't have the file but don't update if realtime updating is disabled -
                // wait 'til we get the value from the serve so that the correct file is displayed.
                if (currentlyDownloadingFile != newFile && !String.IsNullOrEmpty(url) &&
                    ((newFile != FileName && realtimeAssetUpdating && fileReady) ||
                     (Value == null && realtimeAssetUpdating)))
                {
                    VarCache.downloadsPending++;
                    currentlyDownloadingFile = newFile;
                    FileName  = newFile;
                    fileReady = false;

                    LeanplumRequest downloadRequest = LeanplumRequest.Get(url.Substring(1));
                    downloadRequest.Response += delegate(object obj) {
                        _value = (T)obj;
                        if (newFile == FileName && !fileReady)
                        {
                            fileReady = true;
                            OnValueChanged();
                            currentlyDownloadingFile = null;
                        }
                        VarCache.downloadsPending--;
                    };
                    downloadRequest.Error += delegate(Exception obj) {
                        if (newFile == FileName && !fileReady)
                        {
                            LeanplumNative.CompatibilityLayer.LogError("Error downloading assetbundle \"" +
                                                                       FileName + "\". " + obj.ToString());
                            currentlyDownloadingFile = null;
                        }
                        VarCache.downloadsPending--;
                    };
                    downloadRequest.DownloadAssetNow();
                }
            }
            else
            {
                if (Json.Serialize(newValue) != Json.Serialize(Value))
                {
                    try
                    {
                        if (newValue is IDictionary || newValue is IList)
                        {
                            // If the value is a container, copy all the values from the newValue container to Value.
                            SharedUtil.FillInValues(newValue, Value);
                        }
                        else
                        {
                            _value = (T)Convert.ChangeType(newValue, typeof(T));
                        }
                        if (VarCache.IsSilent)
                        {
                            return;
                        }
                        OnValueChanged();
                    }
                    catch (Exception ex)
                    {
                        Util.MaybeThrow(new LeanplumException("Error parsing values from server. " + ex.ToString()));
                        return;
                    }
                }
            }
        }