//
//  PlaceableComponent+extensions.swift
//  
//  Copyright © 2016-2019 Apple Inc. All rights reserved.
//

import UIKit
import PlaygroundSupport
import SPCCore

extension PlaceableComponent {
    
    public static func createComponent(type: String, identity: ComponentIdentity) -> PlaceableComponent? {
        PBLog("\(identity.name) -> \(type)")
        switch type {
        case ActivityButton.componentType:
            return ActivityButton(identity: identity)
        case Button.componentType:
            return Button(identity: identity)
        case Label.componentType:
            return Label(identity: identity)
        case CameraView.componentType:
            return CameraView(identity: identity)
        case ImageView.componentType:
            return ImageView(identity: identity)
        case PhotoAlbumView.componentType:
            return PhotoAlbumView(identity: identity)
        case PhotoCollectionView.componentType:
            return PhotoCollectionView(identity: identity)
        case Slider.componentType:
            return Slider(identity: identity)
        case Space.componentType:
            return Space(identity: identity)
        default:
            PBLog("type not found: \(type)")
            return nil
        }
    }
    
    static func createComponent(type: String, name: String) -> PlaceableComponent? {
        PBLog("\(name) -> \(type)")
        switch type {
        case ActivityButton.componentType:
            return ActivityButton(name: name)
        case Button.componentType:
            return Button(name: name)
        case Label.componentType:
            return Label(name: name)
        case CameraView.componentType:
            return CameraView(name: name)
        case ImageView.componentType:
            return ImageView(name: name)
        case PhotoAlbumView.componentType:
            return PhotoAlbumView(name: name)
        case PhotoCollectionView.componentType:
            return PhotoCollectionView(name: name)
        case Slider.componentType:
            return Slider(name: name)
        case Space.componentType:
            return Space(name: name)
        default:
            PBLog("type not found: \(type)")
            return nil
        }
    }
}

extension PlaceableComponent: PlaygroundValueTransformable {
    
    public var playgroundValue: PlaygroundValue? {
        let componentDict = dictForPlaceableComponent(component: self)
        return PlaygroundValueDictionary(dictionary: componentDict).playgroundValue
    }
    
    private func dictForPlaceableComponent(component: PlaceableComponent) -> [String : PlaygroundValue] {
        var dict = [String : PlaygroundValue]()
        dict["type"] = type(of: component).componentType.playgroundValue
        dict["name"] = component.name.playgroundValue
        dict["id"] = component.identity.identifier.playgroundValue
        dict["position"] = component.position.playgroundValue
        dict["size"] = component.size.playgroundValue
        if let containerSpace = component as? ContainerSpace {
            var childComponentDicts = [PlaygroundValue]()
            for placeableComponent in containerSpace.liveSubcomponents {
                let childComponentDict = dictForPlaceableComponent(component: placeableComponent)
                if let childComponentPlaygroundValue = PlaygroundValueDictionary(dictionary: childComponentDict).playgroundValue {
                    childComponentDicts.append(childComponentPlaygroundValue)
                }
            }
            if !childComponentDicts.isEmpty {
                dict["childComponents"] = PlaygroundValueArray(array: childComponentDicts).playgroundValue
            }
        }
        return dict
    }
    
    public static func from(_ playgroundValue: PlaygroundValue) -> PlaygroundValueTransformable? {
        guard case .dictionary(let dict) = playgroundValue else { return nil }
        return placeableComponentFor(dict: dict)
    }
    
    private static func placeableComponentFor(dict: [String : PlaygroundValue]) -> PlaceableComponent? {
        guard let typePlaygroundValue = dict["type"],
            let namePlaygroundValue = dict["name"],
            let idPlaygroundValue = dict["id"],
            let type = String.from(typePlaygroundValue) as? String,
            let name = String.from(namePlaygroundValue) as? String,
            let id = String.from(idPlaygroundValue) as? String
            else { return nil }
        
        let identity = ComponentIdentity(name: name, identifier: id)
        guard let placeableComponent = PlaceableComponent.createComponent(type: type, identity: identity) else { return nil }
        
        if let playGroundValue = dict["position"], let value = Point.from(playGroundValue) as? Point {
            placeableComponent.position = value
        }
        if let playGroundValue = dict["size"], let value = Size.from(playGroundValue) as? Size {
            placeableComponent.size = value
        }

        guard
            let hasSpaceToPlaceComponent = placeableComponent as? ContainerSpace,
            let childComponentsPlaygroundValue = dict["childComponents"]
            else { return placeableComponent }
        
        if case .array(let childComponentPlaygroundValueDicts) = childComponentsPlaygroundValue {
            for childComponentPlaygroundValueDict in childComponentPlaygroundValueDicts {
                guard case .dictionary(let childComponentDict) = childComponentPlaygroundValueDict else { continue }
                
                if let childPlaceableComponent = placeableComponentFor(dict: childComponentDict) {
                    if let spaceComponent = hasSpaceToPlaceComponent as? Space {
                        spaceComponent.add(childPlaceableComponent, at: childPlaceableComponent.position, size: childPlaceableComponent.size)
                    }
                }
            }
        }
        return placeableComponent
    }
}

