//---------------------------------------------------------------------------

#ifndef QSSmartUH
#define QSSmartUH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
enum QSSmartStatus {qsssDisabled, qsssStatusOk, qsssStatusWarning};
enum QSSmartSelfTest {qsstShort = 1, qsstExtended, qsstConveyance};
enum QSSmartSelftestStatus {qstsNoErrorOrNeverRun, qstsAbortedByHost, qstsAbortedByReset, qstsFatalError, qstsUnknownFailure, qstsElectricalFailure, qstsServoFailure, qstsReadFailure, qstsHandlingDamage, qstsReserved9, qstsReserved10, qstsReserved11, qstsReserved12, qstsReserved13, qstsReserved14, qstsInProgress, qstsError};
//---------------------------------------------------------------------------
#pragma pack(push,1)
class QSSmartValue
{
public:
	unsigned char IDNumber;
	short Flags;
	unsigned char Value;
	unsigned char Worst;
	unsigned int CurrentValue;
	char Reserved[3];

	__fastcall QSSmartValue(){}
	__fastcall QSSmartValue(AnsiString Record);
	AnsiString __fastcall AsString();
};
//---------------------------------------------------------------------------
class QSSmartReport
{
public:
	short RevisionNumber;
	QSSmartValue SmartValue[30];
	unsigned char OfflineDataCollectionStatus;
	unsigned char SelfTestExecutionStatus;
	unsigned short OfflineSeconds;
	unsigned char vs1;
	unsigned char OfflineDataCollectionCapability;
	unsigned short SmartCapability;
	unsigned char ErrorLoggingCapability;
	unsigned char vs2;
	unsigned char SSTPollingMinutes;
	unsigned char ESTPollingMinutes;
	unsigned char CSTPollingMinutes;
	unsigned char reserved[11];
	unsigned char vs3[125];
	unsigned char Checksum;

