/// <summary>
        ///     Requests loading the image of <paramref name="size"/> located on <paramref name="uri"/>. 
        /// </summary>
        /// <param name="uri">
        ///     An uri of the image to load.
        /// </param>
        /// <param name="size">
        ///     The desired size of the image.
        /// </param>
        /// <returns>
        ///     Returns an observable sequence which contains an image(s) of <paramref name="size"/> loaded using <paramref name="uri"/>.
        /// </returns>
        /// <remarks>
        ///     Override this method to provide concrete logic of loading the image per each <see cref="BaseImageLoader"/>.
        /// </remarks>
        protected override IObservable<ImageInfo> WhenLoadedInternal(Uri uri, Size size)
        {
            var result = Observable.Create<ImageInfo>(observer =>
                {
                    var imageLoadContext = new ImageLoadContext(uri, size, observer);

                    this.downloadManager.EnqeueReqeust(imageLoadContext);

                    return () => this.downloadManager.DequeueRequest(imageLoadContext);
                });

            return result;
        }
        /// <summary>
        ///     Requests loading the image of <paramref name="size"/> located on <paramref name="uri"/>.
        /// </summary>
        /// <param name="uri">
        ///     An uri of the image to load.
        /// </param>
        /// <param name="size">
        ///     The desired size of the image.
        /// </param>
        /// <returns>
        ///     Returns an observable sequence which contains an image(s) of <paramref name="size"/> loaded using <paramref name="uri"/>.
        /// </returns>
        /// <remarks>
        ///     The observable sequence may generate several instances of same image but with different size. For example,
        ///     there cam be a smaller sample of the requested image in the local cache, so this image will be returned immediatly while the image of requested 
        ///     size is loading. Once the image of the desired size is loaded, it will be pushed into the same observable sequence.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///     <paramref name="size"/> has non positive width or height.
        /// </exception>
        public IObservable<ImageInfo> WhenLoaded(Uri uri, Size size)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            if (size == default(Size) || size.Width <= 0 || size.Height <= 0)
            {
                throw new ArgumentException("The size should have positive width and height", "size");
            }

            return this.WhenLoaded(uri, size, new Size(0, 0));
        }
        protected override IObservable<ImageInfo> WhenLoadedInternal(Uri uri, Size size)
        {
            return Observable.Create<ImageInfo>(observer =>
                {
                    if (imageData != null)
                    {
                        var imageInfo = new ImageInfo(uri, size, imageData) { ForceFallback = true };
                        observer.OnNext(imageInfo);
                    }

                    observer.OnCompleted();

                    return () => { };
                });
        }
 public ImageLoadContext(Uri uri, Size size, IObserver<ImageInfo> observer)
 {
     this.Uri = uri;
     this.Size = size;
     this.Observer = observer;
 }
 public ImageInfo(Uri uri, Size size, byte[] data)
 {
     this.Uri = uri;
     this.Size = size;
     this.Data = data;
 }
        internal ImageInfo WithSize(Size size)
        {
            this.Size = size;

            return this;
        }
 internal bool IsFittedIn(Size size)
 {
     return this.Size.Width >= size.Width || this.Size.Height >= size.Height;
 }
 /// <summary>
 ///     Requests loading the image of <paramref name="size"/> located on <paramref name="uri"/>. 
 /// </summary>
 /// <param name="uri">
 ///     An uri of the image to load.
 /// </param>
 /// <param name="size">
 ///     The desired size of the image.
 /// </param>
 /// <returns>
 ///     Returns an observable sequence which contains an image(s) of <paramref name="size"/> loaded using <paramref name="uri"/>.
 /// </returns>
 /// <remarks>
 ///     Override this method to provide concrete logic of loading the image per each <see cref="BaseImageLoader"/>.
 /// </remarks>
 protected abstract IObservable<ImageInfo> WhenLoadedInternal(Uri uri, Size size);
        /// <summary>
        ///     Requests loading the image of <paramref name="size"/> located on <paramref name="uri"/>. 
        /// </summary>
        /// <param name="uri">
        ///     An uri of the image to load.
        /// </param>
        /// <param name="size">
        ///     The desired size of the image.
        /// </param>
        /// <param name="minSize">
        ///     Thi mimimum accetable size. 
        /// </param>
        /// <returns>
        ///     Returns an observable sequence which contains an image(s) of <paramref name="size"/> loaded using <paramref name="uri"/>.
        /// </returns>
        /// <remarks>
        ///     If the image cannot be loaded or loaded image has smaller size than requested, then it tries to load the image using fallback
        ///     <see cref="BaseImageLoader"/>. All intermediate images (the images of smaller size than requested), are pushed into observable sequence.
        /// </remarks>
        protected IObservable<ImageInfo> WhenLoaded(Uri uri, Size size, Size minSize)
        {
            var result = Observable.Create<ImageInfo>(observer =>
                {
                    ImageInfo image = null;
                    var compositeDisposable = new CompositeDisposable();

                    compositeDisposable.Add(this.WhenLoadedInternal(uri, size).Subscribe(
                        img =>
                        {
                            observer.OnNext(img);
                            image = img;
                        },
                        err =>
                        {
                            if (fallbackLoader != null)
                            {
                                compositeDisposable.Add(this.fallbackLoader.WhenLoaded(uri, size, minSize)
                                    .Do(this.OnFallbackImageLoaded)
                                    .Subscribe(observer));
                            }
                            else
                            {
                                observer.OnError(err);
                            }
                        },
                        () =>
                        {
                            if ((image == null || image.IsFittedIn(size) == false || image.ForceFallback) && fallbackLoader != null)
                            {
                                compositeDisposable.Add(this.fallbackLoader.WhenLoaded(uri, size, image == null ? minSize : image.Size)
                                    .Do(this.OnFallbackImageLoaded)
                                    .Subscribe(observer));
                            }
                            else
                            {
                                observer.OnCompleted();
                            }
                        }));

                    return () => { compositeDisposable.Dispose(); };
                });

            return result;
        }