/**
 * File: Includes.js
 *
 * Module used for fetching static content for the website
 * like js, css, images, and other static html pages
 *
 * @author Jeffery Russell
 */

const HEADER_KEY = "header";

const FOOTER_KEY = "footer";

//name of header file
const HEADER_FILE = "includes/html/header.html";

//path of footer file
const FOOTER_FILE = "includes/html/footer.html";

//admin header path
const ADMIN_HEADER = "includes/html/adminHeader.html";

//used for hashing stuff for the header's e-tag for clients cache
const crypto = require('crypto');


//caching program to make the application run faster
const cache = require('memory-cache');

const fs = require('fs');


const readFile = function(filename)
{
    return new Promise(function(resolve, reject)
    {
        try
        {
            resolve(fs.readFileSync(filename));
        }
        catch (e)
        {
            console.log(e);
            console.log("Could not find " + filename);
            return("");
        }
    })
};

/**
 * Sends a static file to the client in a way which the web browser
 * caches the contents sent.
 *
 * @param cache -- server's hashmap which reduces file io
 * @param path -- file requested by user
 * @param type -- type of file for the header
 * @param result -- sent to client
 */
const sendCachedContent = function(path, type, result)
{
    const goods = cache.get(path);

    if(goods == null)
    {
        readFile(path).then(function(content)
        {
            const eTag = crypto.createHash('md5').update(content).digest('hex');
            result.writeHead(200, {'Content-Type': type, 'Cache-Control':
                    'public, max-age=2678400', 'ETag': '"' + eTag + '"',
                    'Vary': 'Accept-Encoding'});
            result.write(content);
            result.end();
        }).catch(function(error)
        {
            cache.del(path);
            console.log(error);
        });
    }
    else
    {
        const eTag = crypto.createHash('md5').update(goods).digest('hex');
        result.writeHead(200, {'Content-Type': type,
            'Cache-Control': 'public, max-age=2678400',
            'ETag': '"' + eTag + '"',
            'Vary': 'Accept-Encoding'});
        result.write(goods);
        result.end();
    }
};


module.exports =
{
    /** Appends the header html section to the result which is
     * sent to the user.
     *
     * @param result
     * @return {*} a promise retrieved from the utils.include function
     */
    printHeader: function(templateContext)
    {
        return module.exports.includeInObject(HEADER_KEY, templateContext, HEADER_FILE);
    },


    includeInObject: function(key, context, fileName)
    {
        return new Promise(function(resolve, reject)
        {
            readFile(fileName).then(function(result)
            {
                context[key] = result;
                resolve();
            }).catch(function(error)
            {
                context[key] = "File Not Found";
                reject(error);
                console.log(error);
            })
        });
    },


    /**
     * A function similar to the include statement in PHP
     * This function writes a file to the output
     *
     * @param fileName the file to append to the result
     */
    include: function(fileName)
    {
        return readFile(fileName);
    },

    /**
     * Appends the footer to the result object
     *
     * @return {*|Promise}
     */
    printFooter: function(templateContext)
    {
        return module.exports.includeInObject(FOOTER_KEY, templateContext, FOOTER_FILE);
    },

    /**
     * Displays the admin header
     *
     * @returns {*|Promise}
     */
    printAdminHeader(templateContext)
    {
        return module.exports.includeInObject(HEADER_KEY, templateContext, ADMIN_HEADER);
    },


    /**Sends a css file to the user
     *
     * @param result
     * @param path
     * @return {*}
     */
    sendCSS: function(result, path)
    {
        sendCachedContent(path, 'text/css', result);
    },


    /**Sends the user an image from the specified fileName.
     *
     * @param result
     * @param fileName
     */
    sendImage: function(result, fileName)
    {
        sendCachedContent(fileName, 'image/png', result);
    },


    /**Sends the user an image from the specified fileName.
     *
     * @param result
     * @param fileName
     */
    sendJS: function(result, fileName)
    {
        sendCachedContent(fileName, 'application/javascript', result);
    },


    /** Might want to change this to be non cached later
     *
     * @param result
     * @param fileName
     */
    sendPDF: function(result, fileName)
    {
        sendCachedContent(fileName, 'application/pdf', result);
    },


    fetchTemplate: function(templateName)
    {
        return readFile("templates/" + templateName);
    },


    /**Sends the user an image from the specified fileName.
     *
     * @param result
     * @param fileName
     */
    sendHTML: function(result, fileName)
    {
        readFile(fileName).then(function(content)
        {
            result.writeHead(200, {'Content-Type': 'text/html'});
            result.write(content);
            result.end();
        }).catch(function(error)
        {
            console.log(error);
        });
    },


    /**
     * Sends a svg file to the client.
     *
     * @param result
     * @param fileName
     */
    sendSVG: function(result, fileName)
    {
        sendCachedContent(fileName, 'image/svg+xml', result);
    },

    /**
     * Clears the cache
     */
    clearCache: function()
    {
        console.log("Includes cache cleared");
        cache.clear();
    }
};