//
//  buffer.h
//
//  Created by hark on 2014/06/13.
//  Copyright (c) 2014 hark. All rights reserved.
//
#ifndef buffer_h
#define buffer_h

#ifdef __cplusplus
#include <algorithm>
#include <vector>
#endif // __cplusplus

#include "ringbuffer.h"

#include "bt_const.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

struct rawdata {

  int num_bytes;
  int reserved[7];
  char data[0x00100000]; // 1MB
  //char data[0x00200000]; // 2MB

#ifdef __cplusplus

  rawdata() : num_bytes(0) {}
  rawdata& operator = (const rawdata& rhs) {
    const int trans_byte = std::min(rhs.num_bytes, static_cast<int>(sizeof(data)));
    this->num_bytes = trans_byte;
    std::copy(&rhs.data[0], &rhs.data[trans_byte], &data[0]);
    return(*this);
  }
#endif // __cplusplus

};

extern int buf_init(void);
extern int buf_write(struct rawdata *raw);
extern int buf_read(struct rawdata *raw);

#ifdef __cplusplus
}
#endif // __cplusplus


#ifdef __cplusplus

class BufferObject {
private:

    ringbuffer<rawdata> buffer;

public:
    BufferObject(const BufferObject&);
    BufferObject();
    explicit BufferObject(const unsigned int default_size = 16);
    virtual ~BufferObject();
    BufferObject& operator = (const BufferObject&);

    int write(const rawdata& dat) {
        return(buffer.write(dat));
    }

    int read(rawdata& dat) {
      return(buffer.read(dat));
    }

    int readWithTimeout(rawdata& dat, const unsigned int timeout_ms) {
        return(buffer.read(dat, timeout_ms));
    }

    int clear() {
        return(buffer.clear());
    }
    
    unsigned int getlen() const {
        return(buffer.getlen());
    }
    
    unsigned int getdatnum() {
        return(buffer.getdatnum());
    }
};

//
// TODO:可変長
//
class rawdata_v {

public:
  
  int num_bytes;
  int seq_no;
  bool isLast;
  int reserved[5];
  std::vector<char> data;
  
  rawdata_v (const rawdata_v&arg) {
    *this = arg;
  }
  
  rawdata_v() : num_bytes(0), seq_no(0), isLast(false) {
  }
  
  rawdata_v& operator = (const rawdata_v& rhs) {
    if (rhs.data.size() > data.size()) {
      data.resize(rhs.data.size());
    }
    const int trans_byte = rhs.num_bytes;
    this->num_bytes = trans_byte;
    this->seq_no = rhs.seq_no;
    this->isLast = rhs.isLast;
    std::copy(&rhs.data[0], &rhs.data[trans_byte], &data[0]);
    return(*this);
  }

};

class AsyncBufferObject {
private:

  ::pthread_mutex_t  buf_mutex;
  ringbuffer<rawdata_v> buffer;

public:
  AsyncBufferObject(const AsyncBufferObject&);
  AsyncBufferObject();
  virtual ~AsyncBufferObject();
  AsyncBufferObject& operator = (const AsyncBufferObject&);
  
  int write(const rawdata_v& dat) {
    return(buffer.write(dat));
  }
  
  int read(rawdata_v& dat) {
    return(buffer.read(dat));
  }

  int readWithTimeout(rawdata_v& dat, const unsigned int timeout_ms) {
    return(buffer.read(dat, timeout_ms));
  }
  
  int clear() {
    return(buffer.clear());
  }
  
  unsigned int getlen() const {
    return(buffer.getlen());
  }
  
  unsigned int getdatnum() {
    return(buffer.getdatnum());
  }

  int lock() {
    ::pthread_mutex_lock(&buf_mutex);
    return(0);
  }

  int unlock() {
    ::pthread_mutex_unlock(&buf_mutex);
    return(0);
  }

};

extern int dbuf_lock();
extern int dbuf_write(struct rawdata_v *raw);
extern int dbuf_read(struct rawdata_v *raw);
extern int dbuf_unlock();

#endif /* __cplusplus */

#endif
