#ifndef NET_TELNET_HAL_HPP_
#define NET_TELNET_HAL_HPP_

/*
 * telnet_hal.hpp
 *
 *  Created on: 11 янв. 2020 г.
 *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
  ------------------------------------------------------------------------
 * this is a telnet protocol filter over stdio device
 */

#include "hal_device.h"
#include "serial/stdio_hal.hpp"
#include <bitset>

class TelnetCommand;

class TelnetDeviceProxy : public StdIO_Device
                    //, public HAL_INBlock_Device
                    //, public HAL_Device
{
    public:
        typedef StdIO_Device inherited;
        typedef StdIO_Device io_t;

        TelnetDeviceProxy(io_t* _io);
        TelnetDeviceProxy(const_string name, io_t* _io);
        virtual ~TelnetDeviceProxy(){}

        //using inherited::init;
        void init(io_t* _io);

        // reset telnet negotiated state
        virtual void reset();

        io_t*   io() const {return _io;}

    public: // StdIO_Device
        virtual int get_char();
        // @return - amount of availiable data.
        virtual int get_wait(unsigned to = 0);
        // блокирующий прием

        //* блокирующая печать
        virtual int putChar(int ch);

        //*  неблокирующая печать
        virtual int postData ( const void* str, unsigned len);
        //* блокирующая печать
        virtual int puts( const char* str);
        //*  \return - длинна отправленного участка
        virtual int putData ( const void* str, unsigned len);

        //*  ожидание доступности печати
        //*  \return - количество байт возможных для неблокирующей печати
        virtual int put_wait(unsigned to = 0);
        //*  почти тоже put_wait, ждет полного опустошения
        virtual int put_flush(unsigned to = 0);
        //*  очищает буфер, прерывая текущую отправку
        virtual int put_drop();

        //* монополизация вывода (puts, putData предпочтительно использую ее )
        //* \arg onoff - захват/освобождение
        //* \return    - состояние захвачн ли вывод
        virtual bool put_access(bool onoff, unsigned to = toInfinite);

    public: // HAL_INBlock_Device
        //*  \return - длинна полученного участка
        //virtual int getData ( void* dst, unsigned len);
        //*  ожидание amount доступных символов
        //virtual int get_waitfor(unsigned amount, unsigned to = 0);

    protected:
        io_t*           _io;
        int             peekchar;

        // this is telnet command handle, shoud implement commands reaction
        virtual void command (int c);

        void reply (int cmd, int opt);
        // sends subnegotiation 
        void reply_sub(int opt, const u8* sub, unsigned len);
};

class TelnetDeviceBasic : public TelnetDeviceProxy
{
public:
        typedef TelnetDeviceProxy inherited;

        TelnetDeviceBasic( io_t* aio ) : inherited(aio){}
        virtual void command (int c);
        virtual void reset();

        typedef std::bitset<256>    TelnetOptions;
        TelnetOptions   local_option;
        TelnetOptions   remote_option;

        /*
        // this provided by linux <arpa/telnet.h>
        // Definitions for the TELNET protocol.
        enum TelnetCmd { //class : u8
            IAC     = 255,     // interpret as command:
            DONT    = 254,     // you are not to use option
            DO      = 253,     // please, you use option
            WONT    = 252,     // I won't use option
            WILL    = 251,     // I will use option
            SB      = 250,     // interpret as subnegotiation
            AYT     = 246,     // are you there
            NOP     = 241,     // nop
        };

        // Telnet options
        enum TelnetOption { //class : u8
            TELOPT_BINARY   = 0,   // 8-bit data path
            TELOPT_ECHO     = 1,   // echo
            TELOPT_SGA      = 3,   // suppress go ahead
            TELOPT_TM       = 6,   // timing mark
        };
        */

protected:

        void will_option (int opt);
        void wont_option (int opt);
        void do_option (int opt);
        void dont_option (int opt);
        void sub_option(int opt, u8* data,  unsigned len);
};




typedef TelnetDeviceBasic TelnetDevice;




#endif /* NET_TELNET_HAL_HPP_ */
