#ifndef HARDWARE_H
#define HARDWARE_H

#include <QtGui>
#include <QWidget>
#include <windows.h>
#include "ui_hardware.h"
#include "information.h"
#include "PCANBasic.h"

class FCAN_View;

// Function pointers
//
typedef TPCANStatus (__stdcall *fpInitialize)(TPCANHandle, TPCANBaudrate, TPCANType, DWORD, WORD); 
typedef TPCANStatus (__stdcall *fpOneParam)(TPCANHandle); 
typedef TPCANStatus (__stdcall *fpRead)(TPCANHandle, TPCANMsg*, TPCANTimestamp*); 
typedef TPCANStatus (__stdcall *fpWrite)(TPCANHandle, TPCANMsg*); 
typedef TPCANStatus (__stdcall *fpFilterMessages)(TPCANHandle, DWORD, DWORD, TPCANMode); 
typedef TPCANStatus (__stdcall *fpGetSetValue)(TPCANHandle, TPCANParameter, void*, DWORD); 
typedef TPCANStatus (__stdcall *fpGetErrorText)(TPCANStatus, WORD, char*);

// Re-define of name for better code-read
//
#define fpUninitialize fpOneParam
#define fpReset fpOneParam
#define fpGetStatus fpOneParam
#define fpGetValue fpGetSetValue
#define fpSetValue fpGetSetValue


typedef struct ListViewMessageStatus
{
public:
	// Position Of Message In Listview
	//
	int Position;
	// TPCANMsg
	//
	TPCANMsg Msg;
	// Message TPCANTimestamp
	//
	TPCANTimestamp TimeStamp;

	// Constructor
	//
	ListViewMessageStatus(TPCANMsg *CanMsg,int Index, TPCANTimestamp* time)
	{
		Msg = *CanMsg;
		TimeStamp = *time;
		Position = Index;
	}
}MessageStatus;


class Hardware : public QWidget
{
	Q_OBJECT

public:
	Hardware(QWidget *parent = 0);
	~Hardware();

//public:       
		// PCANBasicClass constructor
		//
//		Hardware();
		// PCANBasicClass destructor
		//
//		~Hardware();

		/// <summary>
		/// Initializes a PCAN Channel 
		/// </summary>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="Btr0Btr1">"The speed for the communication (BTR0BTR1 code)"</param>
		/// <param name="HwType">"NON PLUG&PLAY: The type of hardware and operation mode"</param>
		/// <param name="IOPort">"NON PLUG&PLAY: The I/O address for the parallel port"</param>
		/// <param name="Interupt">"NON PLUG&PLAY: Interrupt number of the parallel port"</param>
		/// <returns>"A TPCANStatus error code"</returns>
        TPCANStatus Initialize(TPCANHandle Channel, TPCANBaudrate Btr0Btr1, TPCANType HwType = 0, DWORD IOPort = 0, WORD Interrupt = 0);

        /// <summary>
		/// Uninitializes one or all PCAN Channels initialized by CAN_Initialize
		/// </summary>
		/// <remarks>Giving the TPCANHandle value "PCAN_NONEBUS", 
		/// uninitialize all initialized channels</remarks>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus Uninitialize(TPCANHandle Channel);

		/// <summary>
		/// Resets the receive and transmit queues of the PCAN Channel
		/// </summary>
		/// <remarks>
		/// A reset of the CAN controller is not performed.
		/// </remarks>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <returns>"A TPCANStatus error code"</returns>
	        TPCANStatus Reset(TPCANHandle Channel);

		/// <summary>
		/// Gets the current status of a PCAN Channel
		/// </summary>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus GetStatus(TPCANHandle Channel);

		/// <summary>
		/// Reads a CAN message from the receive queue of a PCAN Channel 
		/// </summary>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="MessageBuffer">"A TPCANMsg structure buffer to store the CAN message"</param>
		/// <param name="TimestampBuffer">"A TPCANTimestamp structure buffer to get 
		/// the reception time of the message. If this value is not desired, this parameter
		/// should be passed as NULL"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus Read(TPCANHandle Channel, TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer);

		/// <summary>
		/// Transmits a CAN message 
		/// </summary>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="MessageBuffer">"A TPCANMsg buffer with the message to be sent"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus Write(TPCANHandle Channel, TPCANMsg* MessageBuffer);

		/// <summary>
		/// Configures the reception filter. 
		/// </summary>
		/// <remarks>The message filter will be expanded with every call to 
		/// this function. If it is desired to reset the filter, please use 
		/// the CAN_SetParameter function</remarks>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="FromID">"The lowest CAN ID to be received"</param>
		/// <param name="ToID">"The highest CAN ID to be received"</param>
		/// <param name="Mode">"Message type, Standard (11-bit identifier) or 
		/// Extended (29-bit identifier)"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus FilterMessages(TPCANHandle Channel, DWORD FromID, DWORD ToID, TPCANMode Mode);

