/**
 * Simple class for WebTV Mime Types and overrides
 */


class WTVMime {

    mime = require('mime-types');
    wtvshared = null;
    minisrv_config = [];


    constructor(minisrv_config) {
        const { WTVShared }  = require("./WTVShared.js");
        this.minisrv_config = minisrv_config;
        this.wtvshared = new WTVShared(minisrv_config);
        if (!String.prototype.reverse) {
            String.prototype.reverse = function () {
                var splitString = this.split("");
                var reverseArray = splitString.reverse();
                var joinArray = reverseArray.join("");
                return joinArray;
            }
        }
    }

    shouldWeCompress(ssid_session, headers_obj) {
        var compress_data = false;
        var compression_type = 0; // no compression
        if (ssid_session) {
            if (ssid_session.capabilities) {
                if (ssid_session.capabilities['client-can-receive-compressed-data']) {

                    if (this.minisrv_config.config.enable_lzpf_compression || this.minisrv_config.config.force_compression_type) {
                        compression_type = 1; // lzpf
                    }

                    if (ssid_session) {
                        // if gzip is enabled...
                        if (this.minisrv_config.config.enable_gzip_compression || this.minisrv_config.config.force_compression_type) {
                            var is_bf0app = ssid_session.get("wtv-client-rom-type") == "bf0app";
                            var isOldBuild = this.wtvshared.isOldBuild(ssid_session);
                            var is_softmodem = false;
                            if (ssid_session.get("wtv-client-rom-type")) is_softmodem = ssid_session.get("wtv-client-rom-type").match(/softmodem/);
                            if (!is_bf0app && ((!is_softmodem && !isOldBuild) || (is_softmodem && !isOldBuild))) {
                                // softmodem boxes do not appear to support gzip in the minibrowser
                                // LC2 appears to support gzip even in the MiniBrowser
                                // LC2 and newer approms appear to support gzip
                                // bf0app does not appear to support gzip
                                compression_type = 2; // gzip
                            }
                        }
                    }



                    // mostly for debugging
                    if (this.minisrv_config.config.force_compression_type == "lzpf") compression_type = 1;
                    if (this.minisrv_config.config.force_compression_type == "gzip") compression_type = 2;

                    // do not compress if already encoded
                    if (headers_obj["Content-Encoding"]) return 0;

                    // should we bother to compress?
                    var content_type = "";
                    if (typeof (headers_obj) == 'string') content_type = headers_obj;
                    else content_type = (typeof (headers_obj["wtv-modern-content-type"]) != 'undefined') ? headers_obj["wtv-modern-content-type"] : headers_obj["Content-Type"];

                    if (content_type) {
                        // both lzpf and gzip
                        if (content_type.match(/^text\//) && content_type != "text/tellyscript") compress_data = true;
                        else if (content_type.match(/^application\/(x-?)javascript$/)) compress_data = true;
                        else if (content_type == "application/json") compress_data = true;
                        if (compression_type == 2) {
                            // gzip only
                            if (content_type.match(/^audio\/(x-)?(s3m|mod|xm|midi|wav|wave|aif(f)?)$/)) compress_data = true; // s3m, mod, xm, midi & wav
                            if (content_type.match(/^application\/karaoke$/)) compress_data = true; // midi karaoke
                            if (content_type.match(/^binary\/(x-wtv-approm|doom-data)/)) compress_data = true; // approms and DOOM WADs
                            if (content_type.match(/^wtv\/download-list$/)) compress_data = true; // WebTV Download List                            
                        }
                    }
                }
            }
        }

        // return compression_type if compress_data = true
        return (compress_data) ? compression_type : 0;
    }

    /**
     * Gets the WebTV Content-Type
     * @param {string} path Path to a file
     * @returns {string} Content-Type
     */
    getSimpleContentType(path) {
        return this.getContentType(path)[0];
    }

    /**
     * Gets both the WebTV Content-Type and the Modern Content-Type
     * @param {string} path Path to a file
     * @returns {Array} (WebTV Content-Type, Modern Content-Type)
     */
    getContentType(path) {
        var file_ext = this.wtvshared.getFileExt(path).toLowerCase();
        var wtv_mime_type = "";
        var modern_mime_type = "";
        // process WebTV overrides, fall back to generic mime lookup
        switch (file_ext) {
            case "aif":
                wtv_mime_type = "audio/x-aif";
                break;
            case "aifc":
                wtv_mime_type = "audio/x-aifc";
                break;
            case "aiff":
                wtv_mime_type = "audio/x-aiff";
                break;
            case "ani":
                wtv_mime_type = "x-wtv-animation";
                break;
            case "brom":
                wtv_mime_type = "binary/x-wtv-bootrom";
                break;
            case "cdf":
                wtv_mime_type = "application/netcdf";
                break;
            case "dat":
                wtv_mime_type = "binary/cache-data";
                break;
            case "dl":
                wtv_mime_type = "wtv/download-list";
                break;
            case "gsm":
                wtv_mime_type = "audio/x-gsm";
                break;
            case "gz":
                wtv_mime_type = "application/gzip";
                break;
            case "ini":
                wtv_mime_type = "wtv/jack-configuration";
                break;
            case "kar":
                wtv_mime_type = "audio/midi";
                break;
            case "mips-code":
                wtv_mime_type = "code/x-wtv-code-mips";
                break;
            case "o":
                wtv_mime_type = "binary/x-wtv-approm";
                break;
            case "ram":
                wtv_mime_type = "audio/x-pn-realaudio";
                break;
            case "rom":
                wtv_mime_type = "binary/x-wtv-flashblock";
                break;
            case "rsp":
                wtv_mime_type = "wtv/jack-response";
                break;
            case "swa":
            case "swf":
                wtv_mime_type = "application/x-shockwave-flash";
                break;
            case "srf":
            case "spl":
                wtv_mime_type = "wtv/jack-data";
                break;
            case "ttf":
                wtv_mime_type = "wtv/jack-fonts";
                break;
            case "tvch":
                wtv_mime_type = "wtv/tv-channels";
                break;
            case "tvl":
                wtv_mime_type = "wtv/tv-listings";
                break;
            case "tvsl":
                wtv_mime_type = "wtv/tv-smartlinks";
                break;
            case "wad":
                wtv_mime_type = "binary/doom-data";
                break;
            case "kar":
                wtv_mime_type = "application/karaoke";
                break;
            case "mp2":
            case "hsb":
            case "rmf":
            case "s3m":
            case "mod":
            case "xm":
                wtv_mime_type = "application/Music";
                break;
        }

        modern_mime_type = this.mime.lookup(path);
        if (modern_mime_type === false) modern_mime_type = "application/octet-stream";
        if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
        return new Array(wtv_mime_type, modern_mime_type);
    }

    // modified from https://github.com/sergi/mime-multipart/blob/master/index.js

    generateMultipartMIME(tuples, options) {
        // modified for creating usenet compliant headers/content from an attachment
        var CRLF = '\n';
        if (tuples.length === 0) {
            // according to rfc1341 there should be at least one encapsulation
            throw new Error('Missing argument. At least one part to generate is required');
        }

        options = options || {};
        var preamble = options.preamble || "This is a multi-part message in MIME format.";
        var epilogue = options.epilogue;
        var boundary = options.boundary || "------------" + this.wtvshared.generateString(24);

        if (boundary.length < 1 || boundary.length > 70) {
            throw new Error('Boundary should be between 1 and 70 characters long');
        }

        var boundary_header = 'multipart/mixed; boundary="' + boundary + '"';

        var delimiter = CRLF + '--' + boundary;
        var closeDelimiter = delimiter + '--';

        var wtvshared = this.wtvshared;

        var encapsulations = tuples.map(function (tuple, i) {
            var mimetype = tuple.mime || 'text/plain';
            var encoding = tuple.encoding || 'utf-8';
            var use_base64 = tuple.use_base64 || !wtvshared.isASCII(tuple.content);
            var is_base64 = tuple.is_base64 || wtvshared.isBase64(tuple.content);
            var filename = (tuple.filename) ? tuple.filename : (use_base64) ? ('file' + i) : null;
            
            var headers = [
                `Content-Type: ${mimetype}; ${(use_base64) ? `name="${filename}"` : `charset=${encoding.toUpperCase()}; format=flowed`}`,
            ];

            if (filename) headers.push(`Content-Disposition: attachment; filename="${filename}"`);
            headers.push(`Content-Transfer-Encoding: ${(use_base64) ? 'base64' : '7bit'}`);

            var bodyPart = headers.join(CRLF) + CRLF + CRLF;
            if (use_base64 && !is_base64) bodyPart += wtvshared.lineWrap(Buffer.from(tuple.content).toString('base64'),72) + CRLF;
            else bodyPart += wtvshared.lineWrap(tuple.content,72);

            return delimiter + CRLF + bodyPart;
        });

        var multipartBody = [
            preamble ? preamble : undefined,
            encapsulations.join(''),
            closeDelimiter,
            epilogue ? CRLF + epilogue : undefined,
        ].filter(function (element) { return !!element; });

        return {
            "mime_version": "1.0",
            "content_type": boundary_header,
            "content": multipartBody.join('')
        };
    }

}

module.exports = WTVMime;
