
#ifndef _H_USB_SERVER
#define _H_USB_SERVER

#include "api.h"

#include <boost/function.hpp>
#include <boost/thread.hpp>

#include <list>
#include <vector>

class UsbCriteria;

class UsbServer
{
public:
    typedef boost::function<void ()> handler;
    typedef std::pair<unsigned long, std::string> device_desc;
    typedef std::vector<device_desc> devices_desc;

public:
    UsbServer(const UsbServer::handler& handler_func);
    ~UsbServer();

    bool start(const std::string& client_addr, uint16_t client_port = 32023);
    void stop();
    void set_filter(const std::string& filter);
    bool get_devices_desc(devices_desc& devices);
    bool is_running();
    bool is_shared_device(unsigned long hdev);
    bool is_share_allowed(unsigned long hdev);
    void share_device(unsigned long hdev);
    void stop_sharing_device(unsigned long hdev);
    void auto_sharing(bool enable);

private:
    void usb_notify();
    void enum_local_usb_devices();
    void connect_shared_devices();
    void connect_shared_device(unsigned long hdev);
    void stop_sharing_unplugged();
    void clear_criterias();
    void trace_usb_devices();
    void close_existing_callback_connection(const char *host, unsigned short port);
    void find_connected_client();
    void find_connected_client(const std::vector<SERVER_DESCRIPTOR>& clients);
    uint32 extract_host_ip(const char* hostname);
    int find_criteria_action(const DEVICE_DESCRIPTOR& desc);
    void ignore_existing_devices();
    void update_ignored_devices(const DEVICE_DESCRIPTOR& desc);
    void auto_share_devices();
    bool is_shared_device(const DEVICE_DESCRIPTOR& desc);
    bool is_share_allowed(const DEVICE_DESCRIPTOR& desc);
    // Returns true if device is connected to our client.
    bool is_connected_device(const DEVICE_DESCRIPTOR& desc);
    void share_device(const DEVICE_DESCRIPTOR& desc);
    void remove_ignored_unplugged();
    bool set_notification_event();
    void unset_notification_event();
    void raise_notification_event();
    void wait_for_notification();
    void stop_waiting();
    std::vector<DEVICE_DESCRIPTOR>::const_iterator find_device(unsigned long hdev);
    void remove_connected_device(unsigned long hdev);
    bool is_disconnected_from_remote(const DEVICE_DESCRIPTOR& desc);
    void update_connected_devices();

private:
    const UsbServer::handler _handler_func;
    std::vector<DEVICE_DESCRIPTOR> _devices;
    std::vector<UsbCriteria*> _criterias;
    std::list<unsigned long> _share_devices;
    std::list<unsigned long> _ignored_devices;
    std::list<unsigned long> _connected_devices;
    boost::thread* _usb_notify_thread;
    boost::mutex _protect_devices;
    uint32 _connection;
    uint32 _client;
#ifdef WIN32
    HANDLE _usb_event;
#else
    sem_t *_usb_event;
#endif
    uint32 _client_ip;
    bool _auto_sharing;
    bool _stop_notify_thread;
};

#endif // _H_USB_SERVER
