#ifndef MACDEVICELISTER_H
#define MACDEVICELISTER_H

#include "devicelister.h"

#include <QMutex>
#include <QThread>

#include <DiskArbitration/DADisk.h>
#include <DiskArbitration/DADissenter.h>
#include <IOKit/IOKitLib.h>

class MacDeviceLister : public DeviceLister {
  Q_OBJECT
 public:
  MacDeviceLister();
  ~MacDeviceLister();

  virtual QStringList DeviceUniqueIDs();
  virtual QVariantList DeviceIcons(const QString& id);
  virtual QString DeviceManufacturer(const QString& id);
  virtual QString DeviceModel(const QString& id);
  virtual quint64 DeviceCapacity(const QString& id);
  virtual quint64 DeviceFreeSpace(const QString& id);
  virtual QVariantMap DeviceHardwareInfo(const QString& id);
  virtual QString MakeFriendlyName(const QString& id);
  virtual QList<QUrl> MakeDeviceUrls(const QString& id);

  virtual void UnmountDevice(const QString &id);
  virtual void UpdateDeviceFreeSpace(const QString& id);

  struct MTPDevice {
    MTPDevice() : capacity(0), free_space(0) {}
    QString vendor;
    QString product;
    quint16 vendor_id;
    quint16 product_id;

    int quirks;
    int bus;
    int address;

    int capacity;
    int free_space;
  };

 public slots:
  virtual void ShutDown();

 private:
  virtual void Init();

  static void DiskAddedCallback(DADiskRef disk, void* context);
  static void DiskRemovedCallback(DADiskRef disk, void* context);
  static void USBDeviceAddedCallback(void* refcon, io_iterator_t it);
  static void USBDeviceRemovedCallback(void* refcon, io_iterator_t it);

  static void DiskUnmountCallback(
      DADiskRef disk, DADissenterRef dissenter, void* context);

  void FoundMTPDevice(const MTPDevice& device, const QString& serial);
  void RemovedMTPDevice(const QString& serial);

  int GetFreeSpace(const QUrl& url);
  int GetCapacity(const QUrl& url);

  DASessionRef loop_session_;
  CFRunLoopRef run_loop_;

  QMap<QString, QString> current_devices_;
  QMap<QString, MTPDevice> mtp_devices_;

  QMutex libmtp_mutex_;

  static QSet<MTPDevice> sMTPDeviceList;
};

uint qHash(const MacDeviceLister::MTPDevice& device);
inline bool operator==(const MacDeviceLister::MTPDevice& a, const MacDeviceLister::MTPDevice& b) {
  return (a.vendor_id == b.vendor_id) &&
         (a.product_id == b.product_id);
}

#endif
