/*----------------------------------------------------------------------------
  ChucK Strongly-timed Audio Programming Language
    Compiler, Virtual Machine, and Synthesis Engine

  Copyright (c) 2003 Ge Wang and Perry R. Cook. All rights reserved.
    http://chuck.stanford.edu/
    http://chuck.cs.princeton.edu/

  This program is free software; you can redistribute it and/or modify
  it under the dual-license terms of EITHER the MIT License OR the GNU
  General Public License (the latter as published by the Free Software
  Foundation; either version 2 of the License or, at your option, any
  later version).

  This program is distributed in the hope that it will be useful and/or
  interesting, but WITHOUT ANY WARRANTY; without even the implied warranty
  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  MIT Licence and/or the GNU General Public License for details.

  You should have received a copy of the MIT License and the GNU General
  Public License (GPL) along with this program; a copy of the GPL can also
  be obtained by writing to the Free Software Foundation, Inc., 59 Temple
  Place, Suite 330, Boston, MA 02111-1307 U.S.A.
-----------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// name: chuck_io.h
// desc: chuck i/o
//
// authors: Spencer Salazar (spencer@ccrma.stanford.edu)
//    date: Summer 2012
//-----------------------------------------------------------------------------
#ifndef __CHUCK_IO_H__
#define __CHUCK_IO_H__

#include "chuck_oo.h"
#include "chuck_dl.h"
#include "util_buffers.h"

#include <list>
#include <fstream>
#include <sstream> // REFACTOR-2017: for custom output




// class initialization
// do not __DISABLE_MIDI__ this one in particular
t_CKBOOL init_class_Midi( Chuck_Env * env );
#ifndef __DISABLE_MIDI__
t_CKBOOL init_class_MidiRW( Chuck_Env * env );
#endif
#ifndef __DISABLE_HID__
t_CKBOOL init_class_HID( Chuck_Env * env );
#endif
t_CKBOOL init_class_io( Chuck_Env * env, Chuck_Type * type );
t_CKBOOL init_class_fileio( Chuck_Env * env, Chuck_Type * type );
// added 1.3.0.0 -- moved to be full-fledged class
t_CKBOOL init_class_chout( Chuck_Env * env, Chuck_Type * type );
// added 1.3.0.0 -- moved to be full-fledged class
t_CKBOOL init_class_cherr( Chuck_Env * env, Chuck_Type * type );
#ifndef __DISABLE_SERIAL__
 // added 1.3.1
t_CKBOOL init_class_serialio( Chuck_Env * env );
#endif




//-----------------------------------------------------------------------------
// name: Chuck_IO
// desc: base Chuck IO class
//-----------------------------------------------------------------------------
struct Chuck_IO : public Chuck_Event
{
public:
    Chuck_IO();
    virtual ~Chuck_IO();

public:
    // meta
    virtual t_CKBOOL good() = 0;
    virtual void close() = 0;
    virtual void flush() = 0;
    virtual t_CKINT mode() = 0;
    virtual void mode( t_CKINT flag ) = 0;

    // reading
    virtual Chuck_String * readLine() = 0;
    virtual t_CKINT readInt( t_CKINT flags ) = 0;
    virtual t_CKFLOAT readFloat() = 0;
    virtual t_CKFLOAT readFloat( t_CKINT flags ) = 0;
    virtual t_CKBOOL readString( std::string & str ) = 0;
    virtual t_CKBOOL eof() = 0;

    // writing
    virtual void write( const std::string & val ) = 0;
    virtual void write( t_CKINT val ) = 0;
    virtual void write( t_CKINT val, t_CKINT flags ) = 0;
    virtual void write( t_CKFLOAT val ) = 0;
    virtual void write( t_CKFLOAT val, t_CKINT flags ) = 0;
    virtual void write( const t_CKCOMPLEX & val ) = 0;
    virtual void write( const t_CKCOMPLEX & val, t_CKINT flags ) = 0;
    virtual void write( const t_CKPOLAR & val ) = 0;
    virtual void write( const t_CKPOLAR & val, t_CKINT flags ) = 0;
    virtual void write( const t_CKVEC2 & val ) = 0;
    virtual void write( const t_CKVEC2 & val, t_CKINT flags ) = 0;
    virtual void write( const t_CKVEC3 & val ) = 0;
    virtual void write( const t_CKVEC3 & val, t_CKINT flags ) = 0;
    virtual void write( const t_CKVEC4 & val ) = 0;
    virtual void write( const t_CKVEC4 & val, t_CKINT flags ) = 0;

public:
    // type | moved to IO in 1.5.0.0 (ge)
    static const t_CKINT TYPE_ASCII;
    static const t_CKINT TYPE_BINARY;
    // datatype
    static const t_CKINT INT8;
    static const t_CKINT INT16;
    static const t_CKINT INT24; // 1.5.0.1 (ge) added
    static const t_CKINT INT32;
    static const t_CKINT INT64; // 1.5.0.1 (ge) added
    // 1.5.0.1 (ge) added SINT and UINT type flags
    static const t_CKINT SINT8;
    static const t_CKINT SINT16;
    static const t_CKINT SINT24;
    static const t_CKINT SINT32;
    static const t_CKINT SINT64;
    static const t_CKINT UINT8;
    static const t_CKINT UINT16;
    static const t_CKINT UINT24;
    static const t_CKINT UINT32;
    static const t_CKINT UINT64;
    // 1.5.0.1 (ge) added FLOAT type flags
    static const t_CKINT FLOAT32;
    static const t_CKINT FLOAT64;
    // flags | moved to IO in 1.5.0.0 (ge)
    static const t_CKINT FLAG_READ_WRITE;
    static const t_CKINT FLAG_READONLY;
    static const t_CKINT FLAG_WRITEONLY;
    static const t_CKINT FLAG_APPEND;
    // asynchronous I/O members
    static const t_CKINT MODE_SYNC;
    static const t_CKINT MODE_ASYNC;

    Chuck_Event * m_asyncEvent;
#ifndef __DISABLE_THREADS__
    XThread * m_thread;
#endif
    struct async_args
    {
        Chuck_IO_File * fileio_obj;
        void * RETURN; // actually a Chuck_DL_Return
        t_CKINT intArg;
        t_CKFLOAT floatArg;
        std::string stringArg;
    };
};




#ifndef __PLATFORM_WINDOWS__
#include <dirent.h>
#else
struct DIR;
#endif

//-----------------------------------------------------------------------------
// name: Chuck_IO_File
// desc: Chuck File IO class
//-----------------------------------------------------------------------------
struct Chuck_IO_File : public Chuck_IO
{
public:
    // REFACTOR-2017
    Chuck_IO_File( Chuck_VM * vm );
    virtual ~Chuck_IO_File();

public:
    // meta
    virtual t_CKBOOL open( const std::string & path, t_CKINT flags );
    virtual t_CKBOOL good();
    virtual void close();
    virtual void flush();
    virtual t_CKINT mode();
    virtual void mode( t_CKINT flag );
    virtual t_CKINT size();

    // seeking
    virtual void seek( t_CKINT pos );
    virtual t_CKINT tell();

    // directories
    virtual t_CKINT isDir();
    virtual Chuck_ArrayInt * dirList();

    // reading
    // virtual Chuck_String * read( t_CKINT length );
    virtual Chuck_String * readLine();
    virtual t_CKINT readInt( t_CKINT flags );
    virtual t_CKFLOAT readFloat();
    virtual t_CKFLOAT readFloat( t_CKINT flags );
    virtual t_CKBOOL readString( std::string & str );
    virtual t_CKBOOL eof();

    // reading -- async
    /* TODO: doesn't look like asynchronous reads will work
     static THREAD_RETURN ( THREAD_TYPE read_thread ) ( void *data );
     static THREAD_RETURN ( THREAD_TYPE readLine_thread ) ( void *data );
     static THREAD_RETURN ( THREAD_TYPE readInt_thread ) ( void *data );
     static THREAD_RETURN ( THREAD_TYPE readFloat_thread ) ( void *data );
     */

     // writing
    virtual void write( const std::string & val );
    virtual void write( t_CKINT val );
    virtual void write( t_CKINT val, t_CKINT flags );
    virtual void write( t_CKFLOAT val );
    virtual void write( t_CKFLOAT val, t_CKINT flags );
    virtual void write( const t_CKCOMPLEX & val );
    virtual void write( const t_CKCOMPLEX & val, t_CKINT flags );
    virtual void write( const t_CKPOLAR & val );
    virtual void write( const t_CKPOLAR & val, t_CKINT flags );
    virtual void write( const t_CKVEC2 & val );
    virtual void write( const t_CKVEC2 & val, t_CKINT flags );
    virtual void write( const t_CKVEC3 & val );
    virtual void write( const t_CKVEC3 & val, t_CKINT flags );
    virtual void write( const t_CKVEC4 & val );
    virtual void write( const t_CKVEC4 & val, t_CKINT flags );

