//
//  MINTLResponderProxy.swift
//  DateBook
//
//  Created by narita on 2017/09/07.
//  Copyright © 2017年 narita. All rights reserved.
//

import Cocoa

// シンプルだが強力なアイデア。異なるnibファイルののobjectにactionを投げる事が出来る。ダクトテープ系クラス
class MINTLResponderProxy: NSObject
{
    // MARK: - class methods
    
    // MARK: - init methods
    
    // MARK: - dealloc
    
    // MARK: - NSCopying, hash, isEqual:
    
    // MARK: - NSCoding methods
    
    // MARK: - restorableState methods
    
    // MARK: - life cycle methods
    
    @objc override func awakeFromNib()
    {
        // nibの読み込みが完了したフラグを立てる
        // 最初のイベントループが回った時に立てる
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.0)
        {
            self.didFinishNibLoading()
        }
    }
    
    // MARK: - action methods
    
    // MARK: - event handling methods
    
    // MARK: - drawing methods
    
    // MARK: - delegate/datasource methods
    
    // MARK: - accessor methods (in pairs)
    
    // そのポインター値は、objectRootを起点として、キーパスobjectPathで示されるオブジェクトのポインター
    @IBOutlet      var rootObject:        NSObject? = nil
    @IBInspectable var pathString:        String?   = nil

    @IBInspectable var useResponderChain: Bool    = false
    @IBInspectable var isLoadedFromNib:   Bool    = false
    
    // MARK: - Utility methods

    @objc func resolvedRootObject(with selector: Selector?) -> NSObject?
    {
        var theResult: NSObject? = nil
        
        if self.isLoadedFromNib
        {
            if self.rootObject != nil
            {
                theResult = self.rootObject;
                
                if self.pathString != nil && self.pathString!.isEmpty == false
                {
                    theResult = self.rootObject?.value(forKey: self.pathString!) as! NSObject?
                }
            }
            else
            {
                // nilの場合は、エラーにすべき？
            }
            
            if self.useResponderChain && selector != nil && theResult != nil && theResult is NSResponder
            {
                if let theResponder = theResult as! NSResponder?
                {
                    theResult = theResponder.findRespondableObject(theResult!, withAction: selector!)
                }
            }
        }
        
        return theResult
    }
    
    @objc override func value(forKey key: String) -> Any?
    {
        return self.resolvedRootObject(with: nil)?.value(forKey:key)
    }
    
    @objc func didFinishNibLoading()
    {
        self.isLoadedFromNib = true
    }

    @objc override func responds(to aSelector: Selector!) -> Bool
    {
        if self.isLoadedFromNib
        {
            // nibの読み込み完了後

            if self.rootObject != nil
            {
                let theObject = self.resolvedRootObject(with: aSelector)
                
                if theObject != nil
                {
                    return theObject!.responds(to: aSelector)
                }
                else
                {
                    print("self.resolvedRootObject == null \(self)")
                }
            }
            else
            {
                print("rootObject == null \(self)")
            }
            
            return false
        }
        else
        {
            // nib読み込み中の動作

            // 明示的に許可
            if
                    aSelector == #selector(setter: MINTLResponderProxy.rootObject)
                ||
                    aSelector == #selector(setter: MINTLResponderProxy.pathString)
                ||
                    aSelector == #selector(NSObject.awakeFromNib)
            {
                return true
            }

            // 明示的に拒否
            if
                    aSelector == #selector(NSToolbarItemValidation.validateToolbarItem(_:))
                ||
                    aSelector == #selector(NSUserInterfaceValidations.validateUserInterfaceItem(_:))
            {
                return false
            }

            return true
        }
    }
    
    
    
    @objc func _finishedMakingConnections()
    {
        // 何もしない。
    }

    @objc func nibInstantiateWithObjectInstantiator(_ sender:AnyObject?) -> AnyObject?
    {
        return self;
    }

    // ToDo: first responderのようにチェインをたぐるモードも実装すべき
    
    // これだけで良い、methodSignatureForSelectorもforwardInvocationも不要のはず
    @objc override func forwardingTarget(for aSelector: Selector!) -> Any?
    {
        return self.resolvedRootObject(with:aSelector)
    }
}
