//
//  CaretView.swift
//  MobileFirstFramework
//
//  Created by Christiano, Kevin on 1/5/18.
//  Copyright © 2018 Verizon Wireless. All rights reserved.
//


open class CaretView: View {
    //------------------------------------------------------
    // MARK: - Properties
    //------------------------------------------------------
    
    private var caretPath: UIBezierPath = UIBezierPath()
    public var lineWidth: CGFloat = 1
    
    public var direction: Direction = .right
    public var size: CaretSize?
    
    public var enabledColor: UIColor = .mvmBlack
    public var disabledColor: UIColor = .mvmCoolGray3
    
    //------------------------------------------------------
    // MARK: - Property Observer
    //------------------------------------------------------
    
    public var isEnabled: Bool = true {
        didSet {
            guard isEnabled != oldValue else { return }
            setNeedsDisplay()
        }
    }
    
    //------------------------------------------------------
    // MARK: - Constraints
    //------------------------------------------------------
    
    /// Sizes of CaretView are derived from InVision design specs. They are provided for convenience.
    public enum CaretSize {
        case small(Orientation)
        case medium(Orientation)
        case large(Orientation)
        
        /// Orientation based on the longest line of the view.
        public enum Orientation {
            case vertical
            case horizontal
        }
        
        /// Dimensions of container; provided by InVision design.
        func dimensions() -> CGSize {
            
            switch self {
            case .small(let o):
                return o == .vertical ? CGSize(width: 6, height: 10) : CGSize(width: 10, height: 6)
                
            case .medium(let o):
                return o == .vertical ? CGSize(width: 9, height: 16) : CGSize(width: 16, height: 9)
                
            case .large(let o):
                return o == .vertical ? CGSize(width: 14, height: 24) : CGSize(width: 24, height: 14)
            }
        }
    }
    
    //------------------------------------------------------
    // MARK: - Initialization
    //------------------------------------------------------
    
    @objc public override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    @objc public convenience init() {
        self.init(frame: .zero)
    }
    
    @objc public convenience init(lineWidth: CGFloat) {
        self.init(frame: .zero)
        self.lineWidth = lineWidth
    }
    
    @objc required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        fatalError("CaretView xib not supported.")
    }
    
    //------------------------------------------------------
    // MARK: - Setup
    //------------------------------------------------------
    
    @objc override open func setupView() {
        super.setupView()
        defaultState()
    }
    
    //------------------------------------------------------
    // MARK: - Drawing
    //------------------------------------------------------
    
    /// The direction the caret will be pointing to.
    @objc public enum Direction: Int {
        case left
        case right
        case down
        case up
    }
    
    @objc override open func draw(_ rect: CGRect) {
        super.draw(rect)
        
        caretPath.removeAllPoints()
        caretPath.lineJoinStyle = .miter
        caretPath.lineWidth = lineWidth
        
        let inset = lineWidth / 2
        let halfWidth = frame.size.width / 2
        let halfHeight = frame.size.height / 2
        
        switch direction {
        case .up:
            caretPath.move(to: CGPoint(x: inset, y: frame.size.height - inset))
            caretPath.addLine(to: CGPoint(x: halfWidth, y: inset))
            caretPath.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height))
            
        case .right:
            caretPath.move(to: CGPoint(x: inset, y: inset))
            caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: halfHeight))
            caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height - inset))
            
        case .down:
            caretPath.move(to: CGPoint(x: inset, y: inset))
            caretPath.addLine(to: CGPoint(x: halfWidth, y: frame.size.height - inset))
            caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: inset))
            
        case .left:
            caretPath.move(to: CGPoint(x: frame.size.width - inset, y: inset))
            caretPath.addLine(to: CGPoint(x: inset, y: halfHeight))
            caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height - inset))
        }
        
        _ = isEnabled ? enabledColor.setStroke() : disabledColor.setStroke()
        caretPath.stroke()
    }
    
    //------------------------------------------------------
    // MARK: - Methods
    //------------------------------------------------------
    
    @objc public func setLineColor(_ color: UIColor) {
        
        enabledColor = color
        setNeedsDisplay()
    }
    
    @objc public func defaultState() {
        
        isOpaque = false
        isHidden = false
        backgroundColor = .clear
        enabledColor = .mvmBlack
        disabledColor = .mvmCoolGray3
    }
    
    /// Ensure you have defined a CaretSize with Orientation before calling.
    @objc public func setConstraints() {
        
        guard let dimensions = size?.dimensions() else { return }
        
        heightAnchor.constraint(equalToConstant: dimensions.height).isActive = true
        widthAnchor.constraint(equalToConstant: dimensions.width).isActive = true
    }
    
    //------------------------------------------------------
    // MARK: - Atomization
    //------------------------------------------------------
    
    /// Default values for view.
    public required init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.init(frame: .zero)
        defaultState()
        set(with: model, delegateObject, additionalData)
    }
    
    override public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        
        guard let model = model as? CaretViewModel else { return }
        
        enabledColor = (model.inverted ? model.strokeColor_inverted : model.strokeColor).uiColor
        isHidden = model.isHidden
        isOpaque = model.isOpaque
        
        if let lineWidthValue = model.lineWidth {
            lineWidth = lineWidthValue
        }
    }
}

extension CaretView: MVMCoreUIViewConstrainingProtocol {
    
    open func needsToBeConstrained() -> Bool {
        return true
    }
    
    open func horizontalAlignment() -> UIStackView.Alignment {
        return .leading
    }
}
