//
//  PhotoAlbumView.swift
//  
//  Copyright © 2016-2019 Apple Inc. All rights reserved.
//

import UIKit
import PlaygroundSupport
import SPCCore

/// A photo album view is a component that presents a scrolling display of the photos in a **Photos** album.
/// It displays the title of the album and, depending on the view’s aspect ratio, the photos scroll horizontally or vertically.
///
/// You give it a photo album to display by setting its `photoAlbum` property.
///
/// Since `PhotoAlbum` is a `PhotoCollectionView`, you can add images to the photo album by:
/// * Calling its `addImage(image:)` method.
/// * Connecting its `imageInput` input to an output of type `Output<Image>`.
///
/// Outputs `itemSelected` and `imageSelected` allow you to respond when someone touches a photo.
///
/// - localizationKey: PhotoAlbumView
public class PhotoAlbumView: PhotoCollectionView {
    public override class var componentType: String { return String(describing: PhotoAlbumView.self) }
    
    public override var liveComponent: LiveComponent? {
        return super.livePhotoCollectionView
    }
    
    var liveAlbumView: LivePhotoAlbumView? {
        return liveComponent as? LivePhotoAlbumView
    }
    
    fileprivate enum PhotoAlbumViewEventName: ComponentEventName {
        case captionChanged
        case captionStyleChanged
    }
    
    // MARK: Properties

    /// The photo album to be displayed.
    ///
    /// - localizationKey: PhotoAlbumView.album
    public var album = PhotoAlbum() {
        didSet {
            photoCollection = album
            caption = photoCollection.name
        }
    }
    
    
    
    /// The caption to display underneath — or beside — the photo collection.
    /// This defaults to the album name, but can be changed.
    ///
    /// - localizationKey: PhotoAlbumView.caption
    public var caption: String {
        get {
            guard let caption = liveAlbumView?.caption else { return _caption }
            return caption
        }
        set {
            _caption = newValue
            liveAlbumView?.caption = newValue
            if Process.isUser {
                updateLiveComponent(.captionChanged, value: newValue.playgroundValue)
            }
        }
    }
    private var _caption = String()

    /// The style to be used for the caption. Use this property to set the font, size, color and alignment of the text.
    ///
    /// Example usage:
    /// ````
    /// photoAlbum.captionStyle = TextStyle(.Copperplate, fontSize: 48, color: .orange, alignment: .center)
    /// ````
    /// - localizationKey: PhotoAlbumView.captionStyle
    public var captionStyle: TextStyle {
        get {
            guard let captionStyle = liveAlbumView?.captionStyle else { return _captionStyle }
            return captionStyle
        }
        set {
            _captionStyle = newValue
            liveAlbumView?.captionStyle = newValue
            if Process.isUser {
                updateLiveComponent(.captionStyleChanged, value: newValue.playgroundValue)
            }
        }
    }
    private var _captionStyle = TextStyle(.HelveticaNeue)

    // SpacePlaceable
    
    /// The default size of the photo album view if its size is not set: 480 in width by 120 in height.
    ///
    /// - localizationKey: PhotoAlbumView.intrinsicSize
    public override var intrinsicSize: Size { return Size(width: 480, height: 120) }

    // MARK: Initialization
    override func createLiveComponent() {
        super.livePhotoCollectionView = LivePhotoAlbumView(component: self)
    }
    
    // MARK: Messaging
    private func updateLiveComponent(_ eventName: PhotoAlbumViewEventName, value: PlaygroundValue?) {
        guard let playgroundValue = value else { return }
        let event = ComponentEvent(name: eventName.rawValue, value: playgroundValue)
        event.send(to: self, in: .live)
    }
    
    public override func receive(_ event: ComponentEvent, from origin: ComponentMessageOrigin) {
        super.receive(event, from: origin)
        guard let eventName = PhotoAlbumViewEventName(rawValue: event.name) else { return }
        switch eventName {
        case .captionChanged:
            guard case .string(let newValue) = event.value else { return }
            _caption = newValue
            liveAlbumView?.caption = newValue
        case .captionStyleChanged:
            guard let newValue = TextStyle.from(event.value) as? TextStyle else { return }
            _captionStyle = newValue
            liveAlbumView?.captionStyle = newValue
        }
    }
}

class LivePhotoAlbumView: LivePhotoCollectionView {
    private let label = UILabel()
    
    var caption: String? {
        get { return label.text }
        set {
            label.text = newValue
            if let caption = caption, !caption.isEmpty {
                accessibilityValue = String(format: NSLocalizedString("with album: %@", tableName: "SPCComponents", comment: "Photo album view with album loaded."), caption)
            } else {
                accessibilityValue = nil
            }
            setNeedsLayout()
        }
    }
    
    var captionStyle: TextStyle? {
        get {
            guard
                let fontName = FontName(rawValue: label.font.familyName),
                let textAlignment = TextAlignment(rawValue: label.textAlignment.rawValue)
                else { return nil }
            return TextStyle(fontName, fontSize: Double(label.font.pointSize), color: label.textColor, alignment: textAlignment)
        }
        set {
            guard let captionStyle = newValue else { return }
            label.font = captionStyle.font
            label.textColor = captionStyle.color
            label.textAlignment = captionStyle.alignment
            setNeedsLayout()
        }
    }

    required init(component: Component) {
        super.init(component: component)
        
        addSubview(label)
        captionStyle = TextStyle(.SystemFontRegular, fontSize: 14, color: #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1), alignment: .center)
        clipsToBounds = true
        
        backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.8470588235, blue: 0.5215686275, alpha: 1)
        selectedBorderColor = #colorLiteral(red: 1, green: 0.4863265157, blue: 0, alpha: 1)
        layer.cornerRadius = 20.0
                
        label.isAccessibilityElement = false
        setAccessibilityInfo()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        label.sizeToFit()
        let borderInsets = UIEdgeInsets(top: layer.borderWidth, left: layer.borderWidth, bottom: layer.borderWidth, right: layer.borderWidth)
        let availableBounds = bounds.inset(by: borderInsets)
        let labelHeight = max(label.bounds.height * 1.3, photoCellInsets.top)
        var insets = photoCellInsets
        if availableBounds.size.width >= availableBounds.size.height {
            label.transform = CGAffineTransform(rotationAngle: 0)
            label.isHidden = labelHeight >= availableBounds.size.height
            insets.bottom = labelHeight
            label.frame = CGRect(x: borderInsets.left, y: bounds.size.height - labelHeight - borderInsets.bottom, width: availableBounds.size.width, height: labelHeight)
        } else {
            label.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 2)
            label.isHidden = labelHeight >= availableBounds.size.width
            insets.right = labelHeight
            label.frame = CGRect(x: bounds.size.width - labelHeight - borderInsets.right, y: borderInsets.top, width: labelHeight, height: availableBounds.size.height)
        }
        
        photoCellInsets = insets

        super.layoutSubviews()
    }
}

