/* aguix.h
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2026 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License 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,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef AGUIX_H
#define AGUIX_H

#include "aguixdefs.h"
#include "lowlevelfunc.h"
#include "message.h"
#include "util.h"
#include "refcount.hh"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>

#ifdef HAVE_XFT
#include <X11/Xft/Xft.h>
#endif

#include <map>
#include <list>
#include <atomic>
#include <memory>
#include <functional>

#include "aguixfont.hh"
#include "aguixcolor.hh"
#include "backgroundmessagehandler.hh"

#include "faces.hh"

class AWindow;
class PopUpWindow;
class BubbleWindow;
class TimeoutStore;

enum {MES_WAIT,MES_GET};
enum {NON_GADGET,CLOSE_GADGET,BUTTON_GADGET,SHADOW_GADGET,CHOOSE_GADGET,LISTVIEW,ONELVC,MORELVC,STRING_GADGET};

struct AGUIX_XProperty {
    AGUIX_XProperty() : success( true ),
                        property_data( NULL ),
                        type( None ),
                        format( 0 ),
                        number_of_items( 0 )
    {}

    void freeProperty()
    {
        if ( property_data ) {
            XFree( property_data );
            property_data = NULL;
        }
    }

    bool success;
    unsigned char *property_data;
    Atom type;
	int format;
	unsigned long number_of_items;
};

class AGUIX {
public:
  AGUIX( int argc, char **argv, const std::string &classname );
  ~AGUIX();
  AGUIX( const AGUIX &other );
  AGUIX &operator=( const AGUIX &other );

  int initX();
  int checkX();
  void closeX();
  int getDepth() const;
  Colormap getColormap() const;
  Display *getDisplay() const;
  int getScreen() const;
  void panic(const char *);
  void setFG( const AGUIXColor &color );
  void setBG( const AGUIXColor &color );
  void setFG( GC gc, const AGUIXColor &color );
  void setBG( GC gc, const AGUIXColor &color );
  int getCharHeight() const;
  void FillRectangle(Drawable buffer,int x,int y,int w,int h);
  void DrawText( class DrawableCont &dc, const char *text, int x, int y, const AGUIXColor &color );
  void DrawLine(Drawable buffer,int px1,int py1,int px2,int py2);
  void DrawPoint(Drawable buffer,int x,int y);
  void FillRectangle(Drawable buffer,GC gc,int x,int y,int w,int h);
  void DrawText( class DrawableCont &dc, AGUIXFont *, const char *text, int x, int y, const AGUIXColor &color );
  void DrawLine(Drawable buffer,GC gc,int px1,int py1,int px2,int py2);
  void DrawPoint(Drawable buffer,GC gc,int x,int y);

  void DrawTriangleFilled(Drawable buffer, int px1, int py1, int px2, int py2, int px3, int py3);
  void DrawTriangleFilled(Drawable buffer, GC tgc, int px1, int py1, int px2, int py2, int px3, int py3);
  void setClip( AGUIXFont *font, class DrawableCont *dc, int x, int y, int width, int height );
  void unclip( AGUIXFont *font, class DrawableCont *dc );

  void ClearWin(Window win);
  void SetWindowBG( Window win, const AGUIXColor &color );
  int getFontBaseline() const;
  AGUIXColor AddColor( int red, int green, int blue, AGUIXColor::color_type_t type = AGUIXColor::USER_COLOR );
  void freeColors();
  int changeColor( const AGUIXColor &index, int red, int green ,int blue );
  int getNumberOfColorsForType( AGUIXColor::color_type_t type ) const;
  unsigned long getPixel( const AGUIXColor &color ) const;
#ifdef HAVE_XFT
  XftColor *getColBufEntry( const AGUIXColor &color );
#else
  unsigned long getColBufEntry( const AGUIXColor &color );
#endif

    typedef struct _col_values_t {
        _col_values_t() : red( 0 ),
                          green( 0 ),
                          blue( 0 )
        {}
        _col_values_t( int r, int g, int b) : red( r ),
                                              green( g ),
                                              blue( b )
        {}

        bool operator==( const _col_values_t &rhs )
        {
            if ( red == rhs.red &&
                 green == rhs.green &&
                 blue == rhs.blue ) {
                return true;
            } else {
                return false;
            }
        }
        
        int red, green, blue;
    } col_values_t;

    col_values_t getColorInfo( const AGUIXColor &color ) const;
    col_values_t blend( const col_values_t &lhs,
                        const col_values_t &rhs,
                        int percentage ) const;

    AGUIXColor getColor( const col_values_t &v );

  std::string getClassname() const;
  Atom *getCloseAtom();
  void insertWindow( AWindow *win, bool change_transient = false );
  void removeWindow(AWindow *win);
  AGMessage *GetMessage(AWindow *parent);
  AGMessage *WaitMessage(AWindow *parent);
  void ReplyMessage(AGMessage *);
  Message *wait4mess( int mode );
  void copyArea(Drawable source,Drawable dest,int s_x,int s_y,int width,int height,int d_x,int d_y);
  void Flush();
  int getargc() const;
  char **getargv() const;
  void putAGMsg(AGMessage *msg);
  AGMessage *getAGMsg();
  void WindowtoFront(Window);
  void WindowtoBack(Window);
  AGUIXFont *getFont( const char* );
  int setFont( const char* );
  void ExposeHandler(Message*);
  AWindow *findAWindow(Window, bool top_level);
  char *getNameOfKey(KeySym,unsigned int) const;
  Window getGroupWin() const;
  int queryPointer(Window win,int *x,int *y);
  int queryRootPointer(int *x,int *y);
  int queryPointer(Window win,int *x,int *y,unsigned int *buttons);
  void setCursor(Window win,int type);
  void unsetCursor(Window win);

    enum {
        WAIT_CURSOR = 0,
        SCROLLH_CURSOR,
        SCROLLV_CURSOR,
        SCROLLFOUR_CURSOR,
        DOUBLE_DOWN_CURSOR,
        DOUBLE_UP_CURSOR,
        DOUBLE_LEFT_CURSOR,
        DOUBLE_RIGHT_CURSOR,
        MAXCURSORS};

    enum clipboard_request_e {
        CLIPBOARD_REQUEST_STRING,
        CLIPBOARD_REQUEST_FILE_LIST
    };

    enum mouse_click_mode {
        NO_CLICK,
        NORMAL_CLICK,
        DOUBLE_CLICK,
        TRIPLE_CLICK
    };

  int startCut(GUIElement *elem,const char *buffer, bool use_clipboard);
  void cancelCut(bool use_clipboard);
  bool amiOwner(bool use_clipboard) const;
  std::string getCutBuffer(bool use_clipboard) const;
  void requestCut( Window win, bool fallback, bool use_clipboard, GUIElement *elem, void *agmessage_data, clipboard_request_e request_type );
  void rerequestCut();
  void cancelCutPaste(GUIElement *elem, bool use_clipboard);
  bool isDoubleClick(struct timeval *t1,struct timeval *t2) const;
  bool isDoubleClick( Time t1, Time t2 ) const;

  static int scaleElementsW( int wantedWidth,
			     int borderwidth,
			     int minSpace,
			     int maxSpace,
			     bool allowShrink,
			     bool allowStretch,
			     GUIElement **elem,
			     int *minWidths,
			     int nr );
  static int centerElementsY( GUIElement *element,
			      GUIElement *center2element );
  int getRootWindowWidth() const;
  int getRootWindowHeight() const;

  Pixmap createPixmap( Drawable d, int width, int height );
  void freePixmap( Pixmap p );

  void DrawDottedLine( Drawable buffer, int px1, int py1, int px2, int py2 );
  void DrawDottedRectangle( Drawable buffer, int x, int y, int w, int h );
  void setDottedFG( const AGUIXColor &color );

  void DrawDashXorLine( Drawable buffer, int px1, int py1, int px2, int py2 );
  void DrawDashXorRectangle( Drawable buffer, int x, int y, int w, int h );
  
  void DrawDashDLine( Drawable buffer, int px1, int py1, int px2, int py2 );
  void DrawDashDRectangle( Drawable buffer, int x, int y, int w, int h );
  void setDashDFG( const AGUIXColor &color );
  void setDashDBG( const AGUIXColor &color );

  static bool isModifier( KeySym key );
  static char *getStringForKeySym( KeySym key );
  static KeySym getKeySymForString( const char *str1 );
  void rebuildBackgroundPixmap();
  void setWindowBackgroundPixmap( Window win );
  void doXMsgs( AWindow *parent, bool onlyexpose );
  void doXMsgs( int mode, AWindow *parent, bool onlyexpose );
  bool noMoreMessages() const;
#ifdef USE_XIM
  XIMStyle getXIMStyle() const;
  XIM getXIM() const;
  void IMInstCallback( Display *calldsp );
  void IMDestCallback();
#endif
  void setTransientWindow( AWindow *twin = NULL );
  const AWindow* getTransientWindow() const;
  KeySym getLastKeyRelease();
  unsigned int getLastMouseRelease();
  void msgLock( Widget *e );
  void msgUnlock( const Widget *e );
  bool msgHoldsLock( const Widget *e );
  void enableTimer();
  void disableTimer();
  enum { TIMER_TICKS = 25 }; //HARDCODED

  int getTextWidth( const char *str, AGUIXFont *font = NULL );
  int getTextWidth( const char *str, AGUIXFont *font, int len );
  int getStrlen4Width( const char *str, int width, int *return_width, AGUIXFont *font = NULL );

  /**
   *
   * @param str
   * @param maxlen  use not more then len bytes (or <0 for strlen)
   */
  int getStrlen4WidthMaxlen( const char *str, int maxlen,
                             int width, int *return_width, AGUIXFont *font = NULL );

    static std::atomic< long > timerEvent;

  void drawBorder( Drawable buffer, GC usegc, bool pressed, int x, int y, int w, int h, int topright_space );
  void drawBorder( Drawable buffer, bool pressed, int x, int y, int w, int h, int topright_space );

    typedef enum { CLOSE_ATOM, NET_WM_NAME_ATOM, NET_WM_ICON_NAME_ATOM, TARGETS_ATOM,
                   NET_WM_WINDOW_TYPE, NET_WM_WINDOW_TYPE_DIALOG, NET_WM_WINDOW_TYPE_NORMAL,
                   UTF8_STRING, NET_WM_STATE, NET_WM_STATE_MAXIMIZED_HORZ,
                   NET_WM_STATE_MAXIMIZED_VERT,
                   XDNDENTER,
                   XDNDPOSITION,
                   XDNDSTATUS,
                   XDNDTYPELIST,
                   XDNDACTIONCOPY,
                   XDNDDROP,
                   XDNDLEAVE,
                   XDNDFINISHED,
                   XDNDSELECTION,
                   XDNDPROXY,
                   XDNDAWARE,
                   CARDINAL_ATOM,
                   NET_WM_ICON_ATOM,
                   CLIPBOARD
    } atom_name_t;
  Atom getAtom( atom_name_t name ) const;

  void registerPopUpWindow( PopUpWindow *win );
  void hidePopUpWindows( int group_id = -1 );
  void hideOtherPopUpWindows( int group_id = -1 );
  void popupOpened();
  void popupClosed();

  void xSync();
  
  int getWidgetRootPosition( Widget *widget, int *x, int *y );
  bool getLastTypedWindowEvent( Window win, int type, XEvent *return_event );
  int addDefaultColors();

    AWindow *getFocusedAWindow( bool top_level/* = false*/ );

    void registerBGHandler( AWindow *window, const RefCount< BackgroundMessageHandler > &handler );
    void unregisterBGHandler( AWindow *window );
    void executeBGHandlers( AGMessage &msg );
    void destroyBGHandlers();

    enum target_clipboard_buffer {
        PRIMARY_BUFFER,
        CLIPBOARD_BUFFER,
        BOTH_BUFFERS
    };

    int copyToClipboard( const std::string &s, enum target_clipboard_buffer target,
                         const std::string &mimetype = "" );
    void copyPrimaryToClipboard();
    void copyFileListToClipboard( const std::vector< std::string > &l,
                                  bool cut_operation );

    /**
     * return the location and dimension of the largest (xinerama) screen
     * under the mouse
     */
    void getLargestDimensionOfCurrentScreen( int *x, int *y,
                                             int *width, int *height );

    void setApplyWindowDialogType( bool nv );
    bool getApplyWindowDialogType() const;

    void setOverrideXIM( bool nv );
    bool getOverrideXIM() const;

    void setSkipFilterEvent( bool nv );

    void applyFaces( const FaceDB &faces );
    const FaceDB &getFaces() const
    {
        return m_faces;
    }

    int getFaceCol_default_fg() const
    {
        return m_default_fg;
    }

    int getFaceCol_default_bg() const
    {
        return m_default_bg;
    }

    int getFaceCol_3d_bright() const
    {
        return m_3d_bright;
    }

    int getFaceCol_3d_dark() const
    {
        return m_3d_dark;
    }

    void setBubbleHelpWindow( std::shared_ptr< BubbleWindow > bw );
    void setBubbleHelpCandidate( GUIElement *elem );
    void clearBubbleHelpCandidate( GUIElement *elem = NULL);

    void setExternalTimeoutStore( std::weak_ptr< TimeoutStore > timeout_store );

    void external_timeout_callback();

    bool isValidScreenPosition( int x, int y,
                                int w, int h );

    void startXDND( Widget *initiator,
                    Window w,
                    unsigned int mouse_button,
                    unsigned int cancel_mouse_button );

    void widgetDestroyed( Widget *w );

    int getCurrentUserColorInstance() const;

    bool isModifierPressed( unsigned int mask ) const;
    bool lastClickModifier( unsigned int mask ) const;

    void setStandardIconData( const unsigned long *data,
                              size_t data_length );
    bool getStandardIconData( const unsigned long **return_data,
                              size_t *return_data_length ) const;

    void closeBubbleHelp( AWindow *awin );

    void pushPostMsgHandlerCB( std::function< void(void) > f );
    void executeAfterMsgHandler( std::function< void(void) > f );
