//
//  MINTLEncodingPopUpButton.swift
//  ControlSikenjo
//
//  Created by narita on 2018/12/04.
//  Copyright © 2018 narita. All rights reserved.
//


import Cocoa

class MINTLEncodingPopUpButtonCell: NSPopUpButtonCell
{
    // MARK: - class methods
    
    static let NoStringEncoding:  UInt32 = 0xFFFFFFFF

    // MARK: - init methods
    
    public override init(textCell stringValue: String, pullsDown pullDown: Bool)
    {
        super.init(textCell: stringValue, pullsDown: pullDown)

        NotificationCenter.default
            .addObserver(
                self,
                selector: #selector(MINTLEncodingPopUpButtonCell.encodingsListChanged(_:)),
                name: MINTLEncodingManager.EncodingsListChanged,
                object: nil)
        
        setupMenu(selectedMenu: String.Encoding(rawValue:
            UInt(MINTLEncodingPopUpButtonCell.NoStringEncoding)))
    }
    
    // MARK: - dealloc
    
    // MARK: - NSCopying, hash, isEqual:
    
    // MARK: - NSCoding methods

    required init(coder: NSCoder)
    {
        super.init(coder: coder)
        
        NotificationCenter.default
            .addObserver(
                self,
                selector: #selector(MINTLEncodingPopUpButtonCell.encodingsListChanged(_:)),
                name: MINTLEncodingManager.EncodingsListChanged,
                object: nil)

        setupMenu(selectedMenu: String.Encoding(rawValue:
            UInt(MINTLEncodingPopUpButtonCell.NoStringEncoding)))
    }
    
    // MARK: - restorableState methods
    
    // MARK: - life cycle methods
    
    // MARK: - action methods

    @objc override func selectItem(at index: Int)
    {
        if ( index + 2 <= self.numberOfItems )
        {
            super.selectItem(at: index)
        }
    }
    
    @objc func encodingsListChanged(_ notification: Notification?)
    {
        if let theNumber = self.selectedItem?.representedObject as? NSNumber
        {
            setupMenu(selectedMenu: String.Encoding(rawValue: theNumber.uintValue))
        }
        else
        {
            setupMenu(selectedMenu: String.Encoding(rawValue: UInt(MINTLEncodingPopUpButtonCell.NoStringEncoding)))
        }
    }

    // MARK: - event handling methods
    
    // MARK: - drawing methods
    
    // MARK: - delegate/datasource methods
    
    // MARK: - accessor methods (in pairs)
    
    @IBInspectable var wantsAutomatic: Bool = false
    {
        didSet(newValue)
        {
            if let theNumber = self.selectedItem?.representedObject as? NSNumber
            {
                setupMenu(selectedMenu: String.Encoding(rawValue: theNumber.uintValue))
            }
        }
    }
    
    // MARK: - Utility methods
    
    func setupMenu(selectedMenu: String.Encoding)
    {
        let theEncMgr = MINTLEncodingManager.sharedInstance()!
        let theEncodings = theEncMgr.enabledEncodings?.mutableCopy() as? NSMutableArray
        
        self.removeAllItems()
        
        if wantsAutomatic
        {
            self.addItem(withTitle: "Automatic")
            self.item(at: 0)?.representedObject = NSNumber(value: MINTLEncodingPopUpButtonCell.NoStringEncoding)
        }
        
        // Panelの方でenableをoffにして除外したエンコーディングを選んでいる場合は、末尾に追加して救済する
        if (
                !wantsAutomatic
            &&
                (UInt32(selectedMenu.rawValue) != MINTLEncodingPopUpButtonCell.NoStringEncoding)
            &&
                !theEncMgr.enabledEncodingsContain(encoding: selectedMenu)
            )
        {
            if let theItem = theEncMgr.findEncodingItemFrom(encoding: selectedMenu)
            {
                theEncodings!.add(theItem)
            }
        }

        var itemToSelect: NSInteger = 0
        
        theEncodings?.forEach()
        {
            if let i = $0 as? MINTLTextEncodingItem
            {
                self.addItem(withTitle: i.encodingName)
                self.lastItem?.representedObject = i.encodingNumber
                self.lastItem?.isEnabled = true
                
                if i.encoding == selectedMenu
                {
                    itemToSelect = self.numberOfItems - 1
                }
            }
        }
        
        if self.numberOfItems > 0
        {
            self.menu?.addItem(NSMenuItem.separator())
        }
        
        self.addItem(withTitle: "Customize Encodings List…")
        self.lastItem?.action = #selector(MINTLEncodingManager.showEncodingPanel)
        self.lastItem?.target = MINTLEncodingManager.sharedInstance()
        
        self.selectItem(at: itemToSelect)        
    }
}



class MINTLEncodingPopUpButton: NSPopUpButton
{
    // MARK: - class methods
    
    class func cellClass() -> AnyClass?
    {
        return MINTLEncodingPopUpButtonCell.self
    }

    // MARK: - init methods
    
    override init(frame frameRect: NSRect)
    {
        super.init(frame: frameRect)
    }
    
    // MARK: - dealloc
    
    // MARK: - NSCopying, hash, isEqual:
    
    // MARK: - NSCoding methods
    
    required init?(coder: NSCoder)
    {
        super.init(coder: coder)
        
        if     ( self.cell == nil )
            ||
               ( self.cell!.className != MINTLEncodingPopUpButtonCell.className() )
        {
            self.cell = MINTLEncodingPopUpButtonCell(textCell: "", pullsDown: false)
        }
    }
    
    // MARK: - restorableState methods
    
    // MARK: - life cycle methods
    
    // MARK: - action methods
    
    // MARK: - event handling methods
    
    override func bind(_ binding: NSBindingName,
                       to observable: Any,
                       withKeyPath keyPath: String,
                       options: [NSBindingOption : Any]? = nil)
    {
        super.bind(binding, to: observable, withKeyPath: keyPath, options: options)
        
        // binding時にmodelオブジェクトの値をメニューリストに反映させるために、ここでメニューを再構築する。
        if binding.rawValue == "selectedObject"
        {
            if
                let theCell = self.cell as? MINTLEncodingPopUpButtonCell,
                let theObject = observable as? NSObject,
                let theNumber = theObject.value(forKeyPath: keyPath) as? NSNumber
            {
                theCell.setupMenu(selectedMenu: String.Encoding(rawValue: theNumber.uintValue))
            }
        }
    }
    
    // MARK: - drawing methods

    // MARK: - delegate/datasource methods
    
    // MARK: - accessor methods (in pairs)
    
    @IBInspectable var wantsAutomatic: Bool
    {
        set(newValue)
        {
            if let theCell = self.cell as? MINTLEncodingPopUpButtonCell
            {
                theCell.wantsAutomatic = newValue
            }
        }
        
        get
        {
            if let theCell = self.cell as? MINTLEncodingPopUpButtonCell
            {
                return theCell.wantsAutomatic
            }
            
            return false
        }
    }

    // MARK: - Utility methods
}