		/// <summary>
		/// Retrieves a PCAN Channel value
		/// </summary>
		/// <remarks>Parameters can be present or not according with the kind 
		/// of Hardware (PCAN Channel) being used. If a parameter is not available,
		/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="Parameter">"The TPCANParameter parameter to get"</param>
		/// <param name="Buffer">"Buffer for the parameter value"</param>
		/// <param name="BufferLength">"Size in bytes of the buffer"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus GetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);

		/// <summary>
		/// Configures or sets a PCAN Channel value 
		/// </summary>
		/// <remarks>Parameters can be present or not according with the kind 
		/// of Hardware (PCAN Channel) being used. If a parameter is not available,
		/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
		/// <param name="Channel">"The handle of a PCAN Channel"</param>
		/// <param name="Parameter">"The TPCANParameter parameter to set"</param>
		/// <param name="Buffer">"Buffer with the value to be set"</param>
		/// <param name="BufferLength">"Size in bytes of the buffer"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus SetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);

		/// <summary>
		/// Returns a descriptive text of a given TPCANStatus error 
		/// code, in any desired language
		/// </summary>
		/// <remarks>The current languages available for translation are: 
		/// Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
		/// Italian (0x10) and French (0x0C)</remarks>
		/// <param name="Error">"A TPCANStatus error code"</param>
		/// <param name="Language">"Indicates a 'Primary language ID'"</param>
		/// <param name="Buffer">"Buffer for a null terminated char array"</param>
		/// <returns>"A TPCANStatus error code"</returns>
		TPCANStatus GetErrorText(TPCANStatus Error, WORD Language, char* Buffer);	


		TPCANStatus timRead(TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer);
		TPCANStatus btnWrite_Click(TPCANMsg* MessageBuffer);
		TPCANStatus btnResetFilter_Click(DWORD FromID, DWORD ToID, TPCANMode Mode);
		TPCANStatus btnSetFilter_Click(DWORD FromID, DWORD ToID, TPCANMode Mode);

		void InformationSet( Information * information );
		void FcanViewSet( FCAN_View * fcanview );
		QString HardwareInit(int mode, QString line);
		void ListenSet(int mode);
		void ResetSet( );
		int HardwareInitSet;


private slots:

		// txtDevNumber
//		void txtDevNumber_KeyPress();
//		void txtDevNumber_Leave();
		// btnDllInfo
		void btnDllInfo_Click();
		// btnGetDevNumber
		void btnGetDevNumber_Click();
		// btnSetDevNumber
		void btnSetDevNumber_Click();
		// btnInit
		void btnInit_Click();
		// btnInfo
		void btnInfo_Click();
		// cbbInterrupt
		// cbbIO
		// cbbMsgType
		// cbbBaudrates
//		void cbbBaudrates_SelectedIndexChanged();
		// cbbHws
		void cbbHws_Changed( const QString &s );
		// btnWrite
//		void btnWrite_Click();
		// chbRemote
//		void chbRemote_CheckedChanged();
		// chbExtended
//		void chbExtended_CheckedChanged();
		// txtData7
//		void txtID_KeyPress();
//		void txtData0_Leave();
		// txtData6
		// txtData5
		// txtData4
		// txtData3
		// txtData2
		// txtData1
		// txtData0
		// nudLength
//		void nudLength_ValueChanged();
		// txtID
//		void txtID_KeyPress();
//		void txtID_Leave();


		// rdbStandard
//		void rdbStandard_CheckedChanged();
		// rdbExtended
		// txtIdTo
//		void txtID_KeyPress();
//		void txtIdFrom_Leave();
		// txtIdFrom
//		void txtID_KeyPress();
//		void txtIdFrom_Leave();
		// btnResetFilter
//		void btnResetFilter_Click();
		// btnSetFilter
//		void btnSetFilter_Click();


		// rdbEvent
		// rdbTimer
//		void rdbTimer_CheckedChanged();
		// chbTimeStamp
//		void chbTimeStamp_CheckedChanged();
		// lstMessages
//		void lstMessages_DoubleClick();


		// txtInfo
//		void txtInfo_DoubleClick();
		// btnClose
//		void btnClose_Click();


		// timRead
//		void timRead();

		// File Menu
		void menu_triggered( );
		// Load File
		void menu_loadfile( );
		// Save File
		void menu_savefile( );
		// Close
		void closeEvent( QCloseEvent * event );

private:
	Ui::Hardware ui;

	Information * pInformation;
	FCAN_View * pFcanView;


//////////////////////////////////////////////////////////////////////
/// PCAN-BASIC-CLASS
//////////////////////////////////////////////////////////////////////

private:
		//DLL PCANBasic
		HINSTANCE m_hDll;

		//Function pointers
		fpInitialize m_pInitialize;
		fpUninitialize m_pUnInitialize;
		fpReset m_pReset;
		fpGetStatus m_pGetStatus;
		fpRead m_pRead;
		fpWrite m_pWrite;
		fpFilterMessages m_pFilterMessages;
		fpGetValue m_pGetValue;	
		fpSetValue m_pSetValue;
		fpGetErrorText m_pGetTextError;

