/*
 * Copyright 2016 Google LLC. All rights reserved.
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#import "GooglePlacesDemos/Samples/PagingPhotoView.h"

/**
 * Class to store the image and text views that display the image and attributions.
 */
@interface ImageViewAndAttribution : NSObject

@property(nonatomic, strong) UIImageView *imageView;

@property(nonatomic, strong) UITextView *attributionView;

@end

@implementation ImageViewAndAttribution
@end

@implementation AttributedPhoto
@end

@interface PagingPhotoView () <UITextViewDelegate>
@end

@implementation PagingPhotoView {
  // An array of |ImageViewAndAttribution| objects representing the actual views that are
  // being displayed.
  NSMutableArray *_photoImageViews;
  // Whether we should update the image and attribution view frames on the next |layoutSubviews|
  // call. This should be set to YES whenever the frame is updated or the photos change.
  BOOL _imageLayoutUpdateNeeded;
}

- (instancetype)initWithFrame:(CGRect)frame {
  if ((self = [super initWithFrame:frame])) {
    _photoImageViews = [NSMutableArray array];
    self.backgroundColor = [UIColor whiteColor];
    self.pagingEnabled = YES;
  }
  return self;
}

- (void)setPhotoList:(NSArray *)photoList {
  // First, remove all of the existing image and attribution subviews.
  for (ImageViewAndAttribution *photoView in _photoImageViews) {
    [photoView.imageView removeFromSuperview];
    [photoView.attributionView removeFromSuperview];
  }
  [_photoImageViews removeAllObjects];

  // Add the new images and attributions as subviews.
  _photoList = [photoList copy];
  for (AttributedPhoto *photo in photoList) {
    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectZero];
    textView.delegate = self;
    textView.editable = NO;
    textView.attributedText = photo.attributions;
    [self addSubview:textView];

    UIImageView *imageView = [[UIImageView alloc] initWithImage:photo.image];
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.clipsToBounds = YES;
    [self addSubview:imageView];

    ImageViewAndAttribution *attributedView = [[ImageViewAndAttribution alloc] init];
    attributedView.imageView = imageView;
    attributedView.attributionView = textView;
    [_photoImageViews addObject:attributedView];
  }
  [self updateContentSize];
  _imageLayoutUpdateNeeded = YES;
}

- (void)setFrame:(CGRect)frame {
  _imageLayoutUpdateNeeded = YES;

  // We want to make sure that we are still scrolled to the same photo when the frame changes.
  // Measure the current content offset and scroll to the same fraction along the content after the
  // frame change.
  CGFloat scrollOffsetFraction = 0;
  if (self.contentSize.width != 0) {
    scrollOffsetFraction = self.contentOffset.x / self.contentSize.width;
  }
  [super setFrame:frame];
  [UIView performWithoutAnimation:^{
    [self updateContentSize];
    self.contentOffset =
        CGPointMake(scrollOffsetFraction * self.contentSize.width, -self.contentInset.top);
  }];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  if (_imageLayoutUpdateNeeded) {
    [self layoutImages];
    _imageLayoutUpdateNeeded = NO;

    // Re-adjust the content offset to ensure the photos are aligned properly horizontally.
    if (self.contentSize.width != 0) {
      CGFloat scrollOffset =
          (CGFloat)round((self.contentOffset.x / self.contentSize.width) * 10.0f) / 10.0f;
      self.contentOffset =
          CGPointMake(scrollOffset * self.contentSize.width, -self.contentInset.top);
    }
  }
}

#pragma mark - UITextViewDelegate

- (BOOL)textView:(UITextView *)textView
    shouldInteractWithURL:(NSURL *)url
                  inRange:(NSRange)characterRange {
  // Make links clickable.
  return YES;
}

#pragma mark - Helper methods

/**
 * Update the content size of the scroll view based on the number of photos and the view's width.
 * This should be called whenever the frame changes or the number of photos has changed.
 */
- (void)updateContentSize {
  CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, self.contentInset);
  CGFloat usableScrollViewHeight = insetBounds.size.height;

  self.contentSize =
      CGSizeMake(_photoImageViews.count * self.frame.size.width, usableScrollViewHeight);
}

/**
 * Updates the frames of the images and attributions.
 */
- (void)layoutImages {
  CGFloat contentWidth = 0;
  CGFloat scrollViewWidth = self.bounds.size.width;
  CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, self.contentInset);
  CGFloat usableScrollViewHeight = insetBounds.size.height;

  // Lay out the images one after the other horizontally.
  for (ImageViewAndAttribution *attributedImageView in _photoImageViews) {
    UITextView *attributionView = attributedImageView.attributionView;
    UIImageView *imageView = attributedImageView.imageView;
    [attributionView sizeToFit];
    CGFloat attributionHeight = attributionView.frame.size.height;
    CGFloat imageHeight = usableScrollViewHeight - attributionHeight;
    CGFloat safeAreaX = 0.0f;

#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
    // Take into account the safe areas of the device screen and do not use that space for the
    // attribution text.
    if (@available(iOS 11.0, *)) {
      imageHeight -= self.safeAreaInsets.bottom;
      safeAreaX = self.safeAreaInsets.left;
    }
#endif

    // Put the attribution view aligned to the same left edge as the photo, in the bottom left
    // corner of the screen.
    attributionView.frame = CGRectMake(contentWidth + safeAreaX, imageHeight,
                                       scrollViewWidth - (2 * safeAreaX), attributionHeight);
    imageView.frame = CGRectMake(contentWidth, 0, scrollViewWidth, imageHeight);
    contentWidth += imageView.frame.size.width;
  }
}

@end
