/*
  * This file is a part of LibCSys.
  * Library for getting system resource information in real time.
  * Copyright 2019 CuboCore Group
  *
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  *
  *
  * This program 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 General Public License for more details.
  *
  *
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, vsit http://www.gnu.org/licenses/.
  *
  */


#pragma once

#include <QtDBus>
#include <QFileSystemWatcher>

#include "libcsys_global.h"

class StorageBlock;
typedef QList<StorageBlock>    StorageBlocks;

class StorageDevice;
typedef QList<StorageDevice>   StorageDevices;

class LIBCSYSSHARED_EXPORT StorageManager : public QObject {
	Q_OBJECT

public:
	/* Initialization */
	StorageManager();

	/* List all the available devices */
	StorageDevices devices();

	/* All the available devices: will have containers and whole disks and partitions */
	StorageBlocks blocks();

	/* Devices which have a valid FS */
	StorageBlocks validBlocks();

private:
	/* Rescan all the available devices */
	void rescanStorage();

	/* Watcher to detect disk addition/deletion */
	QFileSystemWatcher *devWatch;

	/* List of all available devices */
	StorageDevices mDevices;

	/* List of all available blocks */
	StorageBlocks mBlocks;

	/* List of all blocks with valid FS */
	StorageBlocks mValidBlocks;

	/* Device Name (sda1, sda2, etc) */
	QStringList mDeviceNames;

	/* Block Name (sda1, sda2, etc) */
	QStringList mBlockNames;

private Q_SLOTS:
	/* Slot to emit deviceAdded/deviceRemoved signals */
	void detectChanges();

Q_SIGNALS:
	/* Something was added to /org/freedesktop/UDisks2/block_devices/ */
	void deviceAdded(const QString&);

	/* Something was removed from /org/freedesktop/UDisks2/block_devices/ */
	void deviceRemoved(const QString&);
};

class StorageDevice {
public:
	StorageDevice(StorageManager* sMgr);
	StorageDevice(const QString&, StorageManager*);
	StorageDevice(const StorageDevice&);
	StorageDevice& operator= (const StorageDevice&) = delete;
	~StorageDevice();

	StorageBlocks partitions();
	StorageBlocks validPartitions();

	QString label();
	QString path();
	QString id();
	bool isRemovable();
	bool isOptical();
	quint64 size();
	int rotationRate();
	QString seat();

	QVariant property(const QString &key);

private:
	void readPartitions();

	QStringList mPartNames;
	StorageBlocks mParts;
	StorageBlocks mValidParts;
	QDBusInterface *iface = nullptr;

	QString mDriveId;

	QString mLabel;
	QString mPath;
	QString mId;
	bool mIsRemovable;
	bool mIsOptical;
	quint64 mSize;
	int mRotationRate;
	QString mSeat;

	StorageManager *mSMgr = nullptr;
};

class StorageBlock {
public:
	StorageBlock();
	StorageBlock(const QString&);

	QString label();
	QString path();
	QString device();
	QString drive();
	QString mountPoint();
	QString fileSystem();

	bool isOptical();
	bool isRemovable();

	quint64 availableSize();
	quint64 totalSize();

	QVariant property(const QString &interface, const QString &key);

	bool mount();
	bool unmount();

private:
	void getMountPoint();

	QString mLabel;
	QString mPath;
	QString mDevice;
	QString mDrive;
	QString mMountPoint;
	QString mFileSystem;

	bool mIsOptical;
	bool mIsRemovable;

	quint64 mAvailableSize;
	quint64 mTotalSize;
};
