//
//  UIButton+ext.swift
//  PQSpeed
//
//  Created by ak on 2020/8/14.
//  Copyright © 2020 BytesFlow. All rights reserved.
//
/**
 UIButton图像文字同时存在时---图像相对于文字的位置

 - top:    图像在上
 - left:   图像在左
 - right:  图像在右
 - bottom: 图像在下
 */
public enum PQButtonImageEdgeInsetsStyle {
    case top, left, right, bottom
}

import Foundation
extension UIButton {
    public func imagePosition(at style: PQButtonImageEdgeInsetsStyle, space: CGFloat) {
        guard let imageV = imageView else { return }
        guard let titleL = titleLabel else { return }
        // 获取图像的宽和高
        let imageWidth = imageV.frame.size.width
        let imageHeight = imageV.frame.size.height
        // 获取文字的宽和高
        let labelWidth = titleL.frame.size.width
        let labelHeight = titleL.frame.size.height

        var imageEdgeInsets = UIEdgeInsets.zero
        var labelEdgeInsets = UIEdgeInsets.zero
        // UIButton同时有图像和文字的正常状态---左图像右文字，间距为0
        switch style {
        case .left:
            // 正常状态--只不过加了个间距
            imageEdgeInsets = UIEdgeInsets(top: 0, left: -space * 0.5, bottom: 0, right: space * 0.5)
            labelEdgeInsets = UIEdgeInsets(top: 0, left: space * 0.5, bottom: 0, right: -space * 0.5)
        case .right:
            // 切换位置--左文字右图像
            // 图像：UIEdgeInsets的left是相对于UIButton的左边移动了labelWidth + space * 0.5，right相对于label的左边移动了-labelWidth - space * 0.5
            imageEdgeInsets = UIEdgeInsets(top: 0, left: labelWidth + space * 0.5, bottom: 0, right: -labelWidth - space * 0.5)
            labelEdgeInsets = UIEdgeInsets(top: 0, left: -imageWidth - space * 0.5, bottom: 0, right: imageWidth + space * 0.5)
        case .top:
            // 切换位置--上图像下文字
            /** 图像的中心位置向右移动了labelWidth * 0.5，向上移动了-imageHeight * 0.5 - space * 0.5
              *文字的中心位置向左移动了imageWidth * 0.5，向下移动了labelHeight*0.5+space*0.5
             */
            imageEdgeInsets = UIEdgeInsets(top: -(imageHeight * 0.5 - space), left: labelWidth * 0.5, bottom: imageHeight * 0.5 - space, right: -labelWidth * 0.5)
            labelEdgeInsets = UIEdgeInsets(top: labelHeight * 0.5 + space * 2, left: -imageWidth * 0.5, bottom: -(labelHeight * 0.5 + space * 2), right: imageWidth * 0.5)
        case .bottom:
            // 切换位置--下图像上文字
            /** 图像的中心位置向右移动了labelWidth * 0.5，向下移动了imageHeight * 0.5 + space * 0.5
             *文字的中心位置向左移动了imageWidth * 0.5，向上移动了labelHeight*0.5+space*0.5
             */
            imageEdgeInsets = UIEdgeInsets(top: imageHeight * 0.5 + space * 0.5, left: labelWidth * 0.5, bottom: -imageHeight * 0.5 - space * 0.5, right: -labelWidth * 0.5)
            labelEdgeInsets = UIEdgeInsets(top: -labelHeight * 0.5 - space * 0.5, left: -imageWidth * 0.5, bottom: labelHeight * 0.5 + space * 0.5, right: imageWidth * 0.5)
        }
        titleEdgeInsets = labelEdgeInsets
        self.imageEdgeInsets = imageEdgeInsets
    }
}

/*
   e.g.
 let button = UIButton(frame: CGRect(x: 0, y: 300, width: 100, height: 22))
 button.setTitle("按钮", for: .normal)
 button.setTitleColor(.black, for: .normal)
 button.eventInterval = 2.0  //  按的时间间隔, 设置为0的时候就是可以反复点击
 view.addSubview(button)
 
 */
// MARK: - 按钮的反复点击问题 交换方法
extension UIButton {

    /// 对外交换方法的方法 AppDelegate Launch中使用
    public  static func methodExchange() {
        DispatchQueue.once(token: "UIButton") {
            let originalSelector = Selector.sysFunc
            let swizzledSelector = Selector.myFunc
            changeMethod(originalSelector, swizzledSelector, self)
        }
    }
    
    
    /// Runtime方法交换
    ///
    /// - Parameters:
    ///   - original: 原方法
    ///   - swizzled: 交换方法
    ///   - object: 对象
    public static func changeMethod(_ original: Selector, _ swizzled: Selector, _ object: AnyClass) -> () {
        
        guard let originalMethod = class_getInstanceMethod(object, original),
              let swizzledMethod = class_getInstanceMethod(object, swizzled) else {
            return
        }
        
        let didAddMethod = class_addMethod(object, original, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
        if didAddMethod {
            class_replaceMethod(object, swizzled, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
    
    
    /// 结构体静态key
    public struct UIButtonKey {
        static var isEventUnavailableKey = "isEventUnavailableKey"
        static var eventIntervalKey = "eventIntervalKey"
    }
    
    /// 触发事件的间隔
    public var eventInterval: TimeInterval {
        get {
            return (objc_getAssociatedObject(self, &UIButtonKey.eventIntervalKey) as? TimeInterval) ?? 0
        }
        set {
            objc_setAssociatedObject(self, &UIButtonKey.eventIntervalKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    /// 是否可以触发事件
    fileprivate var isEventUnavailable: Bool {
        get {
            return (objc_getAssociatedObject(self, &UIButtonKey.isEventUnavailableKey) as? Bool) ?? false
        }
        set {
            objc_setAssociatedObject(self, &UIButtonKey.isEventUnavailableKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    /// 手写的set方法
    ///
    /// - Parameter isEventUnavailable: 事件是否可用
    @objc private func setIsEventUnavailable(_ isEventUnavailable: Bool) {
        self.isEventUnavailable = isEventUnavailable
    }
    
    /// mySendAction
    @objc fileprivate func mySendAction(_ action: Selector, to target: Any?, for event: UIEvent?) {
        print("交换了按钮事件的方法")
        
        if isEventUnavailable == false {
            isEventUnavailable = true
            mySendAction(action, to: target, for: event)
            perform(#selector(setIsEventUnavailable(_: )), with: false, afterDelay: eventInterval)
        }
    }
}

fileprivate extension Selector {
    static let sysFunc = #selector(UIButton.sendAction(_:to:for:))
    static let myFunc = #selector(UIButton.mySendAction(_:to:for:))
}

extension DispatchQueue {
    private static var onceTracker = [String]()
    
    open class func once(token: String, block:() -> ()) {
        //注意defer作用域，调用顺序——即一个作用域结束，该作用域中的defer语句自下而上调用。
        objc_sync_enter(self)
        defer {
            print("线程锁退出")
            objc_sync_exit(self)
        }
        
        if onceTracker.contains(token) {
            return
        }
        onceTracker.append(token)
        block()
        defer {
            print("block执行完毕")
        }
    }
}
