// Copyright (C) 2011  Davis E. King (davis@dlib.net), Nils Labugt, Changjiang Yang (yangcha@leidos.com)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOAd_IMAGE_Hh_
#define DLIB_LOAd_IMAGE_Hh_

#include "load_image_abstract.h"
#include "../string.h"
#include "png_loader.h"
#include "jpeg_loader.h"
#include "image_loader.h"
#include <fstream>
#include <sstream>

namespace dlib
{
    namespace image_file_type
    {
        enum type
        {
            BMP,
            JPG,
            PNG,
            DNG,
            UNKNOWN
        };

        inline type read_type(const std::string& file_name) 
        {
            std::ifstream file(file_name.c_str(), std::ios::in|std::ios::binary);
            if (!file)
                throw image_load_error("Unable to open file: " + file_name);

            char buffer[9];
            file.read((char*)buffer, 8);
            buffer[8] = 0;

            // Determine the true image type using link:
            // http://en.wikipedia.org/wiki/List_of_file_signatures

            if (strcmp(buffer, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") == 0) 
                return PNG;
            else if(buffer[0]=='\xff' && buffer[1]=='\xd8' && buffer[2]=='\xff') 
                return JPG;
            else if(buffer[0]=='B' && buffer[1]=='M') 
                return BMP;
            else if(buffer[0]=='D' && buffer[1]=='N' && buffer[2] == 'G') 
                return DNG;

            return UNKNOWN;
        }
    };

    template <typename image_type>
    void load_image (
        image_type& image,
        const std::string& file_name
    )
    {
        const image_file_type::type im_type = image_file_type::read_type(file_name);
        switch (im_type)
        {
            case image_file_type::BMP: load_bmp(image, file_name); return;
            case image_file_type::DNG: load_dng(image, file_name); return;
#ifdef DLIB_PNG_SUPPORT
            case image_file_type::PNG: load_png(image, file_name); return;
#endif
#ifdef DLIB_JPEG_SUPPORT
            case image_file_type::JPG: load_jpeg(image, file_name); return;
#endif
            default:  ;
        }

        if (im_type == image_file_type::JPG)
        {
            std::ostringstream sout;
            sout << "Unable to load image in file " + file_name + ".\n" +
                    "You must #define DLIB_JPEG_SUPPORT and link to libjpeg to read JPEG files.\n" +
                    "Do this by following the instructions at http://dlib.net/compile.html.\n\n";
#ifdef _MSC_VER
            sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n";
            sout << "So don't #define it in one file, add it to the C/C++->Preprocessor->Preprocessor Definitions\n";
            sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.";
#else
            sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n";
            sout << "So don't #define it in one file, use a compiler switch like -DDLIB_JPEG_SUPPORT\n";
            sout << "so it takes effect for your entire application.";
#endif
            throw image_load_error(sout.str());
        }
        else if (im_type == image_file_type::PNG)
        {
            std::ostringstream sout;
            sout << "Unable to load image in file " + file_name + ".\n" +
                    "You must #define DLIB_PNG_SUPPORT and link to libpng to read PNG files.\n" +
                    "Do this by following the instructions at http://dlib.net/compile.html.\n\n";
#ifdef _MSC_VER
            sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n";
            sout << "So don't #define it in one file, add it to the C/C++->Preprocessor->Preprocessor Definitions\n";
            sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.\n";
#else
            sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n";
            sout << "So don't #define it in one file, use a compiler switch like -DDLIB_PNG_SUPPORT\n";
            sout << "so it takes effect for your entire application.";
#endif
            throw image_load_error(sout.str());
        }
        else
        {
            throw image_load_error("Unknown image file format: Unable to load image in file " + file_name);
        }
    }

}

#endif // DLIB_LOAd_IMAGE_Hh_ 

