/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef NMM_X_VIRTUAL_IMG_HPP
#define NMM_X_VIRTUAL_IMG_HPP NMM_X_VIRTUAL_IMG_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/Result.hpp"

#include <string>

#include <X11/Xutil.h>

namespace NMM {
  
  class Node;
  class ShmBufferManager;
  class Buffer;
  class XProducer;
  
  /** X11 image base class.
   *
   * This class provides common functionality for X11 display windows.
   */
  class XVirtualImg {
  public:
    /** @name Constructor and Destructor
     */
    //@{
    /** Create an %XVirtualImg with the given properties.
     *
     * - Fullscreen is set to @c false
     * - The aspect ratio is @c width : @c height
     *
     * @param parent The parent %Node
     * @param width Width of the image in pixels
     * @param width Height of the image in pixels
     * @param title Window title
     */
    XVirtualImg(Node* parent, int width, int height,
                const std::string& title);

    /** Create an %XVirtualImg with the given properties.
     *
     * @param parent The parent %Node
     * @param width Width of the image in pixels
     * @param width Height of the image in pixels
     * @param ratio_x Numerator of X:Y aspect ratio
     * @param ratio_y Denominator of X:Y aspect ratio
     * @param fullscreen @c true for fullscreen, @c false for windowed mode
     * @param title Window title
     */
    XVirtualImg(Node* parent, int width, int height,
                int ratio_x, int ratio_y, bool fullscreen,
                const std::string& title);
    
    /** Virtual destructor.
     */
    virtual ~XVirtualImg();
    //@}
    
    /** @name Get/set attributes
     */
    //@{
    /** Get the parent %Node of this image.
     */
    Node* getParent() const throw();
    
    /** Get the display ID of this image.
     */
    Display* getDisplay() const throw();
    
    /** Get the window ID of this image.
     */
    Window getWindow() const throw();
    
    /** Get the width of this image in pixels.
     */
    int getWidth() const throw();
    
    /** Get the height of this image in pixels.
     */
    int getHeight() const throw();
    
    /** Get gra[hics context of this image.
     */
    GC getContext() const throw();
    
    /** Get the Y blit offset.
     */
    int getYBlitOffset() const throw();

    /** Get the Y blit offset.
     */
    int getXBlitOffset() const throw();
    
    /** Get the screen width in pixels.
     */
    int getScreenWidth() const throw();
    
    /** Get the screen height in pixels.
     */
    int getScreenHeight() const throw();
    //@}
    
    /** @name Window management
     */
    //@{
    /** Initialize window.
     *
     * This method does all the initialization of this image. It also
     * invokes initialization methods that are implemented in
     * subclasses.
     */
    void init();
    
    /** Deinitialize window.
     *
     * This method does all the deinitialization of this image. It
     * also invokes deinitialization methods that are implemented in
     * subclasses.
     */
    void deinit();
    
    /** Set image size.
     *
     * This method changes the size of this image.
     *
     * @param width New width of this image in pixels
     * @param height New height of this image in pixels
     * @return @c SUCCESS, if this method succeeds, otherwise @c FAILURE
     */
    Result setSize(int width, int height);
    
    /** Set window title
     *
     * @param title The new title of this window
     */
    void setTitle(const std::string& title);
    
    /** Set X:Y aspect ratio.
     *
     * @param ratio_x numerator of aspect ratio
     * @param ratio_y denominator aspect ratio
     */
    void setRatio(int ratio_x, int ratio_y);
    
    /** Set fullscreen mode.
     *
     * @param fullscreen @c true for fullscreen, @c false for windowed mode
     */
    void setFullscreen(bool fullscreen);
    
    void setAlignment(int i,int XPOS,int YPOS);
    //@}
    
    /** @name Cursor functions
     */
    //@{
    /** Use a dot-shaped cursor.
     */
    void useDotCursor(bool use_dot_cursor);
    
    /** Use a triangle-shaped cursor.
     */
    void useTriangleCursor(bool use_triangle_cursor);
    
    /** Use the standard cursor.
     */
    void useStandardCursor();
    //@}
    
    /** @name %Buffer management and display
     */
    //@{
    /** Update the shared memort buffer manager.
     *
     * @param manager The shared memory buffer manager
     * @param shared_pages Number of shared pages
     */
    virtual void updateMemoryManager(ShmBufferManager* manager, unsigned int shared_pages);
    
    /** Prepare display of a buffer.
     *
     * @param buffer The buffer to display
     */
    virtual void prepareOutput(Buffer* buffer) = 0;
    
    /** Display a buffer on the image.
     *
     * The buffer must have been prepared by calling prepareOutput
     * with the same @c buffer argument.
     *
     * @param buffer The buffer to display
     */
    virtual void update(Buffer*) = 0;
    
    /** Get pointer to image data.
     */
    virtual char* getImage() = 0;
    //@}
    
    /** @name Event production
     */
    //@{
    /** Enable display events.
     *
     * This method enables the %XProducer to send display events. The
     * events sent in response to keys pressed are defined in the XML
     * configuration file given by @c config_file
     *
     * @param config_file Filename of display event config file
     */
    void enableDisplayEvents(const std::string& config_file);
    
    /** Disable display events.
     *
     * This method disables sending of display events
     */
    void disableDisplayEvents();
    
    /** Set whether to send key events directly without using the %XProducer.
     *
     * @param direct_keyboard @c true to send key events directly, @c false to use the %XProducer
     */
    void setUsingKeySymKeyEvents(const bool& direct_keyboard);
    
    /** Check whether key events are sent directly.
     *
     * @return @c true if key events are sent directly, otherwise @c false
     */
    bool isUsingKeySymKeyEvents();
    
    /** Set whether to send mouse events directly.
     *
     * @param direct_keyboard @c true to send key events directly, @c false for normal mode
     */
    void setSendingMouseEventsDirect(const bool& direct_mouse);

    /** Check whether mouse events are sent directly.
     *
     * @return @c true if mouse events are sent directly, otherwise @c false
     */
    bool isSendingMouseEventsDirect();
    
    /** Set X auto-repeat mode for keys.
     *
     * If auto-repeat mode is active (which is the default), key
     * events are repeated if a key is being held.  Otherwise key
     * events are sent only when the key is pressed and released.
     *
     * @param auto_repeat @c true to enable, @c false to disable auto-repeat
     */
    void setXAutoRepeat(const bool& on);
    
    /** Check for X auto-repeat mode.
     *
     * @return @c true if auto-repeat mode is active, otherwise @c false
     */
    bool isXAutoRepeat();
    
    /** Get default event mask.
     */
    static long getEventMask();
    //@}
    
  protected:
    /** Initialize visual.
     *
     * This method sets the visual information by calling the
     * setVisualInfo method. The default implementation uses @c
     * XMatchVisualInfo to find a matching visual. Subclasses can
     * override this behavious by reimplementing this method.
     */
    virtual void initVisual();
    
    /** Deinitialize visual.
     *
     * This method is called when the visual information set by @c
     * initVisual is no longer needed.  Subclasses can implement this
     * method to free the @c XVisualInfo structure and any related
     * resources.
     */
    virtual void deinitVisual();

    /** Create the graphics context.
     *
     * This method sets the graphics context by calling the setContext
     * method. The default implementation creates a standard graphics
     * context. If any other kind of graphics context should be used
     * in a subclass, then it must reimplement this method.
     */
    virtual void initContext();
    
    /** Free the graphics context.
     *
     * This method frees the graphics context created by @c
     * initContext
     */
    virtual void deinitContext();
    
    /** Allocate image.
     *
     * This method allocates the image used to display buffers
     */
    virtual bool initImage() = 0;
    
    /** This method frees the image allocated by @c allocateImage.
     */
    virtual void deinitImage() = 0;
    
    /** Set the visual information
     *
     * This method is used by implementations of initVisual to set the
     * visual information.
     *
     * @param gc The new visual information
     */
    void setVisualInfo(XVisualInfo* visual_info) throw();

    /** Set the graphics context.
     *
     * This method is used by implementations of initContext to set
     * the graphics context.
     *
     * @param gc The new graphics context
     */
    void setContext(GC gc) throw();
    
  private:    
    /** Common initialization method called by all constructors.
     */
    void initCommon();
    
    /** Wait for X @c UnmapEvent event.
     */
    void waitForXUnmapEvent();
    
    /** Wait for X @c Expose event.
     */
    void waitForXExposureEvent();
    
    /** Wait for X @c ConfigureNotifyEvent.
     */
    void waitForXConfigureNotifyEvent();
    
    /** Calculate the screen size.
     */
    void calcScreenWidthHeight();
    
    /** Set the size hints for the window manager.
     */
    void setSizeHints();
    
    /** Set the cursor and window decoration for this window.
     *
     * This method turns both the cursor and the window decoration off
     * if the window is in fullscreen mode.
     */
    void setCursorAndDecoration();
    
    /** Create an X cursor.
     *
     * @param src The cursor image source
     * @param mask The cursor transparency mask
     * @param width The cursor width in pixels
     * @param height The cursor height in pixels
     * @return The created X11 cursor
     */
    Cursor createCursor(char* src, char* mask, int width, int height);
    
    /** Save window position before switching to fullscreen mode.
     *
     * @bug Saving the window position before switching to fullscreen is currently broken
     */
    void saveXYPosition();
    
    /** Set the window position.
     */
    void setPosition();

    /** Initialize window.
     */
    void initWindow();

    /** Deinitialize window.
     */
    void deinitWindow();

    /** Change window.
     *
     * This method is called when the window size or fullscreen flag
     * has changed.
     */
    void changeWindow();

    /** Turn cursor on/off.
     *
     * @param show @c true to show, @c false to hide cursor
     */
    void showCursor(bool show);
    
    /** Turn window decoration on/off.
     *
     * @param show @c true to show, @c false to hide window decoration
     */
    void showDecorations(bool show);
    
    /** Set EWMH fullscreen state.
     *
     * This method adds or removes the EWMH fullscreen state.
     *
     * @param fullscreen @c true for fullscreen, @c false for windowed mode
     */
    void setEWMHFullscreen(bool fullscreen);
    
    /** Fill rectangle with background color.
     *
     * This method is a wrapper for XFillRectangle which checks if the
     * coordinates are valid and otherwise draws no rectangle.
     *
     * @param x X position of upper-left corner
     * @param y Y position of upper-left corner
     * @param w Width in pixels
     * @param h Height in pixels
     */
    void fillRectangle(int x, int y, int w, int h);
    
  private:
    Node*        __parent;                 ///< The parent node
    XProducer*   __xproducer;              ///< The X producer that converts X events into NMM events
    bool         __direct_mouse;           ///< Send mouse events directly
    bool         __direct_keyboard;        ///< Send keyboard events directly
    
    int          __xpos;                   ///< X position of the window on the screen
    int          __ypos;                   ///< Y position of the window on the screen
    int          __width;                  ///< Width of the image in pixels
    int          __height;                 ///< Height of the image in pixels
    int          __ratio_x;                ///< Numerator of the X:Y aspect ratio
    int          __ratio_y;                ///< Denominator of the X:Y aspect ratio
    int          __scaled_width;           ///< Scaled width in pixels
    int          __scaled_height;          ///< Scaled height in pixels
    int          __full_screen_width;      ///< Full screen width in pixels
    int          __full_screen_height;     ///< Full screen height in pixels
    int          __screen_width;           ///< Screen width in pixels
    int          __screen_height;          ///< Screen height in pixels
    int          __x_blit_offset;          ///< x offset in pixels where buffers should be displayed on the window
    int          __y_blit_offset;          ///< Y offset in pixels where buffers should be displayed on the window
    std::string  __title;                  ///< Window title
    bool         __fullscreen;             ///< Fullscreen mode
    int          __screen;                 ///< X Screen
    int          __depth;                  ///< Color depth
    int          __align;                  ///< Left / Center / Right alignment
    bool         __have_ewmh;              ///< Have support for EWMH
    
    Display*     __display;                ///< X display ID
    Window       __win;                    ///< X window ID
    XSizeHints   __size_hints;             ///< X size hints
    GC           __gc;                     ///< X graphics context
    XVisualInfo  __own_visual_info;        ///< Default visual information
    XVisualInfo* __visual_info;            ///< Current visual information

    /** Default event mask.
     */
    static const long WINDOW_MASK = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | ExposureMask;
  };
  
  inline Node* XVirtualImg::getParent() const throw() {
    return __parent;
  }
  
  inline Display* XVirtualImg::getDisplay() const throw() {
    return __display;
  }
  
  inline Window XVirtualImg::getWindow() const throw() {
    return __win;
  }
  
  inline int XVirtualImg::getWidth() const throw() {
    return __width;
  }

  inline int XVirtualImg::getHeight() const throw() {
    return __height;
  }
  
  inline GC XVirtualImg::getContext() const throw() {
    return __gc;
  }
  
  inline int XVirtualImg::getYBlitOffset() const throw() {
    return __y_blit_offset;
  }

  inline int XVirtualImg::getXBlitOffset() const throw() {
    return __x_blit_offset;
  }
  
  inline int XVirtualImg::getScreenWidth() const throw() {
    return __screen_width;
  }
  
  inline int XVirtualImg::getScreenHeight() const throw() {
    return __screen_height;
  }
  
  inline long XVirtualImg::getEventMask() {
    return WINDOW_MASK;
  }
}

#include "nmm/nmm_suffix.hpp"

#endif
