// 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
//


import CoreFoundation

internal final class _NSCFArray : NSMutableArray {
    deinit {
        _CFDeinit(self)
        _CFZeroUnsafeIvars(&_storage)
    }
    
    required init(coder: NSCoder) {
        fatalError()
    }
    
    required init(objects: UnsafePointer<AnyObject>!, count cnt: Int) {
        fatalError()
    }
    
    required public convenience init(arrayLiteral elements: Any...) {
        fatalError()
    }
    
    override var count: Int {
        return CFArrayGetCount(_cfObject)
    }
    
    override func object(at index: Int) -> Any {
        let value = CFArrayGetValueAtIndex(_cfObject, index)
        return _SwiftValue.fetch(unsafeBitCast(value, to: AnyObject.self))
    }
    
    override func insert(_ value: Any, at index: Int) {
        let anObject = _SwiftValue.store(value)
        CFArrayInsertValueAtIndex(_cfMutableObject, index, unsafeBitCast(anObject, to: UnsafeRawPointer.self))
    }
    
    override func removeObject(at index: Int) {
        CFArrayRemoveValueAtIndex(_cfMutableObject, index)
    }
    
    override var classForCoder: AnyClass {
        return NSMutableArray.self
    }
}

internal func _CFSwiftArrayGetCount(_ array: AnyObject) -> CFIndex {
    return (array as! NSArray).count
}

internal func _CFSwiftArrayGetValueAtIndex(_ array: AnyObject, _ index: CFIndex) -> Unmanaged<AnyObject> {
    let arr = array as! NSArray
    if type(of: array) === NSArray.self || type(of: array) === NSMutableArray.self {
        return Unmanaged.passUnretained(arr._storage[index])
    } else {
        let value = _SwiftValue.store(arr.object(at: index))
        let container: NSMutableDictionary
        if arr._storage.count == 0 {
            container = NSMutableDictionary()
            arr._storage.append(container)
        } else {
            container = arr._storage[0] as! NSMutableDictionary
        }
        container[NSNumber(value: index)] = value
        return Unmanaged.passUnretained(value)
    }
}

internal func _CFSwiftArrayGetValues(_ array: AnyObject, _ range: CFRange, _ values: UnsafeMutablePointer<Unmanaged<AnyObject>?>) {
    let arr = array as! NSArray
    if type(of: array) === NSArray.self || type(of: array) === NSMutableArray.self {
        for idx in 0..<range.length {
            values[idx] = Unmanaged.passUnretained(arr._storage[idx + range.location])
        }
    } else {
        for idx in 0..<range.length {
            let index = idx + range.location
            let value = _SwiftValue.store(arr.object(at: index))
            let container: NSMutableDictionary
            if arr._storage.count == 0 {
                container = NSMutableDictionary()
                arr._storage.append(container)
            } else {
                container = arr._storage[0] as! NSMutableDictionary
            }
            container[NSNumber(value: index)] = value
            values[idx] = Unmanaged.passUnretained(value)
        }
    }
}

internal func _CFSwiftArrayAppendValue(_ array: AnyObject, _ value: AnyObject) {
    (array as! NSMutableArray).add(value)
}

internal func _CFSwiftArraySetValueAtIndex(_ array: AnyObject, _ value: AnyObject, _ idx: CFIndex) {
    (array as! NSMutableArray).replaceObject(at: idx, with: value)
}

internal func _CFSwiftArrayReplaceValueAtIndex(_ array: AnyObject, _ idx: CFIndex, _ value: AnyObject) {
    (array as! NSMutableArray).replaceObject(at: idx, with: value)
}

internal func _CFSwiftArrayInsertValueAtIndex(_ array: AnyObject, _ idx: CFIndex, _ value: AnyObject) {
    (array as! NSMutableArray).insert(value, at: idx)
}

internal func _CFSwiftArrayExchangeValuesAtIndices(_ array: AnyObject, _ idx1: CFIndex, _ idx2: CFIndex) {
    (array as! NSMutableArray).exchangeObject(at: idx1, withObjectAt: idx2)
}

internal func _CFSwiftArrayRemoveValueAtIndex(_ array: AnyObject, _ idx: CFIndex) {
    (array as! NSMutableArray).removeObject(at: idx)
}

internal func _CFSwiftArrayRemoveAllValues(_ array: AnyObject) {
    (array as! NSMutableArray).removeAllObjects()
}

internal func _CFSwiftArrayReplaceValues(_ array: AnyObject, _ range: CFRange, _ newValues: UnsafeMutablePointer<Unmanaged<AnyObject>>, _ newCount: CFIndex) {
    NSUnimplemented()
//    (array as! NSMutableArray).replaceObjectsInRange(NSMakeRange(range.location, range.length), withObjectsFromArray: newValues.array(newCount))
}