private:
  Display *dsp;
  int scr;
  Colormap cmap;
  GC gc, dotted_gc, dashxor_gc, dashdouble_gc;
  Atom WM_delete_window,
      XA_NET_WM_NAME,
      XA_NET_WM_ICON_NAME,
      XA_TARGETS,
      XA_NET_WM_WINDOW_TYPE,
      XA_NET_WM_WINDOW_TYPE_DIALOG,
      XA_NET_WM_WINDOW_TYPE_NORMAL,
      XA_UTF8_STRING,
      XA_NET_WM_STATE,
      XA_NET_WM_STATE_MAXIMIZED_HORZ,
      XA_NET_WM_STATE_MAXIMIZED_VERT,
      XA_XDNDENTER,
      XA_XDNDPOSITION,
      XA_XDNDSTATUS,
      XA_XDNDTYPELIST,
      XA_XDNDACTIONCOPY,
      XA_XDNDDROP,
      XA_XDNDLEAVE,
      XA_XDNDFINISHED,
      XA_XDNDSELECTION,
      XA_XDNDPROXY,
      XA_XDNDAWARE,
      XA_MULTIPLE,
      XA_TEXT_URI_LIST,
      XA_TEXT_PLAIN,
      XA_NET_WM_ICON,
      XA_CARDINAL_ATOM,
      XA_CLIPBOARD,
      XA_SPECIAL_COPIED_FILES,
      XA_INCR;

  std::map< std::string, Atom > m_extra_atoms;

  int m_argc;
  char **m_argv;
  std::string m_classname;
  unsigned long white,black;
  AGUIXFont *mainfont;
  int initOK;
  int CharHeight;
#ifdef HAVE_XFT
  XftColor m_user_col_buf[256];
  XftColor m_system_col_buf[16];
    std::vector< XftColor > m_extra_col_buf;
#else
  unsigned long m_user_col_buf[256];
  unsigned long m_system_col_buf[16];
    std::vector< unsigned long > m_extra_col_buf;
#endif
    int m_user_colors, m_system_colors, m_extra_colors;

  std::map< AGUIXColor, col_values_t > m_color_values;

  XEvent LastEvent;
  std::list<AWindow*> wins;
  typedef std::list<AWindow*>::const_iterator wins_cit_t;
  typedef std::list<AWindow*>::iterator wins_it_t;
  
  std::list<AGMessage*> messages;
  typedef std::list<AGMessage*>::const_iterator agmessage_list_cit_t;
  typedef std::list<AGMessage*>::iterator agmessage_list_it_t;
  
  std::list<AGUIXFont*> fonts;
  typedef std::list<AGUIXFont*>::const_iterator aguixfont_list_cit_t;
  typedef std::list<AGUIXFont*>::iterator aguixfont_list_it_t;

  std::list<PopUpWindow*> popup_wins;
  typedef std::list<PopUpWindow*>::const_iterator popup_wins_cit_t;
  typedef std::list<PopUpWindow*>::iterator popup_wins_it_t;

  std::list<AWindow*> wins_as_transient_for;
  
  Window groupwin;
  void createGroupWin();
  void destroyGroupWin();
  
  bool ReactMessage(Message*,AWindow*);
  void buildAGMessage( Message *agmsg );
  
  bool privatecmap;
  void changeColormap();
  void updateSystemColors( int changed_user_color );

  Cursor cursors[MAXCURSORS];

  unsigned int rootWindowWidth, rootWindowHeight;
  Pixmap backpm;
