/**
 * @file TiproHidLinux.h
 * 
 * Tipro HID Linux
 * 
 * This file is a starting point to comunicate with Tipro devices.
 * 
 * It uses libusb/hidapi library (github.com/libusb/hidapi).
 * 
 * Tipro
 * 
 * support@tipro.si
 * 
 * Copyright 2021-2024
 */

/** 
  * @mainpage Tipro API
  * 
  * @section intro_sec 1. Introduction
  * Tipro API enables communictation with Tipro devices.
  * 
  * It uses libusb/hidapi library (github.com/libusb/hidapi) to comunicate through USB HID interface.
  * 
  * @section install_sec 2. Installation
  * 
  * @subsection step1 2.1 Install HIDAPI (https://github.com/libusb/hidapi):
  * Run the commands:
  * @verbatim
sudo apt update
sudo apt install libhidapi-dev
   @endverbatim
  * 
  * @subsection step2 2.2 Install Tipro library (support@tipro.si):
  * @verbatim
tar -xvzf tiprohidapi.tar.gz
sudo cp libtiprohidapi.so /usr/local/lib/
sudo ldconfig
   @endverbatim
  * 
  * @section usage_tiprohidapi_sec 3. Usage via TiproHidApi.h - same functions as Windows HID API
  * Include "TiproHidApi.h" file
  * 
  * Example code:
  * @verbatim
  

#include <iostream>
#include "string.h"
#include "TiproHidApi.h"
#include <unistd.h>

//**
//* @brief Callback function for returning pressed/released keys programmed with HID telephony content
//* @param nID ID of the telephony device (supporting more then one telephony devices on the same PC)
//* @param nUsagePage Top collection usage page (for now always 0x0b = Telephony)
//* @param nLinkUsage Usage of the specific link collection (0x01 = Phone, 0x06 = Key Pad, 0x07 = Progrmable Button)
//* @param nUsage Usage at the specific collection
//* @param bPressed Key pressed = TRUE or released = FALSE
//* @return 0
//* /
int function_to_recive_callbacks(USHORT nID, USHORT nUsagePage, USHORT nLinkUsage, USHORT nUsage, bool bPressed)
{
	std::cout << "Key event - device id: " << nID << " usagepage: " << nUsagePage << " linkusage: " << nLinkUsage << " usage: " << nUsage 
		<< ((bPressed) ? " Pressed" : " Released") << std::endl;
	return 0;
}

int main(int argc, char **argv)
{
	int res = -1;
	const int MAX_STR = 255;

	//***********************************************************
	// Detect and list connected Tipro devices and their modules
	//***********************************************************

	//search for connected devices with Tipro controller
	res = HIDDetectDevices();
	if (res == 0)
	{
		//get number of detected devices
		int num = HIDGetNumOfDetectedDevices();
		
		if (num > 0)
			std::cout << num << " Tipro device(s) detected." << std::endl;
		else
			std::cout << "No Tipro device detected." << std::endl;
		
		for (int i=0; i<num; i++)
		{
			//select device to comunicate with
			res = HIDSelectDeviceEx(i);
			if (res == 0)
			{
				//enumerate device modules
				res = HIDEnumerateModules();
				if (res == 0)
				{
					std::cout << std::endl << "*** Tipo device " << i << " ***" << std::endl;
					wchar_t wstr[MAX_STR];
					
					//get controller info
					int vmaj, vmin, vbuild, vcustom, fwlevel;
					res = HIDGetControllerInfo(&vmaj, &vmin, &vbuild, &vcustom, &fwlevel);
					if (res == 0)
					{
						std::cout << std::hex << "   controller ver: " << vmaj << "." << vmin << "." << vbuild << "." << vcustom << " fw_level: " << fwlevel << std::endl;
					}
					
					for (int j=0; j<16; j++)
					{
						//get module info
						unsigned char cmaj, cmin, cbuild, ctype, cid;
						res = HIDGetModuleVersionEx(j, &cmaj, &cmin, &cbuild, &ctype, &cid);
						if (res != 0)
						{
							break;
						}
						std::cout << std::hex << "   module" << j << " ver: " << static_cast<int>(cmaj) << "." << static_cast<int>(cmin) << "." << static_cast<int>(cbuild) 
							<< " type: " << static_cast<int>(ctype) << " id: " << static_cast<int>(cid) << std::endl;
					}
					
					//manage modules by using module specific functions
				}
			}
		}
	}
	else
	{
		std::cout << "HIDDetectDevices() error: " << res << std::endl;
	}
	
	std::cout << std::endl;


	//****************************
	// Catch HID Telephony events
	//****************************

	//detect conected devices with HID telephony support
	res = HIDDetectTelephonyDevices();
	if (res == 0)
	{
		//get number of HID telephony devices
		int num = HIDGetNumOfDetectedTelephonyDevices();
		
		if (num > 0)
			std::cout << num << " HID telephony device(s) detected." << std::endl;
		else
			std::cout << "No HID telephony device detected." << std::endl;
		
		for (int i=0; i<num; i++)
		{
			std::cout << std::endl << "*** HID telephony device " << i << " ***" << std::endl;
			wchar_t wstr[MAX_STR];
			char cstr[MAX_STR];
			short unsigned int vid, pid;
			
			//get HID telephony device info
			res = HIDGetTelephonyDevice_VID_PID(i, &vid, &pid);
			if (res == 0)
			{
				std::cout << std::hex << "   vendor id: 0x" << vid << std::endl << "   product id: 0x" << pid << std::endl;
			}
			
			memset(cstr, 0, MAX_STR);
			res = HIDGetTelephonyDevicePath(i, &cstr, MAX_STR);
			if (res == 0)
			{
				std::cout << "   device path: " << cstr << std::endl;
			}

			//register callback function
			HIDRegisterTelephonyCallbacks(i, function_to_recive_callbacks, NULL); 
		}
		
		try
		{
  			std::cout << std::endl << "Press keys programmed with HID telephony content." << std::endl << "Press Enter key to exit..." << std::endl; 

   			//wait for enter key
			getchar();

			for (int i=0; i<num; i++)
			{
				//unregister callback function
				HIDStopTelephonyKeyDevice(i);
			}
        	
		}
		catch (std::exception const &exc)
		{
			std::cout << "Exception caught " << exc.what() << std::endl;
		}
		catch (...)
		{
			std::cout << "Unknown exception caught" << std::endl;
		}
		
	}
	else
	{
		std::cout << "HIDDetectTelephonyDevices() error: " << res << std::endl;
	}
	
	return 0; 
}

   @endverbatim
  * 
  * @section usage_tiprohidlinux_sec 4. Usage via TiproHidLinux.h
  * Include "TiproHidLinux.h" file and module files you want to communicate with, e.g. "BF22.h"
  * 
  * Example code:
  * @verbatim
#include <iostream>
#include "TiproHidLinux.h"
#include "BF22.h"

int main(int argc, char** argv) 
{
	int res;
	std::cout << std::hex;
	
	//instance of TiproHid object 	
	TiproHid hid = TiproHid();
	
	//find Tipro devices
	hid.Enumerate();

	//count found devices
	unsigned int numDevices = hid.Count();
	if (numDevices>0)
	{
		std::cout << numDevices << " Tipro device(s) found." << std::endl;

		//get first device
		TiproHidDevice *device = hid.GetDevice(0);

		//open it
		res = device->Open();
		if (res == 0)
		{
			std::cout << "First device open." << std::endl;

			//enumerate its modules
			res = device->EnumerateModules();
			if (res == 0)
			{
				std::cout << "Modules of first device enumerated.\n" << std::endl;

				//comunicate with the device
				
				//if it is BF22 device, you can turn on leds on line keys
				res = TiproBF22SetLineKeysLedState(device, BF22_LED_GREEN, BF22_LED_ORANGE, BF22_LED_RED,
					BF22_LED_BLINK_GREEN_OFF, BF22_LED_BLINK_OFF_GREEN, BF22_LED_BLINK_ORANGE_OFF,
					BF22_LED_BLINK_OFF_ORANGE, BF22_LED_BLINK_RED_OFF, BF22_LED_BLINK_OFF_RED,
					BF22_LED_NOCHANGE, BF22_LED_NOCHANGE, BF22_LED_NOCHANGE, BF22_LED_NOCHANGE,
					BF22_LED_NOCHANGE, BF22_LED_BLINK_GREEN_RED, BF22_LED_BLINK_RED_GREEN);
					
				std::cout << "TiproBF22SetLineKeysLedState " << res << " " << std::endl;
				
				
			}
			else
			{
				std::cout << "EnumerateModules error: " << res << std::endl;
			}
		}
		else
		{
			std::cout << "Open error: " << res << std::endl;
		}

		//close the device
		device->Close();
	}
	else
	{
		std::cout << "No Tipro device found." << std::endl;
	}

	return 0; 
}
   @endverbatim
  */


