export function Name() { return "Corsair Lighting Node Pro "; }
export function VendorId() { return  0x1b1c;}
export function ProductId() { return 0x0C0B;}
export function Publisher() { return "WhirlwindFX"; }
export function Size() { return [1, 1]; }
export function DefaultPosition(){return [0, 0];}
export function DefaultScale(){return 1.0;}
export function LedNames() { return []; }
export function LedPositions() { return []; }
/* global
LightingMode:readonly
forcedColor:readonly
ArduinoCompatibilityMode:readonly
*/
export function ControllableParameters(){
	return [
		{"property":"seek", "group":"lighting", "label":"呼吸定位设备", description:"启用后，未添加模型的接口单色呼吸，根据接口颜色定位设备,设置完成后推荐关闭!推荐关闭！","type":"boolean", "default":"true"},
		{"property":"Turbo", "group":"lighting", "label":"高刷新率", description:"启用后，提升刷新率，但会占用更多系统资源,玩游戏等高负载使用时推荐关闭!！", "type":"boolean", "default":"true"},

//		{"property":"hub", "group":"lighting", "label":"5V_ARGB_HUB", "type":"number", "min":"7", "max":"40", "default":"27", "tooltip":"默认27LED模式 ! 其中7为NODE模式，8-40为NODE+HUB异步模式"},
		
//		{"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas","tooltip":"Canvas：画布模式__Forced：单色模式!"},
//		{"property":"forcedColor", "group":"lighting", "label":"单色模式_颜色", "min":"0", "max":"360", "type":"color", "default":"#009bde"},
//		{"property":"ArduinoCompatibilityMode", "group":"", "label":"Arduino Compatibility Mode", "type":"boolean", "default":"false", "tooltip":"This is required for Arduino Based Models. Enabling will lower frame rate on Official Corsair Models."},
		{"property":"test_hwl", "group":"", "label":"调试开机灯效（请使用海盗船ICUE软件设置板载硬件开机灯效）", description: "美商海盗船官网下载ICUE（https://www.corsair.com/cn/zh/s/downloads）","type":"boolean", "default":"false"},

	];
}

export function SubdeviceController(){ return true; }
export function DefaultComponentBrand() { return "CompGen";}
export function Documentation(){ return "troubleshooting/corsair"; }

//Channel Name, Led Limit
/** @type {ChannelConfigArray}  */
const ChannelALed = 54;
const ChannelBLed = 54;
const MChannel = 5;
const ChannelArray = [
	// ["Channel 1", 204, 120],
	// ["Channel 2", 204, 120],

	["Channel A1", ChannelALed],
	["Channel A2", ChannelALed],
	["Channel A3", ChannelALed],
	["Channel A4", ChannelALed],
	["Channel A5", ChannelALed],

	["Channel B1", ChannelBLed],
	["Channel B2", ChannelBLed],
	["Channel B3", ChannelBLed],
	["Channel B4", ChannelBLed],
	["Channel B5", ChannelBLed],
];

const DeviceMaxLedLimit = 408;

function SetupChannels() {
	device.SetLedLimit(DeviceMaxLedLimit);

	for(let i = 0; i < ChannelArray.length; i++) {
		const channelInfo = ChannelArray[i];

		if(channelInfo){
			device.addChannel(...channelInfo);
		}
	}
}

export function Validate(endpoint) {
	return endpoint.interface === -1 || endpoint.interface === 0 || endpoint.interface === 2;
}

export function Initialize() {
	SetupChannels();

	CorsairLightingController.FetchFirmwareVersion();
	if(Turbo) device.setFrameRateTarget(60);
}

export function Render() {
	device.clearReadBuffer();

	SendChannel(0);
//	device.pause(1);

	SendChannel(1);
//	device.pause(1);

	CorsairLightingController.CommitColors();

}

export function Shutdown() {
	CorsairLightingController.SetChannelToHardwareMode(0);
	CorsairLightingController.SetChannelToHardwareMode(1);
}
export function onTurboChanged(){ 
	if(Turbo){
		device.setFrameRateTarget(60);
	}else{
		device.setFrameRateTarget(30);
	}
}
function SendChannel(Channel) {
	let RGBData = [[],[],[]];
	let hub = 27;
	for(let i = 0; i < MChannel; i++) {
		let ch = i + Channel*MChannel;
		let componentChannel = device.channel(ChannelArray[ch][0]);
		let ChannelLedCount = componentChannel.LedCount();
		let ColorData = [];
		// if(LightingMode === "Forced"){
		// 	ColorData = device.createColorArray(forcedColor, ChannelLedCount, "Separate");
		// }else 
		if(!ChannelLedCount){
			ChannelLedCount = hub;
			const pulseColor = device.getChannelPulseColor(ChannelArray[ch][0]);
			ColorData = device.createColorArray(pulseColor, ChannelLedCount, "Separate");
		}else{
			ColorData = componentChannel.getColors("Separate");
		}
		let KongData = [];
		let num = Math.floor(ChannelLedCount / hub);
		i += num;
		if(ChannelLedCount%hub){
			KongData = Array(hub- (ChannelLedCount%hub)).fill(0x00);
		}else i--;
		for(let w=0; w<3; w++){
		RGBData[w].push(...ColorData[w]);
		RGBData[w].push(...KongData);
		}
	}
	CorsairLightingController.SetDirectColors(Channel, RGBData);
}