#ifndef __DISABLE_THREADS__
    // writing -- async
    static THREAD_RETURN( THREAD_TYPE writeStr_thread ) (void * data);
    static THREAD_RETURN( THREAD_TYPE writeInt_thread ) (void * data);
    static THREAD_RETURN( THREAD_TYPE writeFloat_thread ) (void * data);
#endif

    // get filename
    std::string filename() const { return m_path; }

protected:
    // open flags
    t_CKINT m_flags;
    // I/O mode
    t_CKINT m_iomode;
    // file stream
    std::fstream m_io;
    // directory pointer
    DIR * m_dir;
    // directory location
    long m_dir_start;
    // path
    std::string m_path;
    // vm and shred
    Chuck_VM * m_vmRef;

public:
    // auto prefix | 1.5.1.5
    std::string m_autoPrefix;
    // auto extension | 1.5.1.5
    std::string m_autoExtension;
};




//-----------------------------------------------------------------------------
// name: Chuck_IO_Chout
// desc: Chuck console IO out
//-----------------------------------------------------------------------------
struct Chuck_IO_Chout : public Chuck_IO
{
public:
    Chuck_IO_Chout( Chuck_Carrier * carrier );
    virtual ~Chuck_IO_Chout();

public:
    // meta
    virtual t_CKBOOL good();
    virtual void close();
    virtual void flush();
    virtual t_CKINT mode();
    virtual void mode( t_CKINT flag );

