/***************************************************************************
 *   Copyright (C) 2003 by Mattia Merzi                                    *
 *   ottobit@ferrara.linux.it                                              *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef BLUEZCONNECTOR_H
#define BLUEZCONNECTOR_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>

#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

extern "C" {
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
}

#define BT_DISABLED 0
#define BT_ENABLED  1
#define BT_UNKNOWN  2
#define BTVALUE(x)       (x?BT_ENABLED:BT_DISABLED)
#define EMPTY_STRING ""

/*
 * This class handles the connection with the BlueZ libraries, implements
 * most of the bluetooth-related functions and owns the KBTDevice class
 * that is a single local bluetooth device representation.
 * It is used as a Singleton pattern thru the getDefaultConnector() method.
 *
 */

class BluezConnector
{

public:
    BluezConnector();
    ~BluezConnector();

    /*
     * This method implements the Singleton pattern. Returns the unique
     * instance of BluezConnector.
     */
    static BluezConnector* getDefaultConnector();

    /*
     * Renewes the BluezConnector. Trashes the connector's instance and
     * creates a new one.
     */
    static void Update();

    /*
     * Returns the number of devices
     * found on the local machine.
     */

    int countDevices() { return dev_num; }

    /*
     * This is the representation of a
     * Bluetooth device for the local
     * machine.
     */
    class KBTDevice {
    public:
        KBTDevice(struct hci_dev_info* di);
        ~KBTDevice();

        /*
         * Initializes the device using the passed hci_dev_info
         * struct, contining the basic information in order to
         * talk with the pyisical device.
         */
        void init(struct hci_dev_info* di);

        /*
         * Reinitializes the device, obtaining a fresh
         * hci_dev_info structure.
         */
        void reinit();

        /*
         * Open the device and obtains a file descriptor to id
         */
        void openDev();

        /*
         * Calls the ioctl(HCIDEVRESET) in order to
         * reset the device.
         */
        int  reset();

        /*
         * Turn the device up and the reinitializes the device.
         * If the device is already up, nothing is done.
         */
        void devUp();

        /*
         * Turn the device down and the reinitializes the device.
         * If the device is already down, nothing is done.
         */
        void devDown();

        /*
         * Returns the name of the device. If the device is
         * down, the device id is returned.
         */
        const char* getName();

        int getDevId() const { return dev_id; };

        /*
         * Returns the string representation of the device id,
         * with the same format of the hciconfig tool.
         */
        const char* getDev() { return dev; };

        /*
         * Returns the file descriptor for the local
         * connection to this device
         */
        int getfd() const { return fd; };

        int getType() const { return type; };
        const char* getStrType() { return hci_dtypetostr(type); }

        int getStatus() const { return status; }
        const char* getBDAddr() { return bdaddr; }
        int getIScan() const { return iscan; }
        int getPScan() const { return pscan; }
        int getAuth() const { return auth; }
        int getEncrypt() const { return encrypt; }
        const char* getFeatures() { return features; }
        const char* getRevision();
        const char* getManufacturer() { return manufacturer; }

        void setDevId(int _dev_id) { dev_id = _dev_id; };
        void setDev(char* _dev) { dev = _dev; };
        void setfd(int _fd) { fd = _fd; };
        void setType(int _type) { type = _type; };
        void setFlags(uint32_t flags);
        void setStatus(int _status) { status = _status; };
        void setBDAddr(hci_dev_info* _di);
        void setIScan(int _iscan) { iscan = _iscan; }
        void setPScan(int _pscan) { pscan = _pscan; }
        void setAuth(int _auth) { auth = _auth; }
        void setEncrypt(int _encrypt) { encrypt = _encrypt; }
        void setFeatures(uint8_t* _f) {
            features = lmp_featurestostr(_f, NULL, 255);
        }
        void setManufacturer(int compid) {
            strcpy(manufacturer,bt_compidtostr(compid));
        }
        void setScanMode(bool iscan, bool pscan);
	void setClass(uint32_t cls);
        void changeDevName(const char* name);
        void changeEncryption(bool _encryption);
        void changeAuthentication(bool _auth);
        void getClass(uint8_t* service, uint8_t* major, uint8_t* minor);
        void changeClass(uint8_t service, uint8_t major, uint8_t minor);

        /*
         * Return true if the device is opened.
         */
        int devOpen() { return devopen; };
    private:
        struct hci_dev_info device_info;
        const char* getRevEricsson();
        const char* getRevCsr(uint16_t rev);
        char name[248];
        char* dev;
        int dev_id,fd,devopen,type;
        char* bdaddr;
        char* features;
        char revision[102];
        char manufacturer[64];
        int status,iscan,pscan,auth,encrypt;
    };

    /*
     * Retuns the current device pointed by the
     * current cursor, that is, the current device.
     */
    BluezConnector::KBTDevice* getCurrentDevice() {
        return devices[cur_dev];
    }

    /*
     * Makes the device's list cursor point to
     * the device identified by the "name" parameter.
     * If the device does not exist, nothing is done.
     */
    int setCurrentDevice(const char* _name);

    /*
     * Moves the device's list cursor poin to
     * the next device in the list. If the current
     * is the last, nothing is done.
     */
    void nextDevice();

private:
    static BluezConnector* _instance; // singleton pattern instance
    class BluezConnector::KBTDevice* devices[HCI_MAX_DEV]; // all devices
    int ctl; // HCI Raw Socket: constructor opens, destructor close, God knows.
    int dev_num; // number of devices found on the local machine
    int cur_dev; // current device in list scan

    void HCIGetDeviceList(); // get all bt devices
    void initDevList(int dev_num);
    void addDevInfo(int ord, struct hci_dev_info *di);

};
#endif
