#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <vector>


class VectorAdaptor {
public:
    VectorAdaptor(std::vector<uint8_t> * v) : v_(v) {}

    void write(const char *data, uint32_t size) {
        v_->insert(v_->end(), data, data + size );
    }

private:
    std::vector<uint8_t> * v_;
};

class FilePtrAdaptor {
public:
    FilePtrAdaptor(const String &fileName) {
        static const String baseDirectory(".");
        auto fullFileName = baseDirectory + fileName;
        fptr = fopen(fullFileName.c_str(), "wb");
        if (fptr == NULL) {
            printf("fopen of %s failed, errno = %d - %s\n", fullFileName.c_str(), errno, strerror(errno));
            exit(1);
        }
    }

    ~FilePtrAdaptor() {
        fclose(fptr);
    }
    FilePtrAdaptor(const FilePtrAdaptor &) = delete;
    void operator=(const FilePtrAdaptor &) = delete;

    void write(const char *data, uint32_t size) {
        fwrite(data, size, 1, fptr);
    }

private:
    FILE * fptr;
};


class MockStorageWriter {
public:
    MockStorageWriter(const String &fileName) {
        adaptor_ = new FilePtrAdaptor(fileName);
        encoder_ = new StreamingMsgPackEncoder <FilePtrAdaptor>(adaptor_);
    }
    ~MockStorageWriter(){
        delete adaptor_;
        delete encoder_;
    }
    MockStorageWriter(const MockStorageWriter &) = delete;

    StreamingMsgPackEncoder<FilePtrAdaptor> &encoder() { return *encoder_; }

private:
    FilePtrAdaptor * adaptor_;
    StreamingMsgPackEncoder <FilePtrAdaptor> * encoder_;

};


class MockStorageReader {
public:
    MockStorageReader(const String &fileName)
    {
        static const String baseDirectory(".");
        auto fullFileName = baseDirectory + fileName;
        fptr = fopen(fullFileName.c_str(), "rb");
    }

    uint32_t readBytes(char *buffer, size_t length) {
        return fread(buffer, length, 1, fptr);
    }

    bool seek(uint32_t pos) {
        auto ret = fseek(fptr, pos, SEEK_SET);
        return ret == 0;
    }
private:
    FILE * fptr;
};