    // reading
    virtual Chuck_String * readLine();
    virtual t_CKINT readInt( t_CKINT flags );
    virtual t_CKFLOAT readFloat();
    virtual t_CKFLOAT readFloat( t_CKINT flags );
    virtual t_CKBOOL readString( std::string & str );
    virtual t_CKBOOL eof();

    // writing
    virtual void write( const std::string & val );
    virtual void write( t_CKINT val );
    virtual void write( t_CKINT val, t_CKINT flags );
    virtual void write( t_CKFLOAT val );
    virtual void write( t_CKFLOAT val, t_CKINT flags );
    virtual void write( const t_CKCOMPLEX & val );
    virtual void write( const t_CKCOMPLEX & val, t_CKINT flags );
    virtual void write( const t_CKPOLAR & val );
    virtual void write( const t_CKPOLAR & val, t_CKINT flags );
    virtual void write( const t_CKVEC2 & val );
    virtual void write( const t_CKVEC2 & val, t_CKINT flags );
    virtual void write( const t_CKVEC3 & val );
    virtual void write( const t_CKVEC3 & val, t_CKINT flags );
    virtual void write( const t_CKVEC4 & val );
    virtual void write( const t_CKVEC4 & val, t_CKINT flags );

public: // REFACTOR-2017
    // set callback
    void set_output_callback( void (*fp)(const char *) );

private:
    // callback
    void (*m_callback)(const char *);
    // intermediate line storage
    std::stringstream m_buffer;
};




//-----------------------------------------------------------------------------
// name: Chuck_IO_Cherr
// desc: Chuck console IO err
//-----------------------------------------------------------------------------
struct Chuck_IO_Cherr : public Chuck_IO
{
public:
    Chuck_IO_Cherr( Chuck_Carrier * carrier );
    virtual ~Chuck_IO_Cherr();

public:
    // meta
    virtual t_CKBOOL good();
    virtual void close();
    virtual void flush();
    virtual t_CKINT mode();
    virtual void mode( t_CKINT flag );

    // reading
    virtual Chuck_String * readLine();
    virtual t_CKINT readInt( t_CKINT flags );
    virtual t_CKFLOAT readFloat();
    virtual t_CKFLOAT readFloat( t_CKINT flags );
    virtual t_CKBOOL readString( std::string & str );
    virtual t_CKBOOL eof();