	QSSmartSelftestStatus __fastcall GetSmartSelftestStatus(unsigned int *Progress);
	bool __fastcall GetSelftestSupportShortExtended();
	bool __fastcall GetSelftestSupportConveyance();
	bool __fastcall GetSelftestSupportSelective();
};
//---------------------------------------------------------------------------
class QSSmartCommandData
{
public:
	unsigned char DCR;
	unsigned char FR;
	unsigned char SCR;
	unsigned char LLR;
	unsigned char LMR;
	unsigned char LHR;
	unsigned char DR;
	unsigned char CR;
	unsigned int TimeStamp;
	AnsiString __fastcall AsString();
};
//---------------------------------------------------------------------------
class QSSmartErrorData
{
public:
	unsigned char reserved;
	unsigned char ER;
	unsigned char SCR;
	unsigned char LLR;
	unsigned char LMR;
	unsigned char LHR;
	unsigned char DR;
	unsigned char SR;
	unsigned char ExtendedErrorInfo[19];
	unsigned char State;
	unsigned short Timestamp;
	AnsiString __fastcall AsString();
};
//---------------------------------------------------------------------------
class QSSmartErrorLog
{
public:
	QSSmartCommandData SmartCommandData[5];
	QSSmartErrorData SmartErrorData;
};
//---------------------------------------------------------------------------
class QSSmartLog
{
public:
	unsigned char RevisionNumber;
	unsigned char ErrorLogIndex;
	QSSmartErrorLog SmartErrorLog[5];
	unsigned short DeviceErrorCount;
	unsigned char reserved[57];
	unsigned char Checksum;

};
//---------------------------------------------------------------------------
class QSSmartLimit
{
public:
	unsigned char IDNumber;
	unsigned char Value;
	char Reserved[10];
};
//---------------------------------------------------------------------------
class QSSmartLimits
{
public:
	short RevisionNumber;
	QSSmartLimit SmartLimit[30];
	char reserved[150];
};
//---------------------------------------------------------------------------
const unsigned int SMART_RECEIVE_DRIVE_DATA = 0x0007C088;
//---------------------------------------------------------------------------
typedef struct
{
	BYTE bFeaturesReg;
	BYTE bSectorCountReg;
	BYTE bSectorNumberReg;
	BYTE bCylLowReg;
	BYTE bCylHighReg;
	BYTE bDriveHeadReg;
	BYTE bCommandReg;
	BYTE bReserved;
} IDERegisters;
//---------------------------------------------------------------------------
typedef struct
{
	DWORD        cBufferSize;
	IDERegisters irDriveRegs;
	BYTE         bDriveNumber;
	BYTE         bReserved[3];
	DWORD        dwReserved[4];
	BYTE         bBuffer[1];
} ATAInParam;
//---------------------------------------------------------------------------
typedef struct
{
	BYTE  bDriverError;
	BYTE  bIDEStatus;
	BYTE  bReserved[2];
	DWORD dwReserved[2];
} DriverStat;
//---------------------------------------------------------------------------
typedef struct
{
	DWORD      cBufferSize;
	DriverStat DriverStatus;
	BYTE       bBuffer[1];
} ATAOutParam;
//---------------------------------------------------------------------------
#pragma pack(pop)
//---------------------------------------------------------------------------
class PACKAGE QSDriveInfo
{
public:
	int DriveNumber;
	AnsiString Model;
	AnsiString Firmware;
	AnsiString Serial;
	bool IsCdRom;
};
//---------------------------------------------------------------------------
class QSDriveInfoList : public TList
{
private:
	QSDriveInfo* __fastcall GetItem(int Index)
		{return static_cast <QSDriveInfo*>(TList::Items[Index]);}
public:	
	__fastcall QSDriveInfoList();
	__fastcall ~QSDriveInfoList();
	void __fastcall Add(QSDriveInfo *DriveInfo);
	void __fastcall Erase();
	__property QSDriveInfo* Items[Index] = {read = GetItem};
};
//---------------------------------------------------------------------------
class QSSmartValueList : public TList
{
private:
	QSSmartValue* __fastcall GetItem(int Index)
		{return static_cast <QSSmartValue*>(TList::Items[Index]);}
public:
	__fastcall QSSmartValueList();
	__fastcall ~QSSmartValueList();
	bool __fastcall LoadFromFile(AnsiString Filename);
	void __fastcall SaveToFile(AnsiString Filename);
	void __fastcall Add(QSSmartValue *SmartValue);
	void __fastcall Erase();
	__property QSSmartValue* Items[Index] = {read = GetItem};
};
//---------------------------------------------------------------------------
class QSSmartValueInfo
{
public:
	unsigned int IDNumber;
	bool PreFail;
	unsigned int Value;
	unsigned int Worst;
	unsigned int Limit;
	unsigned int CurrentValue;
	AnsiString Name;
	unsigned int __fastcall GetValuePercentage(bool FullRange);
	unsigned int __fastcall GetLimitPercentage(bool FullRange);
	__fastcall QSSmartValueInfo(QSSmartValue* SmartValue, QSSmartLimit* SmartLimit, TStringList *Names);
	bool __fastcall IsUnderValue(bool FullRange, unsigned int Value);
	bool __fastcall IsUnderLimit(bool FullRange);
	AnsiString __fastcall AsString();
};
//---------------------------------------------------------------------------
typedef void __fastcall (__closure *QSSmartNotifyWarning)(TObject *Sender, QSSmartValueInfo *SmartValueInfo);
typedef void __fastcall (__closure *QSSmartNotifyLimit)(TObject *Sender, QSSmartValueInfo *SmartValueInfo);
typedef void __fastcall (__closure *QSSmartNotifyChange)(TObject *Sender, QSSmartValue* LastValue, QSSmartValue* CurrentValue);
//---------------------------------------------------------------------------
class PACKAGE QSSmart : public TComponent
{
private:
	int FDriveNumber;
	QSDriveInfoList *DriveInfoList;
	bool __fastcall ReadDevices();
	HANDLE DiskDevice;
	bool FFullRange;
	bool FAutoRead;
	bool LastReadResult;
	bool FErrorLoggingCapability;
	bool FBOOL;
	AnsiString FModel;
	AnsiString FFirmware;
	AnsiString FSerial;
	AnsiString FANS;
	unsigned int FErrorCount;
	unsigned int FUINT;
	int FINT;
	bool FoundDriver;
	int FCurrentDrive;
	int FWarningLimit;
	QSSmartValueList* LastValueList;
	QSSmartStatus __fastcall GetSmartStatus(HANDLE DiskDevice, int DriveNumber);
	QSSmartValue* __fastcall GetSmartValue(int Index);
	QSSmartLimit* __fastcall GetSmartLimit(int Index);
	QSDriveInfo* __fastcall GetDriveInfo(int Index);
	QSSmartValueInfo* __fastcall GetSmartValueInfo(int Index);
	QSSmartReport *SmartReport;
	QSSmartLimits *SmartLimits;
	QSSmartLog *SmartLog;
	QSSmartValueInfo *FSmartValueInfo;
	bool __fastcall GetSmartValues(HANDLE DiskDevice, BYTE DriveNum, QSSmartReport *SmartReport);
	bool __fastcall GetSmartLimits(HANDLE DiskDevice, BYTE DriveNum, QSSmartLimits *SmartLimits);
	bool __fastcall GetSmartLog(HANDLE DiskDevice, BYTE DriveNum, QSSmartLog *SmartLog);
	bool __fastcall SmartEnable(HANDLE DiskDevice, int DriveNum);
	bool __fastcall StartSmartSelfTest(HANDLE DiskDevice, BYTE DriveNum, QSSmartSelfTest SmartSelfTest);
	bool __fastcall GetIdentify(HANDLE DiskDevice, QSDriveInfo *DriveInfo);
	void __fastcall GetIdentifyStr(char *s, PWORD InqBuf, unsigned int InqBufSize);
	int __fastcall GetDriveCount();
	int __fastcall GetRevision();
	bool __fastcall GetFullRange();
	void __fastcall SetCurrentDrive(int ACurrentDrive);
	void __fastcall SetAutoRead(bool AAutoRead);
	int __fastcall GetTemperature();
	bool __fastcall GetSelftestSupportShortExtended();
	bool __fastcall GetSelftestSupportConveyance();
	bool __fastcall GetSelftestSupportSelective();
	QSSmartNotifyWarning FOnSmartWarning;
	QSSmartNotifyLimit FOnSmartLimit;
	QSSmartNotifyChange FOnSmartChange;
	TStringList *NameList;
protected:
	void __fastcall EventSmartWarning(QSSmartValueInfo *SmartValueInfo);
	void __fastcall EventSmartLimit(QSSmartValueInfo *SmartValueInfo);
	void __fastcall EventSmartChange(QSSmartValue* LastValue, QSSmartValue* CurrentValue);
	virtual void __fastcall Loaded();
	bool FLogFile;
	void __fastcall SetLogFile(bool ALogFile);
__published:
	//Properties alpha:
	__property bool AutoRead = {read = FAutoRead, write = SetAutoRead, default = false};
	__property int CurrentDrive = {read = FCurrentDrive, write = SetCurrentDrive};
	__property int DriveCount = {read = GetDriveCount};
	__property unsigned int ErrorCount = {read = FErrorCount, write = FUINT};
	__property bool ErrorLoggingCapability = {read = FErrorLoggingCapability, write = FBOOL};
	__property AnsiString Firmware = {read = FFirmware, write = FANS};
	__property bool FullRange = {read = GetFullRange};
	__property bool LogFile = {read = FLogFile, write = SetLogFile, default = false};
	__property AnsiString Model = {read = FModel, write = FANS};
	__property int Revision = {read = GetRevision};
	__property bool SelftestSupportConveyance = {read = GetSelftestSupportConveyance, write = FBOOL};
	__property bool SelftestSupportSelective = {read = GetSelftestSupportSelective, write = FBOOL};
	__property bool SelftestSupportShortExt = {read = GetSelftestSupportShortExtended, write = FBOOL};
	__property AnsiString Serial = {read = FSerial, write = FANS};
	__property int Temperature = {read = GetTemperature, write = FINT};
	__property int WarningLimit = {read = FWarningLimit, write = FWarningLimit, default = 90};
	//Events alpha:
	__property QSSmartNotifyChange OnSmartChange = {read = FOnSmartChange, write = FOnSmartChange};
	__property QSSmartNotifyLimit OnSmartLimit = {read = FOnSmartLimit, write = FOnSmartLimit};
	__property QSSmartNotifyWarning OnSmartWarning = {read = FOnSmartWarning, write = FOnSmartWarning};
public:
	//Properties (Runtime) alpha:
	__property QSDriveInfo* DriveInfo[int Index] = {read = GetDriveInfo};
	__property QSSmartLimit* SmartLimit[int Index] = {read = GetSmartLimit};
	__property QSSmartValue* SmartValue[int Index] = {read = GetSmartValue};
	__property QSSmartValueInfo* SmartValueInfo[int Index] = {read = GetSmartValueInfo};
	//Variables alpha:
	//Functions alpha:
	AnsiString __fastcall AsString();
	void __fastcall CheckLimits();
	void __fastcall CheckWarnings();
	bool __fastcall CompareToLast();
	void __fastcall CopyToLast();
	AnsiString __fastcall GetSmartSelftestStatus();
	QSSmartSelftestStatus __fastcall GetSmartSelftestStatus(unsigned int *Progress);
	bool __fastcall LoadLastValues();
	bool __fastcall Refresh(bool WithEvents = true);
	void __fastcall SaveLastValues();
	void __fastcall SaveReport(AnsiString Filename);
	bool __fastcall SelfTest(QSSmartSelfTest SmartSelfTest);
	//Con- & destructor last:
	__fastcall QSSmart(TComponent* AOwner);
	__fastcall ~QSSmart();

};
//---------------------------------------------------------------------------
#endif
 