#include <Windows.h>
#include <list>
#include <string>

#include "tstring.h"
#include "local.h"
#include "tap_switch.h"

unsigned int __stdcall getMcp2221aNum(void)
{
	unsigned int ret = 0;
	std::list<std::tstring> paths;

	if (getAllHidDevicePaths(paths) != 0) {	// hid デバイスあり
		ret = findHidDeviceByID(paths, mcp2221a_vid, mcp2221a_pid);	// paths から、MCP2221A に該当するもののみ抜き出す
	}

	return ret;
}

unsigned int __stdcall getTapSwitchNum(void)
{
	unsigned int ret = 0;
	std::list<std::tstring> paths;

	if (getAllHidDevicePaths(paths) != 0) {	// hid デバイスあり

		findHidDeviceByID(paths, mcp2221a_vid, mcp2221a_pid);

		std::wstring manufacture;
		std::wstring product;

		for(auto el : paths) {
			if (getHidDeviceInfo(el, manufacture, product)) {
				if (product == productname) {
					++ret;
				}
			}
		}
	}
	return ret;
}

bool __stdcall getMcp2221aInfo(unsigned int index, std::wstring &manu, std::wstring &pro)
{
	bool ret = false;
	unsigned int num = 0;
	std::list<std::tstring> paths;

	if (getAllHidDevicePaths(paths) != 0) {	// hid デバイスあり
		num = findHidDeviceByID(paths, mcp2221a_vid, mcp2221a_pid);	// paths から、MCP2221A に該当するもののみ抜き出す
	}

	if (index < num) {
		
		auto it = paths.begin();
		for (unsigned int i = index; i != 0; --i) {
			++it;
		}
		
		ret = getHidDeviceInfo(*it, manu, pro);
	}
	return ret;
}

bool __stdcall setMcp2221aForTapSwitch(unsigned int index)
{
	bool ret = false;
	unsigned int num = 0;
	std::list<std::tstring> paths;

	if (getAllHidDevicePaths(paths) != 0) {	// hid デバイスあり
		num = findHidDeviceByID(paths, mcp2221a_vid, mcp2221a_pid);	// paths から、MCP2221A に該当するもののみ抜き出す
	}

	if (index < num) {

		auto it = paths.begin();
		for (unsigned int i = index; i != 0; --i) {
			++it;
		}

		// mcp2221a は、送信・受信ともに最大65バイト(最初の1バイトはレポートID == 0x00)
		uint8_t sbuf[65];	// send
		uint8_t rbuf[65];	// recv
		unsigned int rlen = sizeof(rbuf);

		memset(sbuf, 0, sizeof(sbuf));
		uint8_t *command = sbuf + 1;	// 最初のバイトは 0x00 固定（レポートID）

		// product name を書き込む
		command[0] = 0xb1;
		command[1] = 0x03;
		command[2] = sizeof(productname);	// 終端NULL を含む
		command[3] = 0x03;
		wcscpy_s((wchar_t *)(command + 4), (sizeof(sbuf) - 5) / sizeof(wchar_t), productname);	// command + report_id = 5 bytes
		
		ret = rwHidDevice(*it, sbuf, sizeof(sbuf), rbuf, &rlen);

		
		// GP の設定を書き込む
		// GP0 をコントロールする。
		// GP0 HI  -> 5V 出力＆LED ON
		// GP0 LOW -> 0V 出力＆LED OFF
		rlen = sizeof(rbuf);
		command[0] = 0xb1;
		command[1] = 0x01;
		command[2] = 0x00;	// GP0 は、GPIO, OUT, 初期値 LOW
		command[3] = 0x00;	// GP1 は、GPIO, OUT, 初期値 LOW
		command[4] = 0x11;	// GP2 は、USB,  OUT, 初期値 HI
		command[5] = 0x00;	// GP3 は、GPIO, OUT, 初期値 LOW

		ret &= rwHidDevice(*it, sbuf, sizeof(sbuf), rbuf, &rlen);
	}

	return ret;
}

bool __stdcall switchTapSwitch(unsigned int index, uint8_t sw)
{
	bool ret = false;
	std::list<std::tstring> paths;

	if (getAllHidDevicePaths(paths) != 0) {	// hid デバイスあり
		findHidDeviceByID(paths, mcp2221a_vid, mcp2221a_pid);	// paths から、MCP2221A に該当するもののみ抜き出す
	}

	std::wstring manufacture;
	std::wstring product;
	for (auto it = paths.begin(); it != paths.end(); ) {
		if (getHidDeviceInfo(*it, manufacture, product)) {
			if (product == productname) {
				++it;	// tap switch は残す
			}
			else {
				it = paths.erase(it);	// tap switch で無いものは削除する
			}
		}
	}

	if (index < paths.size()) {

		auto it = paths.begin();
		for (unsigned int i = index; i != 0; --i) {
			++it;
		}

		// mcp2221a は、送信・受信ともに最大65バイト(最初の1バイトはレポートID == 0x00)
		uint8_t sbuf[65];	// send
		uint8_t rbuf[65];	// recv
		unsigned int rlen = sizeof(rbuf);

		memset(sbuf, 0, sizeof(sbuf));
		uint8_t *command = sbuf + 1;	// 最初のバイトは 0x00 固定（レポートID）

		// set gpio
		command[0] = 0x50;
		command[1] = 0x00;
		command[2] = 0x01;	// set GP0
		command[3] = sw;	// 1 = ON, 0 = OFF
		command[4] = 0x01;	// in/out set
		command[5] = 0x00;	// output
		command[6] = 0x00;	// leave GP1
		command[7] = 0x00;
		command[8] = 0x00;
		command[9] = 0x00;
		command[10] = 0x00;
		command[11] = 0x00;
		command[12] = 0x00;
		command[13] = 0x00;
		command[14] = 0x00;
		command[15] = 0x00;
		command[16] = 0x00;
		command[17] = 0x00;

		ret = rwHidDevice(*it, sbuf, sizeof(sbuf), rbuf, &rlen);
	}
	return ret;
}