		//Load flag
		bool m_bWasLoaded;

		// Load the PCANBasic API
		//
		void LoadAPI();

		// Releases the loaded API
		//
		void UnloadAPI();		

		// Initializes the pointers for the PCANBasic functions
		//
		void InitializePointers();

		// Loads the DLL
		//
		bool LoadDllHandle();

		// Gets the address of a given function name in a loaded DLL
		//
		FARPROC GetFunction(char* szName);


//////////////////////////////////////////////////////////////////////
/// PCAN-BASIC-DIG
//////////////////////////////////////////////////////////////////////


private:
	// ------------------------------------------------------------------------------------------
	// Private Members
	// ------------------------------------------------------------------------------------------
	// Variables to store the current PCANBasic instance
	//
//	PCANBasicClass *m_objPCANBasic;

	// Saves the handle of a PCAN hardware
	//
	TPCANHandle m_PcanHandle;

	// Saves the baudrate register for a conenction
	//
	TPCANBaudrate m_Baudrate;

	// Saves the type of a non-plug-and-play hardware
	//
	TPCANType m_HwType;

	// Variables to store the current reading mode
	// 0 : Timer Mode
	// 1 : Event Mode
	// 2 : Manual Mode
	//
	int m_ActiveReadingMode;

	// Timer identifier
	//
	UINT_PTR m_tmrRead;

	// CAN messages array. Store the message status for its display
	//
//	CPtrList *m_LastMsgsList;

	// Handle to set Received-Event
	//
	HANDLE m_hEvent;

	// Handle to the thread to read using Received-Event method
	//
	HANDLE m_hThread;

	// Handles of the current available PCAN-Hardware
	//
	TPCANHandle m_HandlesArray[27];


	// ------------------------------------------------------------------------------------------
	// Help functions
	// ------------------------------------------------------------------------------------------
	// Convert a int value to a CString
	//
//	CString IntToStr(int iValue);
	// Convert a int value to a CString formated in Hexadecimal
	//
//	CString IntToHex(int iValue, short iDigits);
	// Convert hexadecimal Cstring into int value (Zero if error)
	//
//	DWORD HexTextToInt(CString ToConvert);
	// Check txtData in an hexadecimal value
	//
//	void CheckHexEditBox(CString* txtData);
	// Create a LVItem renderer for MFC ListView
	//
//	int AddLVItem(CString Caption);
	// Enable/Disable Timer
	//
	void SetTimerRead(bool bEnable);
	// Configures the data of all ComboBox components of the main-form
	//
	void FillComboBoxData();
	// Gets the formated text for a CPAN-Basic channel handle
	//
	QString FormatChannelName(TPCANHandle handle);
	// Gets the name for a CPAN-Basic channel handle
	//
	QString GetTPCANHandleName(TPCANHandle handle);
	// Help Function used to get an error as text
	//
	QString GetFormatedError(TPCANStatus error);
	//Activates/deaactivates the different controls of the main-form according
	//with the current connection status
	//
	void SetConnectionStatus(bool bConnected);
	// Gets the current status of the PCAN-Basic message filter
	//
	bool GetFilterStatus(int* status);
	// Includes a new line of text into the information Listview
	//
//	void IncludeTextMessage(CString strMsg);
	// Gets ComboBox selected label
	// 
//	CString GetComboBoxSelectedLabel(CComboBox* ccb);
	// Configures the Debug-Log file of PCAN-Basic
	//
	void ConfigureLogFile();

	// ------------------------------------------------------------------------------------------
	// Message-proccessing functions
	// ------------------------------------------------------------------------------------------
	// Update existing MessageStatus using provided parameters
	//
	void ModifyMsgEntry(MessageStatus LastMsg,TPCANMsg NewMsg, TPCANTimestamp MyTimeStamp);
	// Create new MessageStatus using provided parameters
	//
	void InsertMsgEntry(TPCANMsg NewMsg, TPCANTimestamp MyTimeStamp);
	// Processes a received message, in order to show it in the Message-ListView
	//
//	void ProcessMessage(TPCANMsg MyMsg, TPCANTimestamp MyTimeStamp);
	// static Thread function to manage reading by event
	//
	static DWORD WINAPI CallCANReadThreadFunc(LPVOID lpParam);
	// member Thread function to manage reading by event
	//
	DWORD WINAPI CANReadThreadFunc(LPVOID lpParam);
	// Manage Reading method (Timer, Event or manual)
	//
	void ReadingModeChanged();
	// Function called to read manually messages
	void ReadMessage();

	void createMenus();
	void createMenuActions();
	int ValueCheck(QString ValueString);
	int HardwareIoInterruptSelect;

	struct {
		QMenu * pMenu;
		QAction * pLoadFile;
		QAction * pSaveFile;
	} SettingMenu;

};

#endif // HARDWARE_H