    // writing
    virtual void write( const std::string & val );
    virtual void write( t_CKINT val );
    virtual void write( t_CKINT val, t_CKINT flags );
    virtual void write( t_CKFLOAT val );
    virtual void write( t_CKFLOAT val, t_CKINT flags );
    virtual void write( const t_CKCOMPLEX & val );
    virtual void write( const t_CKCOMPLEX & val, t_CKINT flags );
    virtual void write( const t_CKPOLAR & val );
    virtual void write( const t_CKPOLAR & val, t_CKINT flags );
    virtual void write( const t_CKVEC2 & val );
    virtual void write( const t_CKVEC2 & val, t_CKINT flags );
    virtual void write( const t_CKVEC3 & val );
    virtual void write( const t_CKVEC3 & val, t_CKINT flags );
    virtual void write( const t_CKVEC4 & val );
    virtual void write( const t_CKVEC4 & val, t_CKINT flags );

public:
    // set callback | REFACTOR-2017
    void set_output_callback( void (*fp)(const char *) );

private:
    // callback
    void (*m_callback)(const char *);
    // intermediate line storage
    std::stringstream m_buffer;
};




//-----------------------------------------------------------------------------
// io API
//-----------------------------------------------------------------------------
CK_DLL_MFUN( io_dummy_int );
CK_DLL_MFUN( io_dummy_float );
CK_DLL_MFUN( io_dummy_string );
CK_DLL_MFUN( io_dummy_void );
CK_DLL_SFUN( io_newline );
CK_DLL_SFUN( io_openfile );


//-----------------------------------------------------------------------------
// fileio API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( fileio_ctor );
CK_DLL_DTOR( fileio_dtor );
CK_DLL_MFUN( fileio_open );
CK_DLL_MFUN( fileio_openflags );
CK_DLL_MFUN( fileio_good );
CK_DLL_MFUN( fileio_close );
CK_DLL_MFUN( fileio_flush );
CK_DLL_MFUN( fileio_getmode );
CK_DLL_MFUN( fileio_setmode );
CK_DLL_MFUN( fileio_size );
CK_DLL_MFUN( fileio_seek );
CK_DLL_MFUN( fileio_tell );
CK_DLL_MFUN( fileio_isdir );
CK_DLL_MFUN( fileio_dirlist );
CK_DLL_MFUN( fileio_read );
CK_DLL_MFUN( fileio_readline );
CK_DLL_MFUN( fileio_readint );
CK_DLL_MFUN( fileio_readintflags );
CK_DLL_MFUN( fileio_readint8 );
CK_DLL_MFUN( fileio_readint16 );
CK_DLL_MFUN( fileio_readint32 );
CK_DLL_MFUN( fileio_readfloat );
CK_DLL_MFUN( fileio_readfloatflags );
CK_DLL_MFUN( fileio_eof );
CK_DLL_MFUN( fileio_more );
CK_DLL_MFUN( fileio_writestring );
CK_DLL_MFUN( fileio_writeint );
CK_DLL_MFUN( fileio_writeintflags );
CK_DLL_MFUN( fileio_writefloat );
CK_DLL_MFUN( fileio_writefloatflags );
CK_DLL_MFUN( file_ctrl_autoPrefixAndExtension );
CK_DLL_MFUN( file_cget_autoPrefix );
CK_DLL_MFUN( file_cget_autoExtension );
CK_DLL_MFUN( file_cget_filename );
CK_DLL_SFUN( fileio_expandpath_impl );


//-----------------------------------------------------------------------------
// chout API -- added 1.3.0.0 as full class
//-----------------------------------------------------------------------------
CK_DLL_MFUN( chout_good );
CK_DLL_MFUN( chout_close );
CK_DLL_MFUN( chout_flush );
CK_DLL_MFUN( chout_getmode );
CK_DLL_MFUN( chout_setmode );
CK_DLL_MFUN( chout_read );
CK_DLL_MFUN( chout_readline );
CK_DLL_MFUN( chout_readint );
CK_DLL_MFUN( chout_readintflags );
CK_DLL_MFUN( chout_readfloat );
CK_DLL_MFUN( chout_eof );
CK_DLL_MFUN( chout_more );
CK_DLL_MFUN( chout_writestring );
CK_DLL_MFUN( chout_writeint );
CK_DLL_MFUN( chout_writefloat );