#ifndef _TIPRO_TIPROHIDAPI_TIPROHIDLINUX_H_
#define _TIPRO_TIPROHIDAPI_TIPROHIDLINUX_H_

#include <vector>
#include "TiproHidDevice.h"


/**
 * @class TiproHid
 * @file TiproHidLinux.h
 * @brief Starting point for communication with Tipro devices.
 */
class TiproHid
{
	public:
	
	/**
	 * @brief Constructor
	 */
	TiproHid(); 
	
	/**
	 * @brief Destructor
	 */
	virtual ~TiproHid(); 
	
	/**
	 * @brief Detects available Tipro devices
	 * @return Error code
	 */
	virtual int Enumerate(); 
	
	/**
	 * @brief Returns number of found devices
	 * @return Number of devices
	 */
	virtual unsigned int Count();
	
	/**
	 * @brief Returns a device by index
	 * @param[in] index Number of device
	 * @return TiproHidDevice handle
	 */
	virtual TiproHidDevice* GetDevice(unsigned int index);
	
	/**
	 * @brief Get a runtime version of the library.
	 * @param[out] nVersionMajor Major version
	 * @param[out] nVersionMinor Minor version
	 * @param[out] nVersionBuild Build version
	 * @return Error code (0 - no error)
	 */
	virtual int GetLibraryVersion(int *nVersionMajor, int *nVersionMinor, int *nVersionBuild);
	
};


#endif