// Add following header comment to force Doxygen to generate documentation
// for methods which are directly in ioformat namespace without belonging to a
// class. Doxygen limitation.
/** \file IOFormat.h */

// ================================================================================ //
//       THE CONTENT OF THIS WORK IS PROPRIETARY TO FEI S.A.S, (FEI S.A.S.),        //
//                  AND IS DISTRIBUTED UNDER A LICENSE AGREEMENT.                   //
//                                                                                  //
//     REPRODUCTION, DISCLOSURE,  OR USE,  IN WHOLE OR IN PART,  OTHER THAN AS      //
//     SPECIFIED  IN THE LICENSE ARE  NOT TO BE  UNDERTAKEN  EXCEPT WITH PRIOR      //
//                       WRITTEN AUTHORIZATION OF FEI S.A.S.                        //
//                                                                                  //
//                             RESTRICTED RIGHTS LEGEND                             //
//     USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT OF THE CONTENT OF THIS     //
//     WORK OR RELATED DOCUMENTATION IS SUBJECT TO RESTRICTIONS AS SET FORTH IN     //
//     SUBPARAGRAPH (C)(1) OF THE COMMERCIAL COMPUTER SOFTWARE RESTRICTED RIGHT     //
//     CLAUSE  AT FAR 52.227-19  OR SUBPARAGRAPH  (C)(1)(II)  OF  THE RIGHTS IN     //
//        TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 52.227-7013.         //
//                                                                                  //
//                         COPYRIGHT (C) 2022 BY FEI S.A.S,                         //
//                                 BORDEAUX, FRANCE                                 //
//                               ALL RIGHTS RESERVED                                //
//                                                                                  //
// SEE http://assets.thermofisher.com/TFS-Assets/MSD/Licensing-Information/FEI_SAS_Thermo-Fisher-EULA_GLOBAL_With Usage Log_Nov2020.pdf //
//                              FOR MORE INFORMATION.                               //
// ================================================================================ //

#pragma once

#include <memory>
#include <string>

#include <ioformat/IOFormatAPI.h>
#include <iolink/Uri.h>
#include <iolink/storage/DataAccess.h>
#include <iolink/view/ImageView.h>
#include <iolink/view/View.h>
#include <iolink/writer/Writer.h>

/**
@namespace ioformat
@brief Global namespace which contains all methods to encode/decode data from/into different resources (files,
streams...) and some other helper classes and methods.
*/
namespace ioformat
{

/**
 * Force IOFormat initialization.
 * If not called, it will be initialized at the first call of any following methods.
 * This method allows you to force the loading of all the IOFormat plugins.
 * It may take some time, depending on the number of plugins to load.
 * @return true if at least one plugin was correctly loaded, false otherwise
 */
IOFORMAT_API bool init();

/**
 * Access to data from given file, using the extension of the file to determine format
 * @throw iolink::Error
 * @throw iolink::InvalidArgument
 * @throw ioformat::UnsupportedFormat
 **/
IOFORMAT_API std::shared_ptr<iolink::View> openView(const std::string& pathFile);

/**
 * Open a View on the file at the given path, forcing to a specific format.
 *
 * @param path The path to the file
 * @param format The format to use to read the file
 *
 * @throw UnsupportedFormat When the extractor selected according to the format cannot read the file.
 */
IOFORMAT_API std::shared_ptr<iolink::View> openView(const std::string& path, const std::string& format);

/**
 * Access to data from Uniform Resource Identifier, using the extension of the path to determine format
 * @throw iolink::Error
 **/
IOFORMAT_API std::shared_ptr<iolink::View> openView(const iolink::Uri& uri);

/**
 * Access to data from Uniform Resource Identifier, using the given format to decode it
 * @throw iolink::Error
 **/
IOFORMAT_API std::shared_ptr<iolink::View> openView(const iolink::Uri& uri, const std::string& format);

/**
 * Access to data from given file, using the extension of the file to determine format.
 * Image is fully loaded in memory.
 * Limitation:
 * - If file contains more than one image (like an image and its thumbnail),
 * this method will only load first read frame.
 * - If file contains a LOD image, resolution-0 image is read
 * - If data is not an image or is not readable, an UnsupportedFormat exception is thrown
 * @throw iolink::Error
 * @throw ioformat::UnsupportedFormat
 **/
IOFORMAT_API std::shared_ptr<iolink::ImageView> readImage(const std::string& pathFile);

/**
 * Access to data from given storage, using the given format to decode it
 * @param storage input storage containing the data to decode with given format
 * @param format file format to apply on given stream to decode
 * @throw iolink::Error
 * @throw iolink::InvalidArgument
 * @throw ioformat::UnsupportedFormat
 **/
IOFORMAT_API std::shared_ptr<iolink::View> openView(std::shared_ptr<iolink::DataAccess> storage,
                                                    const std::string& format);

/**
 * Open a writer used to write an image view into a file.
 *
 * @param view The view that will be written
 * @param pathFile a path to the output file.
 *
 * @return A writer ready to write the image into the file.
 */
IOFORMAT_API std::shared_ptr<iolink::Writer> openWriter(std::shared_ptr<iolink::View> view,
                                                        const std::string& pathFile);

/**
 * Open a writer used to write an image view into an output stream.
 *
 * @param view The view that will be written
 * @param dst The output stream where the encoded data will be written.
 * @param format The format to use to encode the image.
 *
 * @return A writer ready to write the image into the output stream.
 */
IOFORMAT_API std::shared_ptr<iolink::Writer> openWriter(std::shared_ptr<iolink::View> view,
                                                        std::shared_ptr<iolink::DataAccess> dst,
                                                        const std::string& format);

/**
 * Open a writer used to write an image view into an output stream.
 *
 * @param view The view that will be written
 * @param dst The output stream where the encoded data will be written.
 * @param format The format to use to encode the image.
 * @param plugin The specific plugin to use.
 *
 * @return A writer ready to write the image into the output stream.
 */
IOFORMAT_API std::shared_ptr<iolink::Writer> openWriter(std::shared_ptr<iolink::View> view,
                                                        std::shared_ptr<iolink::DataAccess> dst,
                                                        const std::string& format,
                                                        const std::string& plugin);

/**
 * Save a view into a file.
 *
 * @param view The view to save
 * @param pathFile The path of the file where to save the image
 *
 * @throw iolink::Error When the image cannot be written
 */
IOFORMAT_API void writeView(std::shared_ptr<iolink::View> view, const std::string& pathFile);

/**
 * Save a view into a storage.
 *
 * @param view The view to save
 * @param dst The storage where to save the image
 * @param format The format in which the image will be encoded
 *
 * @throw iolink::Error When the image cannot be written
 */
IOFORMAT_API void writeView(std::shared_ptr<iolink::View> view,
                            std::shared_ptr<iolink::DataAccess> dst,
                            const std::string& format);

/**
 * Helper to retrieve a format from an extension.
 *
 * Extension are case insensitive, so for example "png" and "PNG" are the same
 * for this function, and will return the same format.
 *
 * @param extension string which contains the extension to identify (without dot)
 * @return a string containing the format identifier corresponding to this extension
 */
IOFORMAT_API std::string formatFromExtension(const std::string& extension);

} // namespace ioformat