//-----------------------------------------------------------------------------
// cherr API -- added 1.3.0.0 as full class
//-----------------------------------------------------------------------------
CK_DLL_MFUN( cherr_good );
CK_DLL_MFUN( cherr_close );
CK_DLL_MFUN( cherr_flush );
CK_DLL_MFUN( cherr_getmode );
CK_DLL_MFUN( cherr_setmode );
CK_DLL_MFUN( cherr_read );
CK_DLL_MFUN( cherr_readline );
CK_DLL_MFUN( cherr_readint );
CK_DLL_MFUN( cherr_readintflags );
CK_DLL_MFUN( cherr_readfloat );
CK_DLL_MFUN( cherr_eof );
CK_DLL_MFUN( cherr_more );
CK_DLL_MFUN( cherr_writestring );
CK_DLL_MFUN( cherr_writeint );
CK_DLL_MFUN( cherr_writefloat );




//-----------------------------------------------------------------------------
// MidiMsg API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiMsg_ctor );

extern t_CKUINT MidiMsg_offset_data1;
extern t_CKUINT MidiMsg_offset_data2;
extern t_CKUINT MidiMsg_offset_data3;
extern t_CKUINT MidiMsg_offset_when;

#ifndef __DISABLE_MIDI__
//-----------------------------------------------------------------------------
// MidiRW API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiRW_ctor );
CK_DLL_DTOR( MidiRW_dtor );
CK_DLL_MFUN( MidiRW_open );
CK_DLL_MFUN( MidiRW_close );
CK_DLL_MFUN( MidiRW_read );
CK_DLL_MFUN( MidiRW_write );


//-----------------------------------------------------------------------------
// MidiMsgOut API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiMsgOut_ctor );
CK_DLL_DTOR( MidiMsgOut_dtor );
CK_DLL_MFUN( MidiMsgOut_open );
CK_DLL_MFUN( MidiMsgOut_close );
CK_DLL_MFUN( MidiMsgOut_write );


//-----------------------------------------------------------------------------
// MidiMsgIn API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiMsgIn_ctor );
CK_DLL_DTOR( MidiMsgIn_dtor );
CK_DLL_MFUN( MidiMsgIn_open );
CK_DLL_MFUN( MidiMsgIn_close );
CK_DLL_MFUN( MidiMsgIn_read );


//-----------------------------------------------------------------------------
// MidiIn API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiIn_ctor );
CK_DLL_DTOR( MidiIn_dtor );
CK_DLL_MFUN( MidiIn_open );
CK_DLL_MFUN( MidiIn_open_named ); // added 1.3.0.0
CK_DLL_MFUN( MidiIn_open_named_i ); // added 1.3.0.0
CK_DLL_MFUN( MidiIn_good );
CK_DLL_MFUN( MidiIn_num );
CK_DLL_MFUN( MidiIn_name );
CK_DLL_MFUN( MidiIn_printerr );
CK_DLL_MFUN( MidiIn_recv );
CK_DLL_MFUN( MidiIn_can_wait );


//-----------------------------------------------------------------------------
// MidiOut API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( MidiOut_ctor );
CK_DLL_DTOR( MidiOut_dtor );
CK_DLL_MFUN( MidiOut_open );
CK_DLL_MFUN( MidiOut_open_named ); // added 1.3.0.0
CK_DLL_MFUN( MidiOut_open_named_i); // added 1.3.0.0
CK_DLL_MFUN( MidiOut_good );
CK_DLL_MFUN( MidiOut_num );
CK_DLL_MFUN( MidiOut_name );
CK_DLL_MFUN( MidiOut_printerr );
CK_DLL_MFUN( MidiOut_send );
CK_DLL_MFUN( MidiOut_send_msg );
CK_DLL_MFUN( MidiOut_noteOn );
CK_DLL_MFUN( MidiOut_noteOff );
CK_DLL_MFUN( MidiOut_controlChange );
CK_DLL_MFUN( MidiOut_programChange );
CK_DLL_MFUN( MidiOut_pitchBend );
CK_DLL_MFUN( MidiOut_pitchBend_fine );
CK_DLL_MFUN( MidiOut_polyPressure );
CK_DLL_MFUN( MidiOut_channelPressure );
#endif // __DISABLE_MIDI__



#ifndef __DISABLE_HID__
//-----------------------------------------------------------------------------
// HidMsg API
//-----------------------------------------------------------------------------
CK_DLL_MFUN( HidMsg_is_axis_motion );
CK_DLL_MFUN( HidMsg_is_button_down );
CK_DLL_MFUN( HidMsg_is_button_up );
CK_DLL_MFUN( HidMsg_is_mouse_motion );
CK_DLL_MFUN( HidMsg_is_hat_motion );
CK_DLL_MFUN( HidMsg_is_wheel_motion );

