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

import UIKit
import SPCCore
import PlaygroundSupport

/// An image view is a component that displays an image.
///
/// You can provide the image in two ways:
/// * Set the image view’s `image` property.
/// * Connect its input (`input`) to an output of type `Output<Image>` on another component.
///
/// By default the image is scaled to fit within the image view, but keeping the ratio between width and height (`contentMode` is `.scaleAspectFit`). There are other `contentMode` options such as `.scaleToFill`.
///
/// - localizationKey: ImageView
public class ImageView: PlaceableComponent {
    public override class var componentType: String { return String(describing: ImageView.self) }
    
    public override var liveComponent: LiveComponent? {
        return liveImageView
    }
    
    private var liveImageView: LiveImageView?
    
    fileprivate enum EventName: ComponentEventName {
        case imageChanged
    }
    
    // MARK: Properties

    /// The image to be displayed in the image view.
    ///
    /// - localizationKey: ImageView.image
    public var image: Image {
        get {
            guard let image = liveImageView?.image else { return _image }
            return image
        }
        set {
            _image = newValue
            liveImageView?.image = newValue
            
            updateLiveComponent(.imageChanged, value: newValue.playgroundValue)
        }
    }
    private var _image = Image()

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

    // MARK: Inputs

    /// An input that accepts event notifications of type `Image`. When the input receives an event, the image view displays the new image.
    ///
    /// You can connect an output of type `Output<Image>` to this input.
    ///
    /// - localizationKey: ImageView.input
    public private(set) lazy var input = Input<Image>({ [weak self] image in
        self?.image = image
    })
    
    // MARK: Initialization
    override func initialize() {
        super.initialize()
        contentMode = .scaleAspectFit
    }
    
    override func createLiveComponent() {
        liveImageView = LiveImageView(component: self)
    }
    
    // MARK: Messaging
    private func updateLiveComponent(_ eventName: ImageView.EventName, 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)
        if event.name == EventName.imageChanged.rawValue {
            guard let newImage = UIImage.from(event.value) as? UIImage else { return }
            liveImageView?.image = newImage
        }
    }
}

class LiveImageView: UIImageView, LiveComponent {
    weak var component: Component?
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    required init(component: Component) {
        self.component = component
        super.init(frame: CGRect.zero)
        clipsToBounds = true
        isAccessibilityElement = true
        setAccessibilityInfo()
    }
}
