/*
 * File Name: image_page.h
 */

/*
 * This file is part of uds-plugin-comics.
 *
 * uds-plugin-images 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-images 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 _IMAGE_PAGE_H_
#define _IMAGE_PAGE_H_

#include <string>
#include <gdk-pixbuf/gdk-pixbuf-core.h>

#include "plugin_type.h"
#include "images_document.h"

namespace comics
{

static const int DEFAULT_COLOR_DEPTH = 8;

static const float DEFAULT_ZOOM_FACTOR = 100.0f;

static const PluginRotationDegree DEFAULT_ROTATION = Clockwise_Degrees_0;

/// Represent render attributes.
struct ImagePageAttrs
{
    int original_width;         ///< The original image width.
    int original_height;        ///< The original image height.
    int desired_width;          ///< The desired image width.
    int desired_height;         ///< The desired image height.
    int row_stride;             ///< Image width 4 bytes alignment.
    int original_color_depth;   ///< The original color depth.
    int desired_color_depth;    ///< The desired color depth.
    float zoom;                 ///< The zoom factor.
    // Quick fix for tracker 0003079: When opening an image it doesn't autorotate to the best fit.
    //   Added final_rotation which is rotation as requested by uds + autorotate as decided by plugin.
    //   When implementing tracker item 0002533: Auto-rotate content to fit aspect ratio
    //   the final_rotation member variable becomes useless and must be removed.
    PluginRotationDegree rotation;       ///< The rotation as requested by uds.
    PluginRotationDegree final_rotation; ///< The rotation as decided by plugin.
    unsigned char *data;        ///< Image data.

    /// Default constructor.
    ImagePageAttrs()
        : original_width(0)
        , original_height(0)
        , desired_width(0)
        , desired_height(0)
        , row_stride(0)
        , original_color_depth(0)
        , desired_color_depth(DEFAULT_COLOR_DEPTH)
        , zoom(DEFAULT_ZOOM_FACTOR)
        , rotation(DEFAULT_ROTATION)
        , final_rotation(DEFAULT_ROTATION)
        , data(0)
    {}

    /// Operator =
    inline ImagePageAttrs & operator = (const ImagePageAttrs & right)
    {
        if (this != &right)
        {
            original_width = right.original_width;
            original_height = right.original_height;
            desired_width = right.desired_width;
            desired_height = right.desired_height;
            row_stride = right.row_stride;
            desired_color_depth = right.desired_color_depth;
            zoom = right.zoom;
            rotation = right.rotation;
            final_rotation = right.final_rotation;
            data = right.data;
        }
        return *this;
    }
};

/// Represent each image. Through this class, caller is able to
/// - Load a image.
/// - Check the image state is valid or not.
/// - Render a image with desired width, height and zoom factor.
/// - Rotate a image.
/// - Reference the raw image buffer.
/// This class is designed to work in different thread, which means
/// it can work in glib main thread or worker thread. But this class
/// is not thread safety. The caller should make sure use it in thread
/// safety environment.
class ImagePage
{
public:
    ImagePage(ImagesDocument *doc,
              const std::string & p,
              const ImagePageAttrs & request);
    ~ImagePage(void);

public:
    /// Render image with specified request.
    bool render(void);

    /// Retrieve the attributes of render result.
    const ImagePageAttrs & attributes() const { return attrs; }

    /// Retrieve the image path.
    const std::string & get_path() const { return path; }

    static int max_zoom_factor() { return 400; }

    static int min_zoom_factor() { return 10; }
    
    static size_t calc_key(const std::string & anchor,
                           int width,
                           int height,
                           float zoom,
                           int rotation);

    // Define the hash function.
    size_t operator()(void) const;

    // Define the equal function.
    bool operator == (const ImagePage & right);

    // Define operator <
    bool operator < (const ImagePage & right);

    // Define operator >
    bool operator > (const ImagePage & right);

    // Get the approximate size of memory for the page.
    int length(void);

    // Calculate desired image size and rotation
    static void calc_desired_dimension(ImagePageAttrs & request);

    // Pre-calculate the approximate size of memory for rendering the page.
    static int length(const std::string & filename,
                      ImagePageAttrs & request);

    // Update timestamp
    void update_timestamp(void);
 
    void set_in_use_flag(bool flag) { in_use = flag; }
    
    bool get_in_use_flag(void) { return in_use; }
  
    static PluginRotationDegree check_autorotate(int w, int h, int display_w, int display_h);

private:
    /// Make sure g_type system has been initialized. 
    void init_type_system(void);
/*
    /// Load the image if it's not ready yet.
    bool try_to_load(void);

    /// Compare the attributes with the request, re-scale
    /// the image if necessary.
    bool try_to_scale(void);
*/
    /// Load the image at scale.
    /// Notes: need to consider the rotation value.
    bool try_to_load_at_scale(void);

    /// Check the attributes with the request, rotate the
    /// image if necessary.
    bool try_to_rotate(void);

    /// Check the attributes with the request, dither the image
    /// if necessary.
    bool try_to_dither(void);

    /// Update all the other fields of attributes.
    bool update_attributes(void);

    /// Destroy the image.
    void destroy();

private:
	ImagesDocument *doc;	  ///< Loading Document
    std::string path;         ///< Image absolute path.
    ImagePageAttrs attrs;     ///< The image attributes.
 
    /// Indicate the page is in used by UDS host.
    /// The page in use that means it can't be removed 
    //  until UDS doesn't use it anymore.
    bool in_use;

    int display_width;
    int display_height;       ///< display size 
    
    long timestamp;            ///< 
    
    static bool g_type_initialize;
    GdkPixbuf   *loader;      ///< The gdk pixbuf object.
    bool        valid;        ///< Is a valid image.
};

}; // namespace comics

#endif