//-----------------------------------------------------------------------------
// HidIn API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( HidIn_ctor );
CK_DLL_DTOR( HidIn_dtor );
CK_DLL_MFUN( HidIn_open );
CK_DLL_MFUN( HidIn_open_named );
CK_DLL_MFUN( HidIn_open_named_i ); // added 1.3.0.0
CK_DLL_MFUN( HidIn_open_joystick );
CK_DLL_MFUN( HidIn_open_joystick_2 );
CK_DLL_MFUN( HidIn_open_mouse );
CK_DLL_MFUN( HidIn_open_mouse_2 );
CK_DLL_MFUN( HidIn_open_keyboard );
CK_DLL_MFUN( HidIn_open_keyboard_2 );
CK_DLL_MFUN( HidIn_open_tiltsensor );
CK_DLL_MFUN( HidIn_good );
CK_DLL_MFUN( HidIn_num );
CK_DLL_MFUN( HidIn_name );
CK_DLL_MFUN( HidIn_printerr );
CK_DLL_MFUN( HidIn_recv );
CK_DLL_MFUN( HidIn_read );
CK_DLL_MFUN( HidIn_send );
CK_DLL_MFUN( HidIn_can_wait );
CK_DLL_SFUN( HidIn_read_tilt_sensor );
CK_DLL_SFUN( HidIn_ctrl_tiltPollRate );
CK_DLL_SFUN( HidIn_cget_tiltPollRate );
CK_DLL_SFUN( HidIn_start_cursor_track );
CK_DLL_SFUN( HidIn_stop_cursor_track );


//-----------------------------------------------------------------------------
// HidOut API
//-----------------------------------------------------------------------------
CK_DLL_CTOR( HidOut_ctor );
CK_DLL_DTOR( HidOut_dtor );
CK_DLL_MFUN( HidOut_open );
CK_DLL_MFUN( HidOut_good );
CK_DLL_MFUN( HidOut_num );
CK_DLL_MFUN( HidOut_name );
CK_DLL_MFUN( HidOut_printerr );
CK_DLL_MFUN( HidOut_send );

CK_DLL_CTOR( MouseCursor_ctor );
CK_DLL_DTOR( MouseCursor_dtor );
CK_DLL_SFUN( MouseCursor_scaled );
CK_DLL_SFUN( MouseCursor_abs );
CK_DLL_SFUN( MouseCursor_abs_x );
CK_DLL_SFUN( MouseCursor_abs_y );

CK_DLL_CTOR( Mousor_ctor );
CK_DLL_DTOR( Mousor_dtor );

#endif // __DISABLE_HID__1




#ifndef __DISABLE_SERIAL__
//-----------------------------------------------------------------------------
// name: struct Chuck_IO_Serial
// desc: chuck serial I/O
//-----------------------------------------------------------------------------
struct Chuck_IO_Serial : public Chuck_IO
{
public:
    Chuck_IO_Serial( Chuck_VM * vm );
    virtual ~Chuck_IO_Serial();

    static void shutdown();

public:
    // meta
    virtual t_CKBOOL open( const t_CKUINT i, t_CKINT flags, t_CKUINT baud = CK_BAUD_9600 );
    virtual t_CKBOOL open( const std::string & path, t_CKINT flags, t_CKUINT baud = CK_BAUD_9600 );

    virtual t_CKBOOL can_wait();

    virtual t_CKBOOL good();
    virtual void close();
    virtual void flush();
    virtual t_CKINT mode();
    virtual void mode( t_CKINT flag );

    // reading
    virtual Chuck_String * readLine();
    virtual t_CKINT readInt( t_CKINT flags );
    virtual t_CKFLOAT readFloat();
    virtual t_CKFLOAT readFloat( t_CKINT flags );
    virtual t_CKBOOL readString( std::string & str );
    virtual t_CKBOOL eof();

    // writing
    virtual void write( const std::string & val );
    virtual void write( t_CKINT val );
    virtual void write( t_CKINT val, t_CKINT flags );
    virtual void writeBytes( Chuck_ArrayInt * arr );
    virtual void write( t_CKFLOAT val );
    virtual void write( t_CKFLOAT val, t_CKINT flags );
    virtual void write( const t_CKCOMPLEX & val );
    virtual void write( const t_CKCOMPLEX & val, t_CKINT flags );
    virtual void write( const t_CKPOLAR & val );
    virtual void write( const t_CKPOLAR & val, t_CKINT flags );
    virtual void write( const t_CKVEC2 & val );
    virtual void write( const t_CKVEC2 & val, t_CKINT flags );
    virtual void write( const t_CKVEC3 & val );
    virtual void write( const t_CKVEC3 & val, t_CKINT flags );
    virtual void write( const t_CKVEC4 & val );
    virtual void write( const t_CKVEC4 & val, t_CKINT flags );

