import Foundation
import Phidget22_C

/**
Phidget Data Adapter Introduction  The Data Adapter class is used to interface third party devices and microcontrollers with Phidgets.
*/
public class DataAdapterBase : Phidget {

	public init() {
		var h: PhidgetHandle?
		PhidgetDataAdapter_create(&h)
		super.init(h!)
		initializeEvents()
	}

	internal override init(_ handle: PhidgetHandle) {
		super.init(handle)
	}

	deinit {
		if (retained) {
			Phidget_release(&chandle)
		} else {
			uninitializeEvents()
			PhidgetDataAdapter_delete(&chandle)
		}
	}

	/**
	The maximum length of a packet that can be sent in bytes.

	- returns:
	The maximum length of a packet.

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxPacketLength() throws -> UInt32 {
		let result: PhidgetReturnCode
		var maxPacketLength: UInt32 = 0
		result = PhidgetDataAdapter_getMaxPacketLength(chandle, &maxPacketLength)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxPacketLength
	}

	/**
	Sends a specified set of bytes as a packet to the VINTSPI to be read by the master. May overwrite data that has yet to be read by the master.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- data: The data to send.
	*/
	public func sendPacket(data: [UInt8]) throws {
		let result: PhidgetReturnCode
		let dataLen: Int = data.count
		result = PhidgetDataAdapter_sendPacket(chandle, data, dataLen)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Sends a specified set of bytes as a packet to the VINTSPI to be read by the master. May overwrite data that has yet to be read by the master.

	- parameters:
		- data: The data to send.
		- completion: Asynchronous completion callback
	*/
	public func sendPacket(data: [UInt8], completion: @escaping (ErrorCode) -> ()) {
		let callback = AsyncCallback(completion)
		let callbackCtx = Unmanaged.passRetained(callback)
		let dataLen: Int = data.count
		PhidgetDataAdapter_sendPacket_async(chandle, data, dataLen, AsyncCallback.nativeAsyncCallback, UnsafeMutableRawPointer(callbackCtx.toOpaque()))
	}

	internal override func initializeEvents() {
		initializeBaseEvents()
		PhidgetDataAdapter_setOnPacketHandler(chandle, nativePacketHandler, UnsafeMutableRawPointer(selfCtx!.toOpaque()))
	}

	internal override func uninitializeEvents() {
		uninitializeBaseEvents()
		PhidgetDataAdapter_setOnPacketHandler(chandle, nil, nil)
	}

	/**
	The most recent packet that the channel has received will be reported in this event.

	---
	## Parameters:
	*   `data`: The packet as an array of bytes.
	*   `overrun`: Indicates if there has been an overrun in the reveived data buffer. If TRUE, one or more packets from the master has been lost.
	*/
	public let packet = Event<DataAdapter, (data: [UInt8], overrun: Bool)> ()
	let nativePacketHandler : PhidgetDataAdapter_OnPacketCallback = { ch, ctx, data, dataLen, overrun in
		let me = Unmanaged<DataAdapter>.fromOpaque(ctx!).takeUnretainedValue()
		me.packet.raise(me, ([UInt8](UnsafeBufferPointer(start: data!, count: dataLen)), (overrun == 0 ? false : true)));
	}

}
