/*
 * print_hal.hpp
 *
   Copyright 2019 alexrayne <alexraynepe196@gmail.com>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#ifndef PRINT_HAL_HPP_
#define PRINT_HAL_HPP_

#include "serial/stdio_hal.hpp"
#include <stdarg.h>


class StdPrint {
  public:
    virtual int printf(const char* fmt, ...);
    int vprintf(const char* fmt, va_list args);
    virtual int vprintf(const char* fmt, unsigned nargs, va_list args) = 0;
    virtual int puts(const char* s) = 0;
};

class StdOutPrint: public virtual StdPrint {
    public:
        virtual int vprintf(const char* fmt, unsigned nargs, va_list args);
        virtual int puts(const char* s);
};

class StdOUT_ProxyPrint
  : public virtual StdPrint
{
  public:
    typedef StdPrint inherited;
    typedef StdPrint device_t;

    StdOUT_ProxyPrint(device_t* useio);

    using inherited::vprintf;
    //using inherited::printf;

    device_t* io(){return print_out;};
    virtual int printf(const char* fmt, ...);
    virtual int vprintf(const char* fmt, unsigned nargs, va_list args);
    virtual int puts(const char* s);
  protected:
    device_t* print_out;
};

class StdOUT_BufferPrint
  : public virtual StdPrint
{
  protected:
    unsigned print_limit;
    char* print_buf;
    bool  buffer_shared; //buffer is shared by threads
  public:
    typedef StdPrint inherited;
    typedef HAL_OUTBlock_Device device_t;
    StdOUT_BufferPrint();
    StdOUT_BufferPrint(device_t* useio);
    //StdOUT_BufferPrint(device_t* useio, char* buf, unsigned len);
    void init(device_t* useio, char* buf, unsigned len);

    virtual int printf(const char* fmt, ...);
    virtual int vprintf(const char* fmt, unsigned nargs, va_list args);
    virtual int puts(const char* s);

    device_t* io(){return print_out;}
    void buffer_share(bool onoff) {buffer_shared = onoff;}
  protected:
    device_t* print_out;
};

template<unsigned buf_limit>
class StdOUT_PrintBuffer
  : public StdOUT_BufferPrint
{
  protected:
    enum { buf_size = buf_limit};
    char   print_store[buf_size];
  public:
    typedef StdOUT_BufferPrint inherited;
    StdOUT_PrintBuffer()
      :inherited()
    {
       init(NULL);
    }

    StdOUT_PrintBuffer(device_t* useio)
      :inherited()
    {
       init(useio);
    }

    void init(device_t* useio){
      inherited::init(useio, print_store, buf_size);
    }
};







#endif /* PRINT_HAL_HPP_ */