/**
 * Protocol Library for Corsair's Legacy Lighting Controllers
 * @class CorsairLightingControllerProtocol
 */
class CorsairLightingControllerProtocol{
	/** @typedef {1 | 2} ModeId */
	/** @typedef {0 | 1} ChannelId*/

	constructor(){
		this.writeLength = 65;
		this.readLength = 17;

		/** @type {Object.<string, ModeId>} */
		this.modes = {
			hardware: 1,
			software: 2
		};

		/**
		 * @alias CommandIdDict
		 * @type {Object.<string, number>}
		 * @readonly
		 */
		this.commandIds = {
			firmware: 0x02,
			directColors: 0x032,
			commit: 0x33,
			startDirect: 0x34,
			reset: 0x37,
			mode: 0x38
		};
	}

	FetchFirmwareVersion(){
		const packet = [0x00, this.commandIds.firmware];
		device.clearReadBuffer();
		device.write(packet, this.writeLength);

		const data = device.read([0x00], this.readLength);
		device.log(data);
	}
	/** @param {ChannelId} ChannelId */
	SetChannelToHardwareMode(ChannelId){
		this.SetChannelMode(ChannelId, this.modes.hardware);
	}
	/** @param {ChannelId} ChannelId */
	SetChannelToSoftwareMode(ChannelId){
		this.SetChannelMode(ChannelId, this.modes.software);
	}
	/**
	 * @param {ChannelId} ChannelId
	 * @param {ModeId} Mode
	 */
	SetChannelMode(ChannelId, Mode){
		const packet = [0x00, this.commandIds.mode, ChannelId, Mode];

		device.write(packet, this.writeLength);
		this.SafeRead();
	}
	/**
	 * @param {ChannelId} ChannelId
	 * @param {number[][]} RGBData
	 */
	SetDirectColors(ChannelId, RGBData){
		this.SetChannelToSoftwareMode(ChannelId);

		// if(ArduinoCompatibilityMode){
		// 	this.StartDirectColorSend(ChannelId);
		// }

		//Stream RGB Data
		let ledsSent = 0;
		// Check Red Channel Length
		let TotalLedCount = RGBData[0].length >= 204 ? 204 : RGBData[0].length;

		while(TotalLedCount > 0){
			const ledsToSend = TotalLedCount >= 50 ? 50 : TotalLedCount;

			this.StreamDirectColors(ledsSent, ledsToSend, 0, RGBData[0].splice(0, ledsToSend), ChannelId);

			this.StreamDirectColors(ledsSent, ledsToSend, 1, RGBData[1].splice(0, ledsToSend), ChannelId);

			this.StreamDirectColors(ledsSent, ledsToSend, 2, RGBData[2].splice(0, ledsToSend), ChannelId);

			ledsSent += ledsToSend;
			TotalLedCount -= ledsToSend;
		}
	}
	StartDirectColorSend(ChannelId){
		const packet = [0x00, this.commandIds.startDirect, ChannelId];

		device.write(packet, this.writeLength);
		this.SafeRead();
	}
	StreamDirectColors(startIdx, count, colorChannelid, data, channelId) {
		let packet = [0x00, this.commandIds.directColors, channelId, startIdx, count, colorChannelid];
		packet = packet.concat(data);

		device.write(packet, this.writeLength);
		this.SafeRead();
	}
	CommitColors(){
		const packet = [0x00, this.commandIds.commit, 0xFF];

		device.write(packet, this.writeLength);
		this.SafeRead();
	}

	// Arduino based Node Pro's cannot use a 0 timeout buffer clear.
	// This results in a 6fps loss for arduino models we can avoid on official models.
	SafeRead(){
		// if(ArduinoCompatibilityMode){
		// 	return device.read([0x00], 17);
		// }

		return device.read([0x00], 17, 0);
	}
}
const CorsairLightingController = new CorsairLightingControllerProtocol();

export function ImageUrl() {
	return "https://gitee.com/drgb-controller/drgb/raw/master/Image/corsair.png"
}