    // serial stuff
    virtual t_CKBOOL setBaudRate( t_CKUINT rate );
    virtual t_CKUINT getBaudRate();

    // async reading
    virtual t_CKBOOL readAsync( t_CKUINT type, t_CKUINT num );
    virtual Chuck_String * getLine();
    virtual t_CKINT getByte();
    virtual Chuck_Array * getBytes();
    virtual Chuck_Array * getInts();
    virtual Chuck_Array * getFloats();
    virtual Chuck_String * getString();

    static const t_CKUINT TYPE_NONE;
    static const t_CKUINT TYPE_BYTE;
    static const t_CKUINT TYPE_WORD;
    static const t_CKUINT TYPE_INT;
    static const t_CKUINT TYPE_FLOAT;
    static const t_CKUINT TYPE_STRING;
    static const t_CKUINT TYPE_LINE;
    static const t_CKUINT TYPE_WRITE;

    struct Request
    {
        t_CKUINT m_type; // type
        t_CKUINT m_num; // how many
        t_CKUINT m_status;
        t_CKUINT m_val; // ISSUE: 64-bit

        enum Status
        {
            RQ_STATUS_PENDING,
            RQ_STATUS_SUCCESS,
            RQ_STATUS_FAILURE,
            RQ_STATUS_INVALID,
            RQ_STATUS_EOF,
        };
    };

    virtual t_CKBOOL ready();

    // available baud rates
    static const t_CKUINT CK_BAUD_2400;
    static const t_CKUINT CK_BAUD_4800;
    static const t_CKUINT CK_BAUD_9600;
    static const t_CKUINT CK_BAUD_19200;
    static const t_CKUINT CK_BAUD_38400;
    static const t_CKUINT CK_BAUD_7200;
    static const t_CKUINT CK_BAUD_14400;
    static const t_CKUINT CK_BAUD_28800;
    static const t_CKUINT CK_BAUD_57600;
    static const t_CKUINT CK_BAUD_76800;
    static const t_CKUINT CK_BAUD_115200;
    static const t_CKUINT CK_BAUD_230400;

protected:

    void start_read_thread();
    XThread * m_read_thread;
    static void *shell_read_cb(void *);
    void read_cb();

    XThread * m_write_thread;
    static void *shell_write_cb(void *);
    void write_cb();

    void close_int();

    t_CKBOOL get_buffer(t_CKINT timeout_ms = 1);
    t_CKINT peek_buffer();
    t_CKINT pull_buffer();
    t_CKINT buffer_bytes_to_tmp(t_CKINT num_bytes);

    t_CKBOOL handle_line(Request &);
    t_CKBOOL handle_string(Request &);
    t_CKBOOL handle_float_ascii(Request &);
    t_CKBOOL handle_int_ascii(Request &);
    t_CKBOOL handle_byte(Request &);
    t_CKBOOL handle_float_binary(Request &);
    t_CKBOOL handle_int_binary(Request &);

    bool m_do_read_thread;
    bool m_do_write_thread;

    CircularBuffer<Request> m_asyncRequests;
    CircularBuffer<Request> m_asyncResponses;
    CBufferSimple * m_event_buffer;

    int m_fd;
    FILE * m_cfd;

    std::string m_path;

    unsigned char * m_io_buf;
    t_CKUINT m_io_buf_max;
    t_CKUINT m_io_buf_available;
    t_CKUINT m_io_buf_pos;

    unsigned char * m_tmp_buf;
    t_CKUINT m_tmp_buf_max;

    CircularBuffer<Request> m_asyncWriteRequests;
    CircularBuffer<char> m_writeBuffer;

    t_CKINT m_flags;
    t_CKINT m_iomode; // SYNC or ASYNC
    t_CKBOOL m_eof;

    t_CKBOOL m_do_exit;

    static std::list<Chuck_IO_Serial *> s_serials;

    Chuck_VM * m_vmRef;
};
#endif // __DISABLE_SERIAL__





#endif // __CHUCK_IO_H__
