#include "Export.hpp"
#include "Logger.hpp"
#include "PrinterManager.hpp"
#include "Utility.hpp"

#include <iostream>
#include <fstream>

int strcmp_natural(const char* a, const char* b)
{
	if (!a || !b)
		return a ? 1 : b ? -1 : 0;

	if (isdigit(*a) && isdigit(*b))
	{
		char* remainderA, * remainderB;
		long valA = strtol(a, &remainderA, 10), valB = strtol(b, &remainderB, 10);

		if (valA != valB)
		{
			return valA - valB;
		}

		else
		{
			std::ptrdiff_t lengthA = remainderA - a, lengthB = remainderB - b;

			if (lengthA != lengthB)
			{
				return static_cast<int>(lengthA - lengthB);
			}

			else
			{
				return strcmp_natural(remainderA, remainderB);
			}
		}
	}

	if (isdigit(*a) || isdigit(*b))
	{
		return isdigit(*a) ? -1 : 1;
	}

	while (*a && *b)
	{
		if (isdigit(*a) || isdigit(*b))
		{
			return strcmp_natural(a, b);
		}

		if (*a != *b)
		{
			return *a - *b;
		}

		a++;
		b++;
	}

	return *a ? 1 : *b ? -1 : 0;
}

bool natural_less(const std::string& lhs, const std::string& rhs)
{
	return strcmp_natural(lhs.c_str(), rhs.c_str()) < 0;
}

int getZero()
{
	std::ofstream output;
	std::string errorLog;

	Logger::dumpErrorLog(errorLog);
	PrinterManager::clearPrinters();
	output.open("error.log", std::ofstream::out | std::ofstream::trunc);

	if (output)
	{
		output << errorLog;
		output.close();
	}

	else
	{
		std::cout << std::string("Error: failed to create error log file.") << std::endl << std::endl;
	}

	system("pause");
	return 0;
}