#ifdef USE_XIM
  XIM inputmethod;
  XIMStyle im_style;

  int openIM();
  void closeIM();
#endif
  char *keybuf;
  int keybuf_len;

  AWindow *transientwindow;
  KeySym lastkeyrelease;
  unsigned int lastmouserelease;

  Widget *msgLockElement;
  bool timerEnabled;
#ifndef USE_AGUIXTIMER
  struct timeval timerStart;
#endif
  int msgHandler( int mode, AWindow *parent, bool onlyExpose );
  long lastTimerEventNr;

  void checkPopUpWindows( Message * );

  bool waitForEventOnFD( int ms );

    AGUIX_XProperty getProperty( Window win,
                                 Atom property );
    Atom selectBestTargetForDND( Atom type1,
                                 Atom type2,
                                 Atom type3 );
    Atom selectBestTargetForDND( AGUIX_XProperty type_list );
    Atom selectBestTargetForDND( const std::vector< Atom > &list );

    void handleXDNDEnter( XEvent *e );
    void handleXDNDPosition( XEvent *e );
    void handleXDNDLeave( XEvent *e );
    void handleXDNDDrop( XEvent *e );
    void handleXDNDStatus( XEvent *e );
    void handleXDNDFinished( XEvent *e );
    void cleanupDND();
    void abortDND();

    void initXDNDTypes();

    void processSelectionRequest( XEvent *e );
    void setTargetsProperty( Window w, Atom property );
    Window findXDNDAwareWindow( Window w, Window *return_proxy_window );

    std::tuple< int, std::string, std::vector< std::string > > convertPasteDataToFileList( const unsigned char *data );
  int m_open_popup_counter;
  bool m_popup_ignore_button_release;

  Window m_current_xfocus_window;

    /* background handler for some window */
    std::map< AWindow *, RefCount< BackgroundMessageHandler > > m_bg_handlers;

    /* temporary list for unregister to cleanup handler after execution */
    std::list< RefCount< BackgroundMessageHandler > > m_bg_handler_cleanup_list;
    std::list< AWindow *> m_bg_handler_erase_handler;

    struct copy_requestor_state {
        Window requestor_window = None;
        Atom property = None;
        Atom target_atom = None;
        size_t buffer_pos = 0;
        bool in_progress = false;
        std::string buffer_string;
        time_t last_update = 0;
    };

    class copy_and_paste_state {
    public:
        void reset() {
            buffer_string.clear();
            file_list.clear();
            file_list_cut = false;
            last_selection_request_atom = None;
            last_selection_request_window = None;
            cutstart = NULL;
            paste_elem = NULL;
            paste_agmessage_data = NULL;
            target = None;
            requestors.clear();
        }

        std::string buffer_string;
        std::vector< std::string > file_list;
        bool file_list_cut = false;
        Atom target = None;

        Atom last_selection_request_atom = None;
        Window last_selection_request_window = None;

        GUIElement *cutstart = NULL;
        GUIElement *paste_elem = NULL;
        void *paste_agmessage_data = NULL;

        std::list< struct copy_requestor_state > requestors;
        copy_requestor_state not_found;

        copy_requestor_state &find_requestor( Window requestor );
        void remove_requestor( Window requestor );
        void cleanup_old_requestor( time_t now );
    };

    copy_and_paste_state m_primary_buffer_state;
    copy_and_paste_state m_clipboard_state;
    
    bool m_apply_window_dialog_type;

    bool m_override_xim;
    bool m_skip_filter_event;

    int m_filtered_key_events_in_a_row;

    FaceDB m_faces;

    int m_default_fg;
    int m_default_bg;
    int m_3d_bright;
    int m_3d_dark;

    struct bubble_help_data {
        bubble_help_data() : help_candidate( NULL ),
                             enter_time{ 0, 0 }
        {}
        std::shared_ptr< BubbleWindow > bubble_help_window;
        GUIElement *help_candidate;
        struct timeval enter_time;
    } m_bubble_help;

    time_t now;

    struct aguix_timeouts {
        aguix_timeouts() : timeout_set( false )
        {}

        ~aguix_timeouts()
        {
            disableExternalTimer();
        }

        std::weak_ptr< TimeoutStore > timeout_store;
        bool timeout_set;

        void enableExternalTimer();
        void disableExternalTimer();
    } m_external_timeouts;

    struct aguix_xdnd_state {
        aguix_xdnd_state() : drop_active( false ),
                             source( None ),
                             selected_target( None ),
                             last_activity( 0 ),
                             version( 0 ),
                             target_awin( NULL ),
                             sent_target_request( false ),
                             target_widget( NULL ),
                             drag_active( false ),
                             drag_target_status( AGUIX_XDND_UNAWARE ),
                             drag_initiator( NULL ),
                             drag_initiator_window( None ),
                             drag_current_target_window( None ),
                             drag_current_target_version( -1 ),
                             drag_current_proxy_target_window( None ),
                             drag_selection_pending( false ),
                             drop_issued( false ),
                             mouse_button( Button1 ),
                             cancel_mouse_button( Button3 ),
                             skip_release_count( 0 ),
                             position_silent( false ),
                             position_silent_x( 0 ),
                             position_silent_y( 0 ),
                             position_silent_w( 0 ),
                             position_silent_h( 0 )
        {}

        enum xdnd_target_status {
            AGUIX_XDND_UNAWARE,
            AGUIX_XDND_UNRESPONSIVE,
            AGUIX_XDND_ACCEPT
        };

        bool drop_active;
        Window source;
        Atom selected_target;
        time_t last_activity;
        int version;
        AWindow *target_awin;
        bool sent_target_request;
        Widget *target_widget;

        bool drag_active;
        enum xdnd_target_status drag_target_status;
        Widget *drag_initiator;
        Window drag_initiator_window;
        Window drag_current_target_window;
        int drag_current_target_version;

        Window drag_current_proxy_target_window;

        bool drag_selection_pending;
        bool drop_issued;

        unsigned int mouse_button;
        unsigned int cancel_mouse_button;
        int skip_release_count;

        bool position_silent;
        int position_silent_x;
        int position_silent_y;
        int position_silent_w;
        int position_silent_h;
    }  m_xdnd;

    std::map< std::string, int > m_xdnd_receive_types;

    Cursor m_xcursor_plus;
    Cursor m_xcursor_circle;

    int m_x_fd;

    int m_user_color_instance;

    unsigned int m_modifier_pressed = 0;
    unsigned int m_last_click_modifier = 0;

    const unsigned long *m_net_wm_icon_data = NULL;
    size_t m_net_wm_icon_data_length = 0;

    bool msg_handler_active = false;

    std::list< std::function< void(void) > > m_post_msg_handler_cbs;

    long m_max_chunk_size = 0;
};

#endif

/* Local Variables: */
/* mode:c++ */
/* End: */
