/* This file is part of the TDE libraries
   Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
             (C) 2013 Golubev Alexander <fatzer2@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef _TDESTORAGEDEVICE_H
#define _TDESTORAGEDEVICE_H

#include "tdegenericdevice.h"

// Keep readDiskDeviceSubtypeFromString() in tdehardwaredevices.cpp in sync with this enum
namespace TDEDiskDeviceType {
#if __cplusplus >= 201103L
enum TDEDiskDeviceType : unsigned long long {
#else
enum TDEDiskDeviceType {
#endif
	Null =		0x0000000000000000ULL,
	MediaDevice =	0x0000000000000001ULL,
	Floppy =	0x0000000000000002ULL,
	CDROM =		0x0000000000000004ULL,
	CDR =		0x0000000000000008ULL,
	CDRW =		0x0000000000000010ULL,
	CDMO =		0x0000000000000020ULL,
	CDMRRW =	0x0000000000000040ULL,
	CDMRRWW =	0x0000000000000080ULL,
	DVDROM =	0x0000000000000100ULL,
	DVDRAM =	0x0000000000000200ULL,
	DVDR =		0x0000000000000400ULL,
	DVDRW =		0x0000000000000800ULL,
	DVDRDL =	0x0000000000001000ULL,
	DVDRWDL =	0x0000000000002000ULL,
	DVDPLUSR =	0x0000000000004000ULL,
	DVDPLUSRW =	0x0000000000008000ULL,
	DVDPLUSRDL =	0x0000000000010000ULL,
	DVDPLUSRWDL =	0x0000000000020000ULL,
	BDROM =		0x0000000000040000ULL,
	BDR =		0x0000000000080000ULL,
	BDRW =		0x0000000000100000ULL,
	HDDVDROM =	0x0000000000200000ULL,
	HDDVDR =	0x0000000000400000ULL,
	HDDVDRW =	0x0000000000800000ULL,
	Zip =		0x0000000001000000ULL,
	Jaz =		0x0000000002000000ULL,
	Camera =	0x0000000004000000ULL,
	LUKS =		0x0000000008000000ULL,
	OtherCrypted =	0x0000000010000000ULL,
	CDAudio =	0x0000000020000000ULL,
	CDVideo =	0x0000000040000000ULL,
	DVDVideo =	0x0000000080000000ULL,
	BDVideo =	0x0000000100000000ULL,
	Flash =		0x0000000200000000ULL,
	USB =		0x0000000400000000ULL,
	Tape =		0x0000000800000000ULL,
	HDD =		0x0000001000000000ULL,
	Optical =	0x0000002000000000ULL,
	RAM =		0x0000004000000000ULL,
	Loop =		0x0000008000000000ULL,
	CompactFlash =	0x0000010000000000ULL,
	MemoryStick =	0x0000020000000000ULL,
	SmartMedia =	0x0000040000000000ULL,
	SDMMC =		0x0000080000000000ULL,
	UnlockedCrypt =	0x0000100000000000ULL,
	Other =		0x8000000000000000ULL
};

inline TDEDiskDeviceType operator|(TDEDiskDeviceType a, TDEDiskDeviceType b)
{
	return static_cast<TDEDiskDeviceType>(static_cast<unsigned long long>(a) | static_cast<unsigned long long>(b));
}

inline TDEDiskDeviceType operator&(TDEDiskDeviceType a, TDEDiskDeviceType b)
{
	return static_cast<TDEDiskDeviceType>(static_cast<unsigned long long>(a) & static_cast<unsigned long long>(b));
}

inline TDEDiskDeviceType operator~(TDEDiskDeviceType a)
{
	return static_cast<TDEDiskDeviceType>(~static_cast<unsigned long long>(a));
}
};

namespace TDEDiskDeviceStatus {
enum TDEDiskDeviceStatus {
	Null =			0x00000000,
	Mountable =		0x00000001,
	Removable =		0x00000002,
	Inserted =		0x00000004,
	Blank =			0x00000008,
	UsedByDevice =		0x00000010,
	UsesDevice =		0x00000020,
	ContainsFilesystem =	0x00000040,
	Hotpluggable =		0x00000080,
	Hidden =		0x00000100,
	Other =			0x80000000
};

inline TDEDiskDeviceStatus operator|(TDEDiskDeviceStatus a, TDEDiskDeviceStatus b)
{
	return static_cast<TDEDiskDeviceStatus>(static_cast<int>(a) | static_cast<int>(b));
}

inline TDEDiskDeviceStatus operator&(TDEDiskDeviceStatus a, TDEDiskDeviceStatus b)
{
	return static_cast<TDEDiskDeviceStatus>(static_cast<int>(a) & static_cast<int>(b));
}

inline TDEDiskDeviceStatus operator~(TDEDiskDeviceStatus a)
{
	return static_cast<TDEDiskDeviceStatus>(~static_cast<int>(a));
}
};

typedef TQMap<TQString,TQString> TDEStorageMountOptions;

class TDECORE_EXPORT TDEStorageDevice : public TDEGenericDevice
{
	public:
		/**
		*  Constructor.
		*  @param Device type
		*/
		TDEStorageDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn=TQString::null);
		
		/**
		* Destructor.
		*/
		~TDEStorageDevice();

		/**
		* @return a TQString with the disk or partition label, if any
		*/
		TQString diskLabel();

		/**
		* @return a TQString with the disk UUID, if any
		*/
		TQString diskUUID();

		/**
		* @return an OR-ed combination of TDEDiskDeviceType::TDEDiskDeviceType type flags
		*/
		TDEDiskDeviceType::TDEDiskDeviceType diskType();

		/**
		* @return an OR-ed combination of TDEDiskDeviceStatus::TDEDiskDeviceStatus type flags
		*/
		TDEDiskDeviceStatus::TDEDiskDeviceStatus diskStatus();

		/**
		* @return true if media inserted, false if no media available
		*/
		bool mediaInserted();

		/**
		* @return a TQString with the filesystem name, if any
		*/
		TQString fileSystemName();

		/**
		* @return a TQString with the filesystem usage string, if any
		*/
		TQString fileSystemUsage();

		/**
		* @return a TQStringList containing system paths to all devices with a lock on this device, if any
		*/
		TQStringList holdingDevices();

		/**
		* @return a TQStringList containing system paths to all devices locked by this device, if any
		*/
		TQStringList slaveDevices();

		/**
		* Mounts the device if not encrypted
		*
		* @param a TQString containing a requested mount name under /media, if desired
		* @param a TQString containing any mount options for pmount, if desired
		* @param a pointer to a TQString which will be populated with any error messages from pmount, if desired
		* @param a pointer to an integer which will be populated with the return code from pmount, if desired
		*
		* @return a TQString with the mount path, if successful
		*/
		TQString mountDevice(TQString mediaName=TQString::null, TDEStorageMountOptions mountOptions=TDEStorageMountOptions(), TQString* errRet=0, int* retcode=0);

		/**
		* Mounts the encrypted device if the correct passphrase is given
		*
		* @param a TQString containing the passphrase
		* @param a TQString containing a requested mount name under /media, if desired
		* @param a TQString containing any mount options for pmount, if desired
		* @param a pointer to a TQString which will be populated with any error messages from pmount, if desired
		* @param a pointer to an integer which will be populated with the return code from pmount, if desired
		*
		* @return a TQString with the mount path, if successful
		*/
		TQString mountEncryptedDevice(TQString passphrase, TQString mediaName=TQString::null, TDEStorageMountOptions mountOptions=TDEStorageMountOptions(), TQString* errRet=0, int* retcode=0);

		/**
		* Unmounts the device
		*
		* @param a pointer to a TQString which will be populated with any error messages from pmount, if desired
		* @param a pointer to an integer which will be populated with the return code from pmount, if desired
		*
		* @return TRUE if unmount was successful
		*/
		bool unmountDevice(TQString* errRet, int* retcode=0);

		/**
		* @return a TQString with the mount path, if mounted
		*/
		TQString mountPath();

		/**
		* @return an unsigned long with the device size in bytes
		*/
		unsigned long long deviceSize();

		/**
		* @return a TQString with the device size in human readable form
		*/
		TQString deviceFriendlySize();

		/**
		* Get an icon for this device
		* @param size a TDEIcon::StdSizes structure specifying the desired icon size
		* @return a TQPixmap containing the icon for the specified type
		*
		* This method overrides TDEGenericDevice::icon(TDEIcon::StdSizes size)
		*/
		TQPixmap icon(TDEIcon::StdSizes size);

		/**
		* @return a TQString with a friendly name
		*
		* This method overrides TDEGenericDevice::friendlyName()
		*/
		TQString friendlyName();

		/**
		* @return a TQString with a detailed friendly name
		*
		* This method overrides TDEGenericDevice::detailedFriendlyName()
		*/
		TQString detailedFriendlyName();

		/**
		*  @return a TQString containing the friendly type name
		*
		* This method overrides TDEGenericDevice::friendlyDeviceType()
		*/
		TQString friendlyDeviceType();

		/**
		* @param an OR-ed combination of TDEDiskDeviceType::TDEDiskDeviceType type flags
		*/
		bool isDiskOfType(TDEDiskDeviceType::TDEDiskDeviceType tf);

		/**
		* @param an OR-ed combination of TDEDiskDeviceStatus::TDEDiskDeviceStatus type flags
		*/
		bool checkDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus sf);

		/**
		* @param TRUE to engage media lock, FALSE to disable it
		* @return TRUE on success, FALSE on failure
		*
		* This method currently works on CD-ROM drives and similar devices
		*/
		bool lockDriveMedia(bool lock);

		/**
		* @return TRUE on success, FALSE on failure
		*
		* This method currently works on CD-ROM drives and similar devices
		*/
		bool ejectDriveMedia();

		/**
		* @return TRUE on success, FALSE on failure
		*
		* This method currently works on all removable storage devices
		*/
		bool ejectDrive();

		/**
		* @param path Full path to arbitrary file or directory
		* @return TQString with type of file system containing the given file,
		* or TQString::null if file system type unknown
		*/
		static TQString determineFileSystemType(TQString path);

	protected:
		/**
		* @param a TQString with the disk or partition label, if any
		* @internal
		*/
		void internalSetDiskLabel(TQString dn);

		/**
		* @param a TQString with the disk UUID, if any
		* @internal
		*/
		void internalSetDiskUUID(TQString id);

		/**
		* @param an OR-ed combination of TDEDiskDeviceType::TDEDiskDeviceType type flags
		* @internal
		*/
		void internalSetDiskType(TDEDiskDeviceType::TDEDiskDeviceType tf);

		/**
		* @param an OR-ed combination of TDEDiskDeviceStatus::TDEDiskDeviceStatus type flags
		* @internal
		*/
		void internalSetDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus st);

		/**
		* @param a bool with the media status
		* @internal
		*/
		void internalSetMediaInserted(bool inserted);

		/**
		* @param a TQString with the filesystem name, if any
		* @internal
		*/
		void internalSetFileSystemName(TQString fn);

		/**
		* @param a TQString with the filesystem usage string, if any
		* @internal
		*/
		void internalSetFileSystemUsage(TQString fu);

		/**
		* @param a TQStringList containing system paths to all devices with a lock on this device, if any
		* @internal
		*/
		void internalSetHoldingDevices(TQStringList hd);

		/**
		* @param a TQStringList containing system paths to all devices locked by this device, if any
		* @internal
		*/
		void internalSetSlaveDevices(TQStringList sd);

	private:
		TDEDiskDeviceType::TDEDiskDeviceType m_diskType;
		TDEDiskDeviceStatus::TDEDiskDeviceStatus m_diskStatus;
		TQString m_diskName;
		TQString m_diskUUID;
		TQString m_fileSystemName;
		TQString m_fileSystemUsage;
		bool m_mediaInserted;
		TQString m_mountPath;
		TQStringList m_holdingDevices;
		TQStringList m_slaveDevices;

	friend class TDEHardwareDevices;
};

#endif // _TDESTORAGEDEVICE_H