/// <summary>
        /// Get information of current session (API: session-get)
        /// </summary>
        /// <returns>Session information</returns>
        public async Task <SessionInformation> SessionGetAsync()
        {
            var request = new TransmissionRequest("session-get", null);
            TransmissionResponse response = await SendRequestAsync(request);

            return(response.Deserialize <SessionInformation>());
        }
        /// <summary>
        /// Get session statistic
        /// </summary>
        /// <returns>Session stat</returns>
        public async Task <Statistic> SessionGetStatisticAsync()
        {
            var request = new TransmissionRequest("session-stats", null);
            TransmissionResponse response = await SendRequestAsync(request);

            return(response.Deserialize <Statistic>());
        }
        /// <summary>
        /// Add torrent (API: torrent-add)
        /// </summary>
        /// <param name="torrent"></param>
        /// <returns>Torrent info (ID, Name and HashString)</returns>
        public async Task <CreatedTorrent> TorrentAddAsync(NewTorrent torrent)
        {
            if (string.IsNullOrWhiteSpace(torrent.MetaInfo) && string.IsNullOrWhiteSpace(torrent.Filename))
            {
                throw new Exception("Either \"filename\" or \"metainfo\" must be included.");
            }

            var request = new TransmissionRequest("torrent-add", torrent.ToDictionary());

            TransmissionResponse response = await SendRequestAsync(request);

            JObject jObject = response.Deserialize <JObject>();

            if (jObject?.First == null)
            {
                return(null);
            }

            if (jObject.TryGetValue("torrent-duplicate", out JToken value))
            {
                return(JsonConvert.DeserializeObject <CreatedTorrent>(value.ToString()));
            }

            if (jObject.TryGetValue("torrent-added", out value))
            {
                return(JsonConvert.DeserializeObject <CreatedTorrent>(value.ToString()));
            }

            return(null);
        }
        /// <summary>
        /// See if your incoming peer port is accessible from the outside world (API: port-test)
        /// </summary>
        /// <returns>Accessible state</returns>
        public async Task <bool> PortTestAsync()
        {
            var request = new TransmissionRequest("port-test", null);

            TransmissionResponse response = await SendRequestAsync(request);

            JObject data = response.Deserialize <JObject>();

            return((bool)data.GetValue("port-is-open"));
        }
        /// <summary>
        /// Rename a file or directory in a torrent (API: torrent-rename-path)
        /// </summary>
        /// <param name="id">The torrent whose path will be renamed</param>
        /// <param name="path">The path to the file or folder that will be renamed</param>
        /// <param name="name">The file or folder's new name</param>
        public async Task <RenamedTorrent> TorrentRenamePathAsync(int id, string path, string name)
        {
            var arguments = new Dictionary <string, object>
            {
                { "ids", new[] { id } },
                { "path", path },
                { "name", name }
            };

            var request = new TransmissionRequest("torrent-rename-path", arguments);

            TransmissionResponse response = await SendRequestAsync(request);

            return(response.Deserialize <RenamedTorrent>());
        }
        /// <summary>
        /// Add torrents (API: torrent-add)
        /// </summary>
        /// <param name="torrents"></param>
        /// <returns>Torrent info (ID, Name and HashString)</returns>
        public async Task <AddTorrentsResponse> TorrentsAddAsync(List <NewTorrent> torrents)
        {
            var successes = new List <AddTorrentSuccess>();
            var failures  = new List <AddTorrentFailure>();

            foreach (var torrent in torrents)
            {
                try
                {
                    var request = new TransmissionRequest("torrent-add", torrent.ToDictionary());

                    TransmissionResponse response = await SendRequestAsync(request);

                    if (!response.Result.Equals("success", StringComparison.OrdinalIgnoreCase))
                    {
                        failures.Add(new AddTorrentFailure
                        {
                            SubmittedData     = torrent.Filename ?? torrent.MetaInfo,
                            SubmittedDataType = !string.IsNullOrEmpty(torrent.Filename) ? "file or url" : "meta info",
                            Error             = response.Result
                        });

                        continue;
                    }

                    JObject jObject = response.Deserialize <JObject>();

                    if (jObject?.First == null)
                    {
                        failures.Add(new AddTorrentFailure
                        {
                            SubmittedData     = torrent.Filename ?? torrent.MetaInfo,
                            SubmittedDataType = !string.IsNullOrEmpty(torrent.Filename) ? "file or url" : "meta info",
                            Error             = "Deserialization error"
                        });

                        continue;
                    }

                    if (jObject.TryGetValue("torrent-duplicate", out JToken value))
                    {
                        successes.Add(new AddTorrentSuccess
                        {
                            SubmittedData        = torrent.Filename ?? torrent.MetaInfo,
                            SubmittedDataType    = !string.IsNullOrEmpty(torrent.Filename) ? "file or url" : "meta info",
                            TransmissionResponse = JsonConvert.DeserializeObject <CreatedTorrent>(value.ToString())
                        });

                        continue;
                    }

                    if (jObject.TryGetValue("torrent-added", out value))
                    {
                        successes.Add(new AddTorrentSuccess
                        {
                            SubmittedData        = torrent.Filename ?? torrent.MetaInfo,
                            SubmittedDataType    = !string.IsNullOrEmpty(torrent.Filename) ? "file or url" : "meta info",
                            TransmissionResponse = JsonConvert.DeserializeObject <CreatedTorrent>(value.ToString())
                        });
                    }
                }
                catch (Exception e)
                {
                    failures.Add(new AddTorrentFailure
                    {
                        SubmittedData     = torrent.Filename ?? torrent.MetaInfo,
                        SubmittedDataType = !string.IsNullOrEmpty(torrent.Filename) ? "file or url" : "meta info",
                        Error             = $"Unknown error occurred: {e.Message}"
                    });
                }
            }

            return(new AddTorrentsResponse
            {
                Successes = successes.Any() ? successes : null,
                Failures = failures.Any() ? failures : null
            });
        }