// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

internal protocol NSSpecialValueCoding {
    static func objCType() -> String
    
    init(bytes value: UnsafeRawPointer)
    func encodeWithCoder(_ aCoder: NSCoder)
    init?(coder aDecoder: NSCoder)
    func getValue(_ value: UnsafeMutableRawPointer)
    
    // Ideally we would make NSSpecialValue a generic class and specialise it for
    // NSPoint, etc, but then we couldn't implement NSValue.init?(coder:) because 
    // it's not yet possible to specialise classes with a type determined at runtime.
    //
    // Nor can we make NSSpecialValueCoding conform to Equatable because it has associated
    // type requirements.
    //
    // So in order to implement equality and hash we have the hack below.
    func isEqual(_ value: Any) -> Bool
    var hash: Int { get }
    var description: String? { get }
}

internal class NSSpecialValue : NSValue {

    // Originally these were functions in NSSpecialValueCoding but it's probably
    // more convenient to keep it as a table here as nothing else really needs to
    // know about them
    private static let _specialTypes : Dictionary<Int, NSSpecialValueCoding.Type> = [
        1   : NSPoint.self,
        2   : NSSize.self,
        3   : NSRect.self,
        4   : NSRange.self,
        12  : NSEdgeInsets.self
    ]
    
    private static func _typeFromFlags(_ flags: Int) -> NSSpecialValueCoding.Type? {
        return _specialTypes[flags]
    }
    
    private static func _flagsFromType(_ type: NSSpecialValueCoding.Type) -> Int {
        for (F, T) in _specialTypes {
            if T == type {
                return F
            }
        }
        return 0
    }
    
    private static func _objCTypeFromType(_ type: NSSpecialValueCoding.Type) -> String? {
        for (_, T) in _specialTypes {
            if T == type {
                return T.objCType()
            }
        }
        return nil
    }
    
    internal static func _typeFromObjCType(_ type: UnsafePointer<Int8>) -> NSSpecialValueCoding.Type? {
        let objCType = String(cString: type)
        
        for (_, T) in _specialTypes {
            if T.objCType() == objCType {
                return T
            }
        }
        
        return nil
    }
    
    internal var _value : NSSpecialValueCoding
    
    init(_ value: NSSpecialValueCoding) {
        self._value = value
    }
    
    required init(bytes value: UnsafeRawPointer, objCType type: UnsafePointer<Int8>) {
        guard let specialType = NSSpecialValue._typeFromObjCType(type) else {
            NSUnimplemented()
        }
    
        self._value = specialType.init(bytes: value)
    }

    override func getValue(_ value: UnsafeMutableRawPointer) {
        self._value.getValue(value)
    }

    convenience required init?(coder aDecoder: NSCoder) {
        guard aDecoder.allowsKeyedCoding else {
            preconditionFailure("Unkeyed coding is unsupported.")
        }
        let specialFlags = aDecoder.decodeInteger(forKey: "NS.special")
        guard let specialType = NSSpecialValue._typeFromFlags(specialFlags) else {
            return nil
        }
        guard let specialValue = specialType.init(coder: aDecoder) else {
            return nil
        }
        self.init(specialValue)
    }
    
    override func encode(with aCoder: NSCoder) {
        guard aCoder.allowsKeyedCoding else {
            preconditionFailure("Unkeyed coding is unsupported.")
        }
        aCoder.encode(NSSpecialValue._flagsFromType(type(of: _value)), forKey: "NS.special")
        _value.encodeWithCoder(aCoder)
    }
    
    override var objCType : UnsafePointer<Int8> {
        let typeName = NSSpecialValue._objCTypeFromType(type(of: _value))
        return typeName!._bridgeToObjectiveC().utf8String! // leaky
    }
    
    override var classForCoder: AnyClass {
        // for some day when we support class clusters
        return NSValue.self
    }
    
    override var description : String {
        if let description = _value.description {
            return description
        } else {
            return super.description
        }
    }
    
    override func isEqual(_ value: Any?) -> Bool {
        if let object = value as? NSObject {
            if self === object {
                return true
            } else if let special = object as? NSSpecialValue {
                return _value.isEqual(special._value)
            }
        }
        return false
    }
    
    override var hash: Int {
        return _value.hash
    }
}