int main(int argc, char** argv)
{
	std::ifstream input;
	std::vector<std::string> usbDevicePaths(Utility::getUSBDevicePaths()), sortedFiles;
	std::string code, response;
	size_t index = 0, script = 2;

	Logger::enableErrorLog();

	if (usbDevicePaths.empty())
	{
		std::cout << std::string("Error: failed to detect any USB-connected label printers.") << std::endl << std::endl;
		return getZero();
	}

	PrinterManager::addPrinters(usbDevicePaths.size());

	if (argc <= 1)
	{
		std::cout << std::string("Input CPL command to send to printer(s).") << std::endl;
		std::getline(std::cin, code, '\n');

		for (; index < usbDevicePaths.size(); ++index)
		{
			PrinterManager::selectPrinterIndex(index);
			PrinterManager::setPrinterType(std::string("LABEL"));
			PrinterManager::setUSBDevicePath(usbDevicePaths[index]);
			PrinterManager::setUSBTimeout(5000);

			if (!PrinterManager::openUSBPort())
			{
				std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
				return getZero();
			}

			else if (!PrinterManager::writeUSBData(code))
			{
				std::cout << std::string("Error: failed to upload CPL command to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
				return getZero();
			}

			std::cout << std::string("Uploaded CPL command to printer #") << (index + 1) << std::string(".") << std::endl;
			std::cout << std::string("Waiting for download response from printer #") << (index + 1) << std::string(".") << std::endl;

			PrinterManager::readUSBData(response, 256);

			if (!response.empty())
			{
				std::cout << std::string("Received response from printer #") << (index + 1) << std::string(": \"") << response << std::string("\".") << std::endl << std::endl;
			}

			else
			{
				std::cout << std::string("Warning: did not receive response from printer #") << (index + 1) << std::string(": \"") << response << std::string("\".") << std::endl << std::endl;
			}
		}

		std::cout << std::string("Finished uploading CPL command to printer(s).") << std::endl << std::endl;
		return getZero();
	}

	for (; script <= static_cast<size_t>(argc); ++script)
	{
		sortedFiles.push_back(std::string(argv[script - 1]));
	}

	std::sort(sortedFiles.begin(), sortedFiles.end(), natural_less);

	for (; index < usbDevicePaths.size(); ++index)
	{
		PrinterManager::selectPrinterIndex(index);
		PrinterManager::setPrinterType(std::string("LABEL"));
		PrinterManager::setUSBDevicePath(usbDevicePaths[index]);
		PrinterManager::setUSBTimeout(120000);

		for (script = 0; script < sortedFiles.size(); ++script)
		{
			if (sortedFiles[script].find_last_of('.') != std::string::npos && sortedFiles[script].substr(sortedFiles[script].find_last_of('.')) == std::string(".404"))
			{
				std::cout << std::string("Uploading firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl;
				input.open(sortedFiles[script], std::ifstream::binary | std::ifstream::in);

				if (!input)
				{
					std::cout << std::string("Error: failed to open firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}

				input.seekg(0, std::ios::end);
				code.resize(input.tellg());
				input.seekg(0, std::ios::beg);
				input.read(&code[0], code.size());
				input.close();

				if (!PrinterManager::openUSBPort())
				{
					std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
					return getZero();
				}

				else if (!PrinterManager::writeUSBData(code))
				{
					std::cout << std::string("Error: failed to upload firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}
			}

			else
			{
				std::cout << std::string("Uploading CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl;
				input.open(sortedFiles[script], std::ifstream::binary | std::ifstream::in);

				if (!input)
				{
					std::cout << std::string("Error: failed to open CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}

				input.seekg(0, std::ios::end);
				code.resize(input.tellg());
				input.seekg(0, std::ios::beg);
				input.read(&code[0], code.size());
				input.close();

				if (!PrinterManager::openUSBPort())
				{
					std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
					return getZero();
				}

				else if (!PrinterManager::writeUSBData(code))
				{
					std::cout << std::string("Error: failed to upload CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}
			}
		}

		std::cout << std::string("Finished uploading CPL script file(s) to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
	}

	std::cout << std::string("Finished uploading CPL script files(s) to printer(s).") << std::endl << std::endl;
	return getZero();

}
#include "Export.hpp"
#include "Logger.hpp"
#include "PrinterManager.hpp"
#include "Utility.hpp"

/*JNIEXPORT jboolean JNICALL JNIClassPath(addPrinter)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::addPrinters());
}

JNIEXPORT jboolean JNICALL JNIClassPath(addPrinters)(JNIEnv*, jobject, jlong count)
{
	return static_cast<jboolean>(PrinterManager::addPrinters(static_cast<size_t>(count)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(clearPrinters)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::clearPrinters());
}

JNIEXPORT jlong JNICALL JNIClassPath(getPrinterCount)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getPrinterCount());
}

JNIEXPORT jlong JNICALL JNIClassPath(getSelectionIndex)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getSelectionIndex());
}

JNIEXPORT jboolean JNICALL JNIClassPath(selectPrinterIndex)(JNIEnv*, jobject, jlong index)
{
	return static_cast<jboolean>(PrinterManager::selectPrinterIndex(static_cast<size_t>(index)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMBaudRate)(JNIEnv*, jobject, jint baudRate)
{
	return static_cast<jboolean>(PrinterManager::setCOMBaudRate(static_cast<uint32_t>(baudRate)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMByteSize)(JNIEnv*, jobject, jbyte byteSize)
{
	return static_cast<jboolean>(PrinterManager::setCOMByteSize(static_cast<uint8_t>(byteSize)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMParity)(JNIEnv*, jobject, jbyte parity)
{
	return static_cast<jboolean>(PrinterManager::setCOMParity(static_cast<uint8_t>(parity)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMPort)(JNIEnv* virtualMachine, jobject, jstring portName)
{
	if (portName == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(portName, nullptr);
	const std::string port(buffer);

	virtualMachine->ReleaseStringUTFChars(portName, buffer);
	return static_cast<jboolean>(PrinterManager::setCOMPort(port));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMStopBits)(JNIEnv*, jobject, jbyte stopBits)
{
	return static_cast<jboolean>(PrinterManager::setCOMStopBits(static_cast<uint8_t>(stopBits)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setCOMTimeout)(JNIEnv*, jobject, jlong timeout)
{
	return static_cast<jboolean>(PrinterManager::setCOMTimeout(static_cast<size_t>(timeout)));
}

JNIEXPORT jint JNICALL JNIClassPath(getCOMBaudRate)(JNIEnv*, jobject)
{
	return static_cast<jint>(PrinterManager::getCOMBaudRate());
}

JNIEXPORT jboolean JNICALL JNIClassPath(getCOMIsBluetooth)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::getCOMIsBluetooth());
}

JNIEXPORT jbyte JNICALL JNIClassPath(getCOMByteSize)(JNIEnv*, jobject)
{
	return static_cast<jbyte>(PrinterManager::getCOMByteSize());
}

JNIEXPORT jbyte JNICALL JNIClassPath(getCOMParity)(JNIEnv*, jobject)
{
	return static_cast<jbyte>(PrinterManager::getCOMParity());
}

JNIEXPORT jstring JNICALL JNIClassPath(getCOMPort)(JNIEnv* virtualMachine, jobject)
{
	return virtualMachine->NewStringUTF(PrinterManager::getCOMPort().c_str());
}

JNIEXPORT jbyte JNICALL JNIClassPath(getCOMStopBits)(JNIEnv*, jobject)
{
	return static_cast<jbyte>(PrinterManager::getCOMStopBits());
}

JNIEXPORT jlong JNICALL JNIClassPath(getCOMTimeout)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getCOMTimeout());
}

JNIEXPORT jboolean JNICALL JNIClassPath(setLANAddress)(JNIEnv* virtualMachine, jobject, jstring address)
{
	if (address == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(address, nullptr);
	const std::string ipAddress(buffer);

	virtualMachine->ReleaseStringUTFChars(address, buffer);
	return static_cast<jboolean>(PrinterManager::setLANAddress(ipAddress));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setLANPort)(JNIEnv*, jobject, jshort port)
{
	return static_cast<jboolean>(PrinterManager::setLANPort(static_cast<uint16_t>(port)));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setLANTimeout)(JNIEnv*, jobject, jlong timeout)
{
	return static_cast<jboolean>(PrinterManager::setLANTimeout(static_cast<size_t>(timeout)));
}

JNIEXPORT jstring JNICALL JNIClassPath(getLANAddress)(JNIEnv* virtualMachine, jobject)
{
	return virtualMachine->NewStringUTF(PrinterManager::getLANAddress().c_str());
}

JNIEXPORT jshort JNICALL JNIClassPath(getLANPort)(JNIEnv*, jobject)
{
	return static_cast<jshort>(PrinterManager::getLANPort());
}

JNIEXPORT jlong JNICALL JNIClassPath(getLANTimeout)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getLANTimeout());
}

JNIEXPORT jboolean JNICALL JNIClassPath(setLPTPort)(JNIEnv* virtualMachine, jobject, jstring port)
{
	if (port == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(port, nullptr);
	std::string lptPort(buffer);

	virtualMachine->ReleaseStringUTFChars(port, buffer);
	return static_cast<jboolean>(PrinterManager::setLPTPort(lptPort));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setLPTTimeout)(JNIEnv*, jobject, jlong timeout)
{
	return static_cast<jboolean>(PrinterManager::setLPTTimeout(static_cast<size_t>(timeout)));
}

JNIEXPORT jstring JNICALL JNIClassPath(getLPTPort)(JNIEnv* virtualMachine, jobject)
{
	return virtualMachine->NewStringUTF(PrinterManager::getLPTPort().c_str());
}

JNIEXPORT jlong JNICALL JNIClassPath(getLPTTimeout)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getLPTTimeout());
}

JNIEXPORT jboolean JNICALL JNIClassPath(setUSBDevicePath)(JNIEnv* virtualMachine, jobject, jstring devicePath)
{
	if (devicePath == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(devicePath, nullptr);
	const std::string path(buffer);

	virtualMachine->ReleaseStringUTFChars(devicePath, buffer);
	return static_cast<jboolean>(PrinterManager::setUSBDevicePath(path));
}

JNIEXPORT jboolean JNICALL JNIClassPath(setUSBTimeout)(JNIEnv*, jobject, jlong timeout)
{
	return static_cast<jboolean>(PrinterManager::setUSBTimeout(static_cast<size_t>(timeout)));
}

JNIEXPORT jstring JNICALL JNIClassPath(getUSBDevicePath)(JNIEnv* virtualMachine, jobject)
{
	return virtualMachine->NewStringUTF(PrinterManager::getUSBDevicePath().c_str());
}

JNIEXPORT jlong JNICALL JNIClassPath(getUSBTimeout)(JNIEnv*, jobject)
{
	return static_cast<jlong>(PrinterManager::getUSBTimeout());
}

JNIEXPORT jstring JNICALL JNIClassPath(getPrinterType)(JNIEnv* virtualMachine, jobject)
{
	return virtualMachine->NewStringUTF(PrinterManager::getPrinterType().c_str());
}

JNIEXPORT jboolean JNICALL JNIClassPath(setPrinterType)(JNIEnv* virtualMachine, jobject, jstring type)
{
	if (type == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(type, nullptr);
	const std::string printerType(buffer);

	virtualMachine->ReleaseStringUTFChars(type, buffer);
	return static_cast<jboolean>(PrinterManager::setPrinterType(printerType));
}

JNIEXPORT jboolean JNICALL JNIClassPath(openCOMPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::openCOMPort());
}

JNIEXPORT jstring JNICALL JNIClassPath(readCOMString)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::string buffer;
	jstring result = nullptr;

	PrinterManager::readCOMData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewStringUTF(buffer.c_str());

	return result;
}

JNIEXPORT jbyteArray JNICALL JNIClassPath(readCOMData)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::vector<uint8_t> buffer;
	jbyteArray result = nullptr;

	PrinterManager::readCOMData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewByteArray(static_cast<jsize>(buffer.size()));

	if (!buffer.empty())
	{
		virtualMachine->SetByteArrayRegion(result, 0, static_cast<jsize>(buffer.size()), reinterpret_cast<const jbyte*>(&buffer[0]));
	}

	return result;
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeCOMString)(JNIEnv* virtualMachine, jobject, jstring data)
{
	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(data, nullptr);
	const std::string writeData(buffer);

	virtualMachine->ReleaseStringUTFChars(data, buffer);
	return static_cast<jboolean>(PrinterManager::writeCOMData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeCOMData)(JNIEnv* virtualMachine, jobject, jbyteArray data)
{
	std::vector<uint8_t> writeData;
	jsize bytes = 0;
	jbyte* buffer = nullptr;

	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	bytes = virtualMachine->GetArrayLength(data);
	buffer = virtualMachine->GetByteArrayElements(data, nullptr);
	writeData.resize(bytes, '\0');

	for (jsize index = 0; index < bytes; ++index)
	{
		writeData[static_cast<size_t>(index)] = static_cast<uint8_t>(buffer[static_cast<size_t>(index)]);
	}

	return static_cast<jboolean>(PrinterManager::writeCOMData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(closeCOMPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::closeCOMPort());
}

JNIEXPORT jboolean JNICALL JNIClassPath(openLANPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::openLANPort());
}

JNIEXPORT jstring JNICALL JNIClassPath(readLANString)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::string buffer;
	jstring result = nullptr;

	PrinterManager::readLANData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewStringUTF(buffer.c_str());

	return result;
}

JNIEXPORT jbyteArray JNICALL JNIClassPath(readLANData)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::vector<uint8_t> buffer;
	jbyteArray result = nullptr;

	PrinterManager::readLANData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewByteArray(static_cast<jsize>(buffer.size()));

	if (!buffer.empty())
	{
		virtualMachine->SetByteArrayRegion(result, 0, static_cast<jsize>(buffer.size()), reinterpret_cast<const jbyte*>(&buffer[0]));
	}

	return result;
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeLANString)(JNIEnv* virtualMachine, jobject, jstring data)
{
	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(data, nullptr);
	const std::string writeData(buffer);

	virtualMachine->ReleaseStringUTFChars(data, buffer);
	return static_cast<jboolean>(PrinterManager::writeLANData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeLANData)(JNIEnv* virtualMachine, jobject, jbyteArray data)
{
	std::vector<uint8_t> writeData;
	jsize bytes = 0;
	jbyte* buffer = nullptr;

	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	bytes = virtualMachine->GetArrayLength(data);
	buffer = virtualMachine->GetByteArrayElements(data, nullptr);
	writeData.resize(bytes, '\0');

	for (jsize index = 0; index < bytes; ++index)
	{
		writeData[static_cast<size_t>(index)] = static_cast<uint8_t>(buffer[static_cast<size_t>(index)]);
	}

	return static_cast<jboolean>(PrinterManager::writeLANData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(closeLANPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::closeLANPort());
}

JNIEXPORT jboolean JNICALL JNIClassPath(openLPTPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::openLPTPort());
}

JNIEXPORT jstring JNICALL JNIClassPath(readLPTString)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::string buffer;
	jstring result = nullptr;

	PrinterManager::readLPTData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewStringUTF(buffer.c_str());

	return result;
}

JNIEXPORT jbyteArray JNICALL JNIClassPath(readLPTData)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::vector<uint8_t> buffer;
	jbyteArray result = nullptr;

	PrinterManager::readLPTData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewByteArray(static_cast<jsize>(buffer.size()));

	if (!buffer.empty())
	{
		virtualMachine->SetByteArrayRegion(result, 0, static_cast<jsize>(buffer.size()), reinterpret_cast<const jbyte*>(&buffer[0]));
	}

	return result;
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeLPTString)(JNIEnv* virtualMachine, jobject, jstring data)
{
	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(data, nullptr);
	const std::string writeData(buffer);

	virtualMachine->ReleaseStringUTFChars(data, buffer);
	return static_cast<jboolean>(PrinterManager::writeLPTData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeLPTData)(JNIEnv* virtualMachine, jobject, jbyteArray data)
{
	std::vector<uint8_t> writeData;
	jsize bytes = 0;
	jbyte* buffer = nullptr;

	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	bytes = virtualMachine->GetArrayLength(data);
	buffer = virtualMachine->GetByteArrayElements(data, nullptr);
	writeData.resize(bytes, '\0');

	for (jsize index = 0; index < bytes; ++index)
	{
		writeData[static_cast<size_t>(index)] = static_cast<uint8_t>(buffer[static_cast<size_t>(index)]);
	}

	return static_cast<jboolean>(PrinterManager::writeLPTData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(closeLPTPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::closeLPTPort());
}

JNIEXPORT jboolean JNICALL JNIClassPath(openUSBPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::openUSBPort());
}

JNIEXPORT jstring JNICALL JNIClassPath(readUSBString)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::string buffer;
	jstring result = nullptr;

	PrinterManager::readUSBData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewStringUTF(buffer.c_str());

	return result;
}

JNIEXPORT jbyteArray JNICALL JNIClassPath(readUSBData)(JNIEnv* virtualMachine, jobject, jlong size)
{
	std::vector<uint8_t> buffer;
	jbyteArray result = nullptr;

	PrinterManager::readUSBData(buffer, static_cast<size_t>(size));
	result = virtualMachine->NewByteArray(static_cast<jsize>(buffer.size()));

	if (!buffer.empty())
	{
		virtualMachine->SetByteArrayRegion(result, 0, static_cast<jsize>(buffer.size()), reinterpret_cast<const jbyte*>(&buffer[0]));
	}

	return result;
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeUSBString)(JNIEnv* virtualMachine, jobject, jstring data)
{
	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	const char* buffer = virtualMachine->GetStringUTFChars(data, nullptr);
	const std::string writeData(buffer);

	virtualMachine->ReleaseStringUTFChars(data, buffer);
	return static_cast<jboolean>(PrinterManager::writeUSBData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(writeUSBData)(JNIEnv* virtualMachine, jobject, jbyteArray data)
{
	std::vector<uint8_t> writeData;
	jsize bytes = 0;
	jbyte* buffer = nullptr;

	if (data == nullptr)
	{
		return static_cast<jboolean>(false);
	}

	bytes = virtualMachine->GetArrayLength(data);
	buffer = virtualMachine->GetByteArrayElements(data, nullptr);
	writeData.resize(bytes, '\0');

	for (jsize index = 0; index < bytes; ++index)
	{
		writeData[static_cast<size_t>(index)] = static_cast<uint8_t>(buffer[static_cast<size_t>(index)]);
	}

	return static_cast<jboolean>(PrinterManager::writeUSBData(writeData));
}

JNIEXPORT jboolean JNICALL JNIClassPath(closeUSBPort)(JNIEnv*, jobject)
{
	return static_cast<jboolean>(PrinterManager::closeUSBPort());
}

JNIEXPORT void JNICALL JNIClassPath(enableErrorLog)(JNIEnv*, jobject)
{
	Logger::enableErrorLog();
}

JNIEXPORT void JNICALL JNIClassPath(disableErrorLog)(JNIEnv*, jobject)
{
	Logger::disableErrorLog();
}

JNIEXPORT jstring JNICALL JNIClassPath(dumpErrorLog)(JNIEnv* virtualMachine, jobject)
{
	std::string errorLog;

	Logger::dumpErrorLog(errorLog);
	return virtualMachine->NewStringUTF(errorLog.c_str());
}

JNIEXPORT jobject JNICALL JNIClassPath(getCOMPorts)(JNIEnv* virtualMachine, jobject)
{
	static const std::string arrayListClass("java/util/ArrayList"), initString("<init>"), voidString("()V"), addString("add"), objectString("(Ljava/lang/Object;)Z");
	const std::vector<std::string> ports(Utility::getCOMPorts());
	jclass arrayList = virtualMachine->FindClass(arrayListClass.c_str());
	jobject result = virtualMachine->NewObject(arrayList, virtualMachine->GetMethodID(arrayList, initString.c_str(), voidString.c_str()));

	for (size_t index = 0; index < ports.size(); ++index)
	{
		virtualMachine->CallVoidMethod(result, virtualMachine->GetMethodID(arrayList, addString.c_str(), objectString.c_str()), virtualMachine->NewStringUTF(ports[index].c_str()));
	}

	return result;
}

JNIEXPORT jobject JNICALL JNIClassPath(getLPTPorts)(JNIEnv* virtualMachine, jobject)
{
	static const std::string arrayListClass("java/util/ArrayList"), initString("<init>"), voidString("()V"), addString("add"), objectString("(Ljava/lang/Object;)Z");
	const std::vector<std::string> ports(Utility::getLPTPorts());
	jclass arrayList = virtualMachine->FindClass(arrayListClass.c_str());
	jobject result = virtualMachine->NewObject(arrayList, virtualMachine->GetMethodID(arrayList, initString.c_str(), voidString.c_str()));

	for (size_t index = 0; index < ports.size(); ++index)
	{
		virtualMachine->CallVoidMethod(result, virtualMachine->GetMethodID(arrayList, addString.c_str(), objectString.c_str()), virtualMachine->NewStringUTF(ports[index].c_str()));
	}

	return result;
}

JNIEXPORT jobject JNICALL JNIClassPath(getUSBDevicePaths)(JNIEnv* virtualMachine, jobject)
{
	static const std::string arrayListClass("java/util/ArrayList"), initString("<init>"), voidString("()V"), addString("add"), objectString("(Ljava/lang/Object;)Z");
	const std::vector<std::string> ports(Utility::getUSBDevicePaths());
	jclass arrayList = virtualMachine->FindClass(arrayListClass.c_str());
	jobject result = virtualMachine->NewObject(arrayList, virtualMachine->GetMethodID(arrayList, initString.c_str(), voidString.c_str()));

	for (size_t index = 0; index < ports.size(); ++index)
	{
		virtualMachine->CallVoidMethod(result, virtualMachine->GetMethodID(arrayList, addString.c_str(), objectString.c_str()), virtualMachine->NewStringUTF(ports[index].c_str()));
	}

	return result;
}*/

/*static bool writeDataChunks(const std::vector<uint8_t>& data, const size_t cycles, time_t &ms)
{
	std::vector<std::vector<uint8_t>> writeBlocks;
	std::vector<uint8_t> writeData;
	size_t offset = 0, bufferSize = 1024;

	for (size_t index = 0; index < cycles; ++index)
		writeData.insert(writeData.end(), data.begin(), data.end());

	writeData.push_back(0x1B);
	writeData.push_back(0x76);

	while (writeData.size() >= bufferSize)
	{
		writeBlocks.push_back(std::vector<uint8_t>(writeData.begin(), writeData.begin() + bufferSize));
		writeData.erase(writeData.begin(), writeData.begin() + bufferSize);
	}

	if (!writeData.empty())
	{
		writeBlocks.push_back(std::vector<uint8_t>(writeData.begin(), writeData.end()));
		writeData.clear();
	}

	ms = clock();

	while (offset < writeBlocks.size())
	{
		if (!PrinterManager::writeUSBData(writeBlocks[offset]))
		{
			return false;
		}

		++offset;
	}

	return true;
}*/

#include <iostream>
#include <fstream>

int strcmp_natural(const char* a, const char* b)
{
	if (!a || !b)
		return a ? 1 : b ? -1 : 0;

	if (isdigit(*a) && isdigit(*b))
	{
		char* remainderA, * remainderB;
		long valA = strtol(a, &remainderA, 10), valB = strtol(b, &remainderB, 10);

		if (valA != valB)
		{
			return valA - valB;
		}

		else
		{
			std::ptrdiff_t lengthA = remainderA - a, lengthB = remainderB - b;

			if (lengthA != lengthB)
			{
				return static_cast<int>(lengthA - lengthB);
			}

			else
			{
				return strcmp_natural(remainderA, remainderB);
			}
		}
	}

	if (isdigit(*a) || isdigit(*b))
	{
		return isdigit(*a) ? -1 : 1;
	}

	while (*a && *b)
	{
		if (isdigit(*a) || isdigit(*b))
		{
			return strcmp_natural(a, b);
		}

		if (*a != *b)
		{
			return *a - *b;
		}

		a++;
		b++;
	}

	return *a ? 1 : *b ? -1 : 0;
}

bool natural_less(const std::string& lhs, const std::string& rhs)
{
	return strcmp_natural(lhs.c_str(), rhs.c_str()) < 0;
}

int getZero()
{
	std::ofstream output;
	std::string errorLog;

	Logger::dumpErrorLog(errorLog);
	PrinterManager::clearPrinters();
	output.open("error.log", std::ofstream::out | std::ofstream::trunc);

	if (output)
	{
		output << errorLog;
		output.close();
	}

	else
	{
		std::cout << std::string("Error: failed to create error log file.") << std::endl << std::endl;
	}

	system("pause");
	return 0;
}

int main(int argc, char** argv)
{
	std::ifstream input;
	std::vector<std::string> usbDevicePaths(Utility::getUSBDevicePaths()), sortedFiles;
	std::string code, response;
	size_t index = 0, script = 2;

	Logger::enableErrorLog();

	if (usbDevicePaths.empty())
	{
		std::cout << std::string("Error: failed to detect any USB-connected label printers.") << std::endl << std::endl;
		return getZero();
	}

	PrinterManager::addPrinters(usbDevicePaths.size());

	if (argc <= 1)
	{
		std::cout << std::string("Input CPL command to send to printer(s).") << std::endl;
		std::getline(std::cin, code, '\n');

		for (; index < usbDevicePaths.size(); ++index)
		{
			PrinterManager::selectPrinterIndex(index);
			PrinterManager::setPrinterType(std::string("LABEL"));
			PrinterManager::setUSBDevicePath(usbDevicePaths[index]);
			PrinterManager::setUSBTimeout(5000);

			if (!PrinterManager::openUSBPort())
			{
				std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
				return getZero();
			}

			else if (!PrinterManager::writeUSBData(code))
			{
				std::cout << std::string("Error: failed to upload CPL command to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
				return getZero();
			}

			std::cout << std::string("Uploaded CPL command to printer #") << (index + 1) << std::string(".") << std::endl;
			std::cout << std::string("Waiting for download response from printer #") << (index + 1) << std::string(".") << std::endl;

			PrinterManager::readUSBData(response, 256);

			if (!response.empty())
			{
				std::cout << std::string("Received response from printer #") << (index + 1) << std::string(": \"") << response << std::string("\".") << std::endl << std::endl;
			}

			else
			{
				std::cout << std::string("Warning: did not receive response from printer #") << (index + 1) << std::string(": \"") << response << std::string("\".") << std::endl << std::endl;
			}
		}

		std::cout << std::string("Finished uploading CPL command to printer(s).") << std::endl << std::endl;
		return getZero();
	}

	for (; script <= static_cast<size_t>(argc); ++script)
	{
		sortedFiles.push_back(std::string(argv[script - 1]));
	}

	std::sort(sortedFiles.begin(), sortedFiles.end(), natural_less);

	for (; index < usbDevicePaths.size(); ++index)
	{
		PrinterManager::selectPrinterIndex(index);
		PrinterManager::setPrinterType(std::string("LABEL"));
		PrinterManager::setUSBDevicePath(usbDevicePaths[index]);
		PrinterManager::setUSBTimeout(120000);

		for (script = 0; script < sortedFiles.size(); ++script)
		{
			if (sortedFiles[script].find_last_of('.') != std::string::npos && sortedFiles[script].substr(sortedFiles[script].find_last_of('.')) == std::string(".404"))
			{
				std::cout << std::string("Uploading firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl;
				input.open(sortedFiles[script], std::ifstream::binary | std::ifstream::in);

				if (!input)
				{
					std::cout << std::string("Error: failed to open firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}

				input.seekg(0, std::ios::end);
				code.resize(input.tellg());
				input.seekg(0, std::ios::beg);
				input.read(&code[0], code.size());
				input.close();

				if (!PrinterManager::openUSBPort())
				{
					std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
					return getZero();
				}

				else if (!PrinterManager::writeUSBData(code))
				{
					std::cout << std::string("Error: failed to upload firmware file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}
			}

			else
			{
				std::cout << std::string("Uploading CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl;
				input.open(sortedFiles[script], std::ifstream::binary | std::ifstream::in);

				if (!input)
				{
					std::cout << std::string("Error: failed to open CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}

				input.seekg(0, std::ios::end);
				code.resize(input.tellg());
				input.seekg(0, std::ios::beg);
				input.read(&code[0], code.size());
				input.close();

				if (!PrinterManager::openUSBPort())
				{
					std::cout << std::string("Error: failed to open USB interface handle to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
					return getZero();
				}

				else if (!PrinterManager::writeUSBData(code))
				{
					std::cout << std::string("Error: failed to upload CPL script file \"") << sortedFiles[script] << std::string("\".") << std::endl << std::endl;
					return getZero();
				}
			}
		}

		std::cout << std::string("Finished uploading CPL script file(s) to printer #") << (index + 1) << std::string(".") << std::endl << std::endl;
	}

	std::cout << std::string("Finished uploading CPL script files(s) to printer(s).") << std::endl << std::endl;
	return getZero();

	/*std::vector<std::string> usbDevicePaths(Utility::getUSBDevicePaths());
	std::vector<uint8_t> inputData, writeData({ 0x22, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x22, 0x0a, 0x22, 0x20, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x22, 0x0a, 0x22, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x22, 0x0a, 0x22, 0x20, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x22, 0x0a, 0x22, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x22, 0x0a, 0x22, 0x20, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x22, 0x0a, 0x22, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x22, 0x0a, 0x22, 0x20, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x22, 0x0a, 0x22, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x22, 0x0a, 0x22, 0x20, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x22, 0x0a, 0x22, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x22, 0x0a, 0x22, 0x20, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x22, 0x0a, 0x22, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x22, 0x0a, 0x22, 0x20, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x22, 0x0a, 0x22, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x22, 0x0a, 0x22, 0x20, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x22, 0x0a, 0x22, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x22, 0x0a, 0x22, 0x20, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x22, 0x0a, 0x22, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x22, 0x0a, 0x22, 0x20, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x22, 0x0a, 0x22, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x22, 0x0a, 0x22, 0x20, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x22, 0x0a, 0x22, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x22, 0x0a, 0x22, 0x20, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x22, 0x0a, 0x22, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x22, 0x0a, 0x22, 0x20, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x22, 0x0a, 0x22, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x22, 0x0a, 0x22, 0x20, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x22, 0x0a, 0x22, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x22, 0x0a, 0x22, 0x20, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x22, 0x0a, 0x22, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x22, 0x0a, 0x22, 0x20, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x22, 0x0a, 0x22, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x22, 0x0a, 0x22, 0x20, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x22, 0x0a, 0x22, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x22, 0x0a, 0x22, 0x20, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x22, 0x0a, 0x22, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x22, 0x0a, 0x22, 0x20, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x22, 0x0a, 0x22, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x22, 0x0a, 0x22, 0x20, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x22, 0x0a, 0x22, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x20, 0x35, 0x36, 0x20, 0x37, 0x38, 0x22, 0x0a, 0x22, 0x20, 0x20, 0x39, 0x30, 0x20, 0x2b, 0x5c, 0x20, 0x2d, 0x3f, 0x20, 0x24, 0x21, 0x20, 0x2a, 0x41, 0x20, 0x42, 0x43, 0x20, 0x44, 0x45, 0x20, 0x46, 0x47, 0x20, 0x48, 0x49, 0x20, 0x4a, 0x4b, 0x20, 0x4c, 0x4d, 0x20, 0x4e, 0x4f, 0x20, 0x50, 0x51, 0x20, 0x52, 0x22, 0x0a, 0x22, 0x20, 0x53, 0x20, 0x54, 0x55, 0x20, 0x56, 0x57, 0x20, 0x58, 0x59, 0x20, 0x5a, 0x31, 0x20, 0x32, 0x33, 0x20, 0x34, 0x35, 0x20, 0x36, 0x37, 0x20, 0x38, 0x39, 0x20, 0x30, 0x2b, 0x20, 0x5c, 0x2d, 0x20, 0x3f, 0x24, 0x20, 0x21, 0x2a, 0x20, 0x41, 0x42, 0x22, 0x0a, 0x22, 0x20, 0x43, 0x44, 0x20, 0x45, 0x46, 0x20, 0x47, 0x48, 0x20, 0x49, 0x4a, 0x20, 0x4b, 0x4c, 0x20, 0x4d, 0x4e, 0x20, 0x4f, 0x50, 0x20, 0x51, 0x52, 0x20, 0x53, 0x54, 0x20, 0x55, 0x56, 0x20, 0x57, 0x58, 0x20, 0x59, 0x5a, 0x20, 0x31, 0x32, 0x20, 0x33, 0x34, 0x22, 0x0A });
	time_t ms = 0;
	size_t cycles = 0;

	if (usbDevicePaths.empty())
	{
		std::cout << std::string("Failed to detect any USB devices.") << std::endl;
		std::cin >> cycles;

		return 0;
	}

	PrinterManager::addPrinters(1);
	PrinterManager::selectPrinterIndex(0);
	PrinterManager::setPrinterType(std::string("POS"));
	PrinterManager::setUSBDevicePath(usbDevicePaths[0]);
	PrinterManager::setUSBTimeout(60000);

	if (PrinterManager::openUSBPort())
	{
		std::cout << std::string("Connected to a USB device: ") << PrinterManager::getUSBDevicePath() << std::endl;
		size_t cycles = 0;


		if (PrinterManager::writeUSBData(std::vector<uint8_t>({ 0x1F, 0x03, 0x56, 0x01 })))
		{
			std::cout << std::string("Wrote initial configuration command to USB device.") << std::endl << std::endl << std::string("Input number of script cycles: ");
			std::cin >> cycles;
			std::cout << std::endl;

			if (writeDataChunks(writeData, cycles, ms))
			{
				PrinterManager::readUSBData(inputData, 1);
				ms = clock() - ms;

				std::cout << std::string("Wrote print data to USB device.") << std::endl;

				if (!inputData.empty())
				{
					std::cout << std::string("Elapsed: ") << ms << std::string(" milliseconds.") << std::endl;
					std::cout << std::string("Printed ") << (static_cast<double>(cycles) * 215.680) << std::string(" millimeters.") << std::endl;
					std::cout << std::string("Rate of printing = ") << ((static_cast<double>(cycles) * 215.680) / (static_cast<double>(ms) / 1000.0)) << std::string(" mm/s") << std::endl;
				}

				else
				{
					std::cout << std::string("Failed to correctly read status back to accumulate stopwatch timer.") << std::endl;
				}
			}

			else
			{
				std::cout << std::string("Failed to write print data to USB device.") << std::endl;
			}
		}

		else
		{
			std::cout << std::string("Failed to write initial configuration command to USB device.") << std::endl;
		}
	}

	else
	{
		std::cout << std::string("Failed to connect to USB device: ") << PrinterManager::getUSBDevicePath() << std::endl;
	}

	PrinterManager::clearPrinters();
	std::cin >> cycles;

	return 0;*/
}