/*
 * File Name: test_output_device.h
 */

/*
 * This file is part of uds-plugin-pdf.
 *
 * uds-plugin-pdf 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.
 *
 * uds-plugin-pdf 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, see <http://www.gnu.org/licenses/>.
 */

/**
 * Copyright (C) 2008 iRex Technologies B.V.
 * All rights reserved.
 */

#ifndef TEST_OUTPUT_DEVICE_H_
#define TEST_OUTPUT_DEVICE_H_

#include <gtk/gtkwidget.h>
#include <gdk-pixbuf/gdk-pixbuf-core.h>

namespace test
{

#define PLUGIN_ORIENTATION_LANDSCAPE    0
#define PLUGIN_ORIENTATION_PORTRAIT     1

#define MONO_COLOR_DEPTH            8
#define RGB_COLOR_DEPTH             24
#define ARGB_COLOR_DEPTH            32 
#define DEFAULT_ALPHA_VALUE         0

/// @brief Output device context.
struct OutputDeviceContext
{
    GtkWidget *widget;
    GdkGC     *gc;
};

/// @brief The widget output device. NOT SURE THE WIDGET SIZE WILL BE CHANGED OR NOT.
class OutputDevice
{
public:
    OutputDevice();
    ~OutputDevice(void);

    // Set color depth
    void set_color_depth(int c) {color_dep = c;}

    /// @brief Intialize the output device
    /// @param Output Device Context
    void map(OutputDeviceContext &context);

    /// @brief Invalidate a rectangle region
    /// @param rect The rectangle of the region
    void invalidate_rectangle(const GdkRectangle &r);

    /// @brief Clear background directly.
    /// @param color The background color.
    void clear_background(const int color = 0xff, bool flush = false);

    /// @brief Draw a line by output device.
    /// @param x1 The x-coordination of start point.
    /// @param y1 The y-coordination of srart point.
    /// @param x2 The x-coordination of end point.
    /// @param y2 The y-coordination of end point.
    void draw_line(int x1, int y1, int x2, int y2);

    /// @brief Draw highlight rectangle
    /// @param rect The GdkRectangle of the highlight area
    void draw_highlight_rectangle(const GdkRectangle &rect);

    /// @brief Copy data (2 dimensions) directly into virtual framebuffer.
    /// @param src The source data buffer.
    /// @param width The width of source data buffer.  
    /// @param row_stride number of bytes in a row.
    /// @param height The height of source data buffer.
    /// @param xDest The x destination in framebuffer.
    /// @param yDest The y destination in framebuffer.
    void draw_image(const unsigned char *src, 
                    int width, 
                    int height,
                    int row_stride,
                    int xDest = 0,
                    int yDest = 0);

    /// @brief Copy data (2 dimensions) directly into virtual framebuffer with transform.
    /// This function is helpful when caller does not want to reallocate memory.
    /// The caller should make sure the boundary should not exceed the range of framebuffer.
    /// @param src The source data buffer, which will be copied with transformation.
    /// @param width The width of source data buffer. 
    /// @param height The height of source data buffer.
    /// @param row_stride The number of bytes in a row
    /// @param xDest The absolute x destination in framebuffer.
    /// @param yDest The absolute y destination in framebuffer.
    /// The (xDest, yDest) will be left-top corner of the buffer from landscape view.
    void draw_image_with_transform(const unsigned char *src,
                                   int width, 
                                   int height,
                                   int row_stride,
                                   int xDest = 0, 
                                   int yDest = 0,
                                   int transform = PLUGIN_ORIENTATION_LANDSCAPE);

private:
    /// @brief Update the shared image so that it always has the same size 
    /// as the associated widget.
    void update_shared_image(GtkWidget *widget);

    /// @brief Update the shared image so that it fits for the appropriate
    /// size.
    void update_shared_image(int width, int height);

    /// @brief Transform the bitmap
    /// Transform the bitmap with the same color depth
    bool transform_bitmap_with_same_depth(const unsigned char *src,
                                          unsigned char *dst,
                                          int width,
                                          int height, 
                                          int row_stride,
                                          int transform = 
                                              PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 8-depth to 24-depth
    bool transform_bitmap_MONO_to_RGB(const unsigned char *src,
                                      unsigned char *dst,
                                      int width,
                                      int height, 
                                      int row_stride,
                                      int transform = 
                                          PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 8-depth to 32-depth
    bool transform_bitmap_MONO_to_ARGB(const unsigned char *src,
                                       unsigned char *dst,
                                       int width,
                                       int height, 
                                       int row_stride,
                                       int transform = 
                                           PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 24-depth to 8-depth
    bool transform_bitmap_RGB_to_MONO(const unsigned char *src,
                                      unsigned char *dst,
                                      int width,
                                      int height, 
                                      int row_stride,
                                      int transform = 
                                          PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 24-depth to 32-depth
    bool transform_bitmap_RGB_to_ARGB(const unsigned char *src,
                                      unsigned char *dst,
                                      int width,
                                      int height, 
                                      int row_stride,
                                      int transform = 
                                          PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 32-depth to 8-depth
    bool transform_bitmap_ARGB_to_MONO(const unsigned char *src,
                                       unsigned char *dst,
                                       int width,
                                       int height, 
                                       int row_stride,
                                       int transform = 
                                           PLUGIN_ORIENTATION_PORTRAIT);

    /// Transform the bitmap from 32-depth to 24-depth
    bool transform_bitmap_ARGB_to_RGB(const unsigned char *src,
                                      unsigned char *dst,
                                      int width,
                                      int height, 
                                      int row_stride,
                                      int transform = 
                                          PLUGIN_ORIENTATION_PORTRAIT);

private:
    // The widget reference.
    OutputDeviceContext ctx;

    // Draw on the shared image.
    GdkImage  *shared_image;

    // Current color depth
    int       color_dep;

    // XOR GC
    GdkGC     *xor_gc;

};

}; //namespace test

#endif


