/// <summary>
        /// Creates initialization REST request.
        /// </summary>
        /// <param name="request">The instance of uploading file request.</param>
        /// <returns>A REST request to initialize uploading a file with chunks.</returns>
        private static IRestRequest CreateInitRestRequest(DriveFileUploadRequest request)
        {
            var result = RestRequestFactory.CreateRestRequest(ServiceDefs.Drive.DriveUploadFilesResource, Method.POST, request, true);

            result.AddParameter("X-Upload-Content-Type", request.UploadContentType, ParameterType.HttpHeader);
            result.AddParameter("X-Upload-Content-Length", request.LocalStream.Length, ParameterType.HttpHeader);
            return(result);
        }
        /// <summary>
        /// Uploads a file with a specified chunk size.
        /// </summary>
        /// <param name="request">The uploading file request.</param>
        /// <param name="driveClient">The Google Drive client.</param>
        /// <param name="chunkSize">The file chunk size.</param>
        /// <param name="writeChunkTimeout">The timeout in milliseconds to write a file chunk.</param>
        /// <returns>A response with information about remote file.</returns>
        private static DriveResponse <DriveFileInfo> Upload(DriveFileUploadRequest request, DriveClient driveClient, uint chunkSize, int writeChunkTimeout)
        {
            const string locationHeaderName = "Location";
            var          log = Log;

            log.Debug("Upload: Chunk size: \"{0}\"", chunkSize);
            var           stream           = request.LocalStream;
            var           initRestRequest  = CreateInitRestRequest(request);
            var           driveRestClient  = driveClient.DriveRestClient;
            var           initRestResponse = RequestHandler.Request(driveRestClient, initRestRequest, HttpStatusCode.OK);
            var           locationHeader   = initRestResponse.Headers.FirstOrDefault(x => x.Name == locationHeaderName);
            IRestResponse lastrestResponse = initRestResponse;

            if (locationHeader != null)
            {
                string uploadContentType = request.UploadContentType;
                var    location          = locationHeader.Value as string;
                Debug.Assert(location != null, "location != null");
                var uploadClient = new RestClient(location)
                {
                    Authenticator = driveClient.Authenticator.RestAuthenticator
                };
                var  buffer  = new byte[chunkSize];
                long filePos = 0,
                     fileLen = stream.Length;
                int bufferLen;

                request.RaiseUploadProgress(filePos, fileLen);

                while ((bufferLen = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    const string rangeHeaderName = "Range";
                    log.Trace("Upload: Uploading a chunk of file. FilePos: \"{0}\"; BufferLen: \"{1}\"; FileLen: \"{2}\"", filePos, bufferLen, fileLen);
                    var          data = bufferLen < buffer.Length ? CreateArray(buffer, 0, bufferLen) : buffer;
                    IRestRequest uploadRestRequest = CreateUploadRestRequest(uploadContentType, chunkSize, filePos, bufferLen, fileLen, data);
                    uploadRestRequest.Timeout = writeChunkTimeout;
                    lastrestResponse          = RequestHandler.Request(uploadClient, uploadRestRequest, ResumeIncomplete, HttpStatusCode.Created, HttpStatusCode.OK);

                    if (lastrestResponse.StatusCode == HttpStatusCode.Created || lastrestResponse.StatusCode == HttpStatusCode.OK)
                    {
                        request.RaiseUploadProgress(filePos + bufferLen, fileLen);
                        break;
                    }

                    var rangeResultHeader = lastrestResponse.Headers.FirstOrDefault(x => x.Name == rangeHeaderName);
                    if (rangeResultHeader != null)
                    {
                        var rangeResultStr = rangeResultHeader.Value as string;

                        if (rangeResultStr == null)
                        {
                            throw new InteractionException(MessageDefs.ClientName, MessageDefs.InvalidRangeHeaderOfUploadResponse,
                                                           lastrestResponse.StatusCode, lastrestResponse.StatusDescription,
                                                           string.Format(LocalStrings.RangeHeaderInvalidErrorMessage1, rangeResultHeader.Value));
                        }

                        string[] rangeResultItems = rangeResultStr.Replace(" ", string.Empty).Split('-');

                        if (rangeResultItems.Length > 1)
                        {
                            long endRange;

                            if (long.TryParse(rangeResultItems[1], out endRange))
                            {
                                filePos = endRange == 0 ? 0 : endRange + 1;

                                if (filePos != stream.Position)
                                {
                                    stream.Seek(filePos, SeekOrigin.Begin);
                                }

                                request.RaiseUploadProgress(filePos, fileLen);
                            }
                            else
                            {
                                throw new InteractionException(MessageDefs.ClientName, MessageDefs.InvalidRangeHeaderOfUploadResponse,
                                                               lastrestResponse.StatusCode, lastrestResponse.StatusDescription,
                                                               string.Format(LocalStrings.RangeHeaderInvalidEndErrorMessage1, rangeResultStr));
                            }
                        }
                        else
                        {
                            throw new InteractionException(MessageDefs.ClientName, MessageDefs.InvalidRangeHeaderOfUploadResponse,
                                                           lastrestResponse.StatusCode, lastrestResponse.StatusDescription,
                                                           string.Format(LocalStrings.RangeHeaderInvalidEndErrorMessage1, rangeResultStr));
                        }
                    }
                    else
                    {
                        throw new InteractionException(MessageDefs.ClientName, MessageDefs.NoRangeHeaderOfUploadResponse,
                                                       lastrestResponse.StatusCode, lastrestResponse.StatusDescription, LocalStrings.RangeHeaderNotExistErrorMessage);
                    }
                }
            }
            else
            {
                throw new InteractionException(MessageDefs.ClientName, MessageDefs.NoLocationHeaderOfUploadResponse,
                                               lastrestResponse.StatusCode, lastrestResponse.StatusDescription, LocalStrings.LocationHeaderNotExistsMessage);
            }

            var result = new DriveResponse <DriveFileInfo>(lastrestResponse);

            return(result);
        }