/*
 * File Name: images_scanner.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 _IMAGES_SCANNER_H_
#define _IMAGES_SCANNER_H_

#include <map>
#include <vector>
#include <string>

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

#include "plugin_type.h"

#include "unzip.h"

#ifndef WIN32
#include <libexif/exif-data.h>
#endif

namespace comics
{	
	typedef enum
	{
		ARC_UNK = 0,
		ARC_ZIP,
		ARC_RAR,
	}ArchiveType;
	
    typedef enum
    {
        BY_FILEPATH = 0,
        BY_FILENAME,
        BY_EXT,
        BY_DATE,
        BY_SIZE,
    }SortType;

    struct Image
    {
        std::string path;
     
        // MetaData
		bool is_calculated; // Everything is calculated at once now...
        int width;     // '-1' means need to calculate.
        int height;    // '-1' means need to calculate.
        bool is_rotation_calculated;    // true/false means rotation is/is-not calculated
        PluginRotationDegree rotation;  // 

        std::string sort_field;
    };

    typedef Image *ImagePtr;
    typedef std::vector<ImagePtr> Images;
    typedef std::vector<ImagePtr>::iterator ImagesIter;

	typedef bool (*recalc_size_callback)(int *, int *, void *);

    /**
     * @brief  : Scan all the images in the formats supported by gdk_pixbuf
     *           under the input directory 
     *           or the directory which the input filename is located in.
     *           It also supports the option of scanning recursively or not.
     */
    class ImagesScanner
    {
        public:
            /**
             * @brief Construct a 'ImagesScanner'.
             */
            ImagesScanner(void);
            ~ImagesScanner(void);

        public:
			Images images;
				
			bool is_comic(const std::string & filename);
	
            bool is_image(const std::string & filename);
            
			int get_position(const std::string & path);

            /**
             * @brief Set the filename of an archive to scan.
             * @param filename 
             * @param sort_type Sort by date, size, etc.
             * @param sort_ascending Sort by ascending or descending.
             * @return Get the index of the current active image.
             *        The current active image is the input filename.
             *        Or if the input filename is directory, 
             *        the active image is the first image file found.
             */
			int scan_archive(const std::string & filename, SortType sort_type, bool sort_ascending, std::map<std::string, std::string> &metadata);

			// Updates the calculations for a file in one go.
			Image *update_calc(const std::string & filename);

			// Gets a pixel buffer while also offering a means to cause the size to get recalculated
			GdkPixbuf *get_pixbuf(const std::string & filename, recalc_size_callback size_callback, void *user_data);
       private:
			// Zip Versions of Certain Methods
			int scan_zip(const std::string & filename, SortType sort_type, bool sort_ascending, Images & results, std::map<std::string, std::string> &metadata);
			Image *update_calc_zip(const std::string & filename);
			GdkPixbuf *get_pixbuf_zip(const std::string & filename, recalc_size_callback size_callback, void *user_data);
			
			void parse_json(std::string & text, std::map<std::string, std::string> & metadata_map);
			
#ifndef WIN32
			void update_rotation(Image * image, ExifData *ped);
#endif
	
			ArchiveType get_archive_type(const std::string & filename);
	
            void get_supported_extnames(void);

            bool check_extname(const std::string & filename);

            void sort_images(Images & results,
                             SortType sort_type, 
                             bool sort_ascending);

            static bool greater_by_filepath(Image * a, Image * b); 
            static bool greater_by_filename(Image * a, Image * b); 
            static bool greater_by_ext(Image * a, Image * b); 
            static bool greater_by_date(Image * a, Image * b); 
            static bool greater_by_size(Image * a, Image * b); 

            static bool less_by_filepath(Image * a, Image * b); 
            static bool less_by_filename(Image * a, Image * b); 
            static bool less_by_ext(Image * a, Image * b); 
            static bool less_by_date(Image * a, Image * b); 
            static bool less_by_size(Image * a, Image * b); 

        private:
			GMutex *mutex;
			GMutex *scannermutex;
	
            std::string filepath; ///< the original input file path
			ArchiveType arctype;  ///< type of archive at file path
			
			unzFile cbzfile;      ///< archive reference for zip files
			unzFile cbzscanner;	  ///< archive reference for scanning zip files quickly
			
			GdkPixbuf *lastimage;
			std::string lastimagepath;

            typedef std::vector<std::string> ExtNames;
            typedef std::vector<std::string>::iterator ExtNamesIter;
            ExtNames extnames; ///<  stored in format doc jpg bmp png etc.

            int  active;        ///< the index of the active image
    };

} // namespace image

#endif // _IMAGES_SCANNER_H_


