//
//  MINTLUserInterfaceValidationUpdate.swift
//  MenuTester
//
//  Created by narita on 2017/08/17.
//  Copyright © 2017年 narita. All rights reserved.
//

import Cocoa

// MINTLWindowやMINTLPanelのサブクラスを使用した場合に、このプロトコルに一致するオブジェクトは
// update()が呼ばれる時に、userInterfaceValidationUpdateが呼出される。
public protocol MINTLUserInterfaceValidationUpdate
{
    // NSView.updateSubvewsUserInterfaceValidation()経由でMINTLWindow/MINTLPanelのupdateメソッドから呼出されます。
    func userInterfaceValidationUpdate()
}

// MARK: - NSView (MINTLUserInterfaceValidationUpdate)

extension NSView: MINTLUserInterfaceValidationUpdate
{
    // subviews全てを走査して、userInterfaceValidationUpdateを呼出す。
    // MINTLWindow/MINTLPanelのupdateメソッドから呼ばれるので、通常は直接呼出す必要は有りません。
    func updateSubvewsUserInterfaceValidation()
    {
        self.userInterfaceValidationUpdate()
        
        for i in self.subviews
        {
            if i.isHiddenOrHasHiddenAncestor == false
            {
                i.updateSubvewsUserInterfaceValidation()
            }
        }
    }
    
    @objc public func userInterfaceValidationUpdate()
    {
        // デフォルトでは何もしない。NSControlやNSTabViewやNSBrowserViewなどのTarget/actionパラダイムに適合するクラスはここに動作内容をかく
    }
}

// MARK: - NSControl (MINTLUserInterfaceValidationUpdate)

// selfをキャストする。NSControlがプロトコルNSValidatedUserInterfaceItemに従っていないのは、AppKitのバグと思われる。
extension NSControl : NSValidatedUserInterfaceItem { }

extension NSControl
{
    @objc public override func userInterfaceValidationUpdate()
    {
        // actionが設定されているかをチェック。(target == nil)の場合はfirstResponderだから有効なのでtargetのnilチェックはしない。
        if( self.action != nil && self.window != nil && self.isHiddenOrHasHiddenAncestor == false )
        {
            var theResult:    Bool      = false
            var theValidator: NSObject? = nil
            
            theValidator = NSApp.target(forAction: self.action!, to: self.target, from: self) as! NSObject?
            
            if(
                    theValidator == nil
                ||
                    theValidator!.responds(to: self.action!) == false
                )
            {
                // actionを実行できるレスポンダーが無い場合は、ボタンは押せない
                theResult = false
            }
            else if let v = theValidator as? NSUserInterfaceValidations
            {
                // actionを実行できるレスポンダーが"validateUserInterfaceItem:"を実装しているならばそれに従う
                    theResult = v.validateUserInterfaceItem(self)
            }
            else
            {
                // レスポンダーがあるけど、"validateUserInterfaceItem"メソッドが無い場合は、無条件でボタンは押せる。
                theResult = true
            }
            
            // enabledにCocoaBindingが設定されている場合は、CocoaBindingの設定を優先させるために設定しない
            // ここにこの条件分岐があるのは、メソッドvalidateUserInterfaceItemの副作用が必要なため、その前に条件分岐して、
            // validateUserInterfaceItemが呼び出されない事を防ぐためです。
            if( self.infoForBinding(NSBindingName(rawValue: "enabled")) == nil )
            {
                self.isEnabled = theResult
            }
        }
    }
}
