# modules/viewerpreferences.js

    /* global jsPDF */
    /**
     * jsPDF viewerPreferences Plugin
     * @author Aras Abbasi (github.com/arasabbasi)
     * Licensed under the MIT License.
     * http://opensource.org/licenses/mit-license
     */

     /**
     * Adds the ability to set ViewerPreferences and by thus
     * controlling the way the document is to be presented on the
     * screen or in print.
     * @name viewerpreferences
     * @module
     */
    (function (jsPDFAPI) {
        "use strict";
        /**
         * Set the ViewerPreferences of the generated PDF
         *
         * @name viewerPreferences
    	 * @function
    	 * @public
         * @param {Object} options Array with the ViewerPreferences<br />
         * Example: doc.viewerPreferences({"FitWindow":true});<br />
         * <br />
         * You can set following preferences:<br />
         * <br/>
         * <b>HideToolbar</b> <i>(boolean)</i><br />
         * Default value: false<br />
         * <br />
         * <b>HideMenubar</b> <i>(boolean)</i><br />
         * Default value: false.<br />
         * <br />
         * <b>HideWindowUI</b> <i>(boolean)</i><br />
         * Default value: false.<br />
         * <br />
         * <b>FitWindow</b> <i>(boolean)</i><br />
         * Default value: false.<br />
         * <br />
         * <b>CenterWindow</b> <i>(boolean)</i><br />
         * Default value: false<br />
         * <br />
         * <b>DisplayDocTitle</b> <i>(boolean)</i><br />
         * Default value: false.<br />
         * <br />
         * <b>NonFullScreenPageMode</b> <i>(string)</i><br />
         * Possible values: UseNone, UseOutlines, UseThumbs, UseOC<br />
         * Default value: UseNone<br/>
         * <br />
         * <b>Direction</b> <i>(string)</i><br />
         * Possible values: L2R, R2L<br />
         * Default value: L2R.<br />
         * <br />
         * <b>ViewArea</b> <i>(string)</i><br />
         * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
         * Default value: CropBox.<br />
         * <br />
         * <b>ViewClip</b> <i>(string)</i><br />
         * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
         * Default value: CropBox<br />
         * <br />
         * <b>PrintArea</b> <i>(string)</i><br />
         * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
         * Default value: CropBox<br />
         * <br />
         * <b>PrintClip</b> <i>(string)</i><br />
         * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
         * Default value: CropBox.<br />
         * <br />
         * <b>PrintScaling</b> <i>(string)</i><br />
         * Possible values: AppDefault, None<br />
         * Default value: AppDefault.<br />
         * <br />
         * <b>Duplex</b> <i>(string)</i><br />
         * Possible values: Simplex, DuplexFlipLongEdge, DuplexFlipShortEdge
         * Default value: none<br />
         * <br />
         * <b>PickTrayByPDFSize</b> <i>(boolean)</i><br />
         * Default value: false<br />
         * <br />
         * <b>PrintPageRange</b> <i>(Array)</i><br />
         * Example: [[1,5], [7,9]]<br />
         * Default value: as defined by PDF viewer application<br />
         * <br />
         * <b>NumCopies</b> <i>(Number)</i><br />
         * Possible values: 1, 2, 3, 4, 5<br />
         * Default value: 1<br />
         * <br />
         * For more information see the PDF Reference, sixth edition on Page 577
         * @param {boolean} doReset True to reset the settings
         * @function
         * @returns jsPDF jsPDF-instance
         * @example
         * var doc = new jsPDF()
         * doc.text('This is a test', 10, 10)
         * doc.viewerPreferences({'FitWindow': true}, true)
         * doc.save("viewerPreferences.pdf")
         *
         * // Example printing 10 copies, using cropbox, and hiding UI.
         * doc.viewerPreferences({
         *   'HideWindowUI': true,
         *   'PrintArea': 'CropBox',
         *   'NumCopies': 10
         * })
         */
        jsPDFAPI.viewerPreferences = function (options, doReset) {
            options = options || {};
            doReset = doReset || false;

            var configuration;
            var configurationTemplate = {
                "HideToolbar": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.3},
                "HideMenubar": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.3},
                "HideWindowUI": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.3},
                "FitWindow": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.3},
                "CenterWindow": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.3},
                "DisplayDocTitle": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.4},
                "NonFullScreenPageMode": {defaultValue: "UseNone", value: "UseNone", type: "name", explicitSet: false, valueSet: ["UseNone", "UseOutlines", "UseThumbs", "UseOC"], pdfVersion: 1.3},
                "Direction": {defaultValue: "L2R", value: "L2R", type: "name", explicitSet: false, valueSet: ["L2R", "R2L"], pdfVersion: 1.3},
                "ViewArea": {defaultValue: "CropBox", value: "CropBox", type: "name", explicitSet: false, valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"], pdfVersion: 1.4},
                "ViewClip": {defaultValue: "CropBox", value: "CropBox", type: "name", explicitSet: false, valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"], pdfVersion: 1.4},
                "PrintArea": {defaultValue: "CropBox", value: "CropBox", type: "name", explicitSet: false, valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"], pdfVersion: 1.4},
                "PrintClip": {defaultValue: "CropBox", value: "CropBox", type: "name", explicitSet: false, valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"], pdfVersion: 1.4},
                "PrintScaling": {defaultValue: "AppDefault", value: "AppDefault", type: "name", explicitSet: false, valueSet: ["AppDefault", "None"], pdfVersion: 1.6},
                "Duplex": {defaultValue: "", value: "none", type: "name", explicitSet: false, valueSet: ["Simplex", "DuplexFlipShortEdge", "DuplexFlipLongEdge", "none"], pdfVersion: 1.7},
                "PickTrayByPDFSize": {defaultValue: false, value: false, type: "boolean", explicitSet: false, valueSet: [true, false], pdfVersion: 1.7},
                "PrintPageRange": {defaultValue: "", value: "", type: "array", explicitSet: false, valueSet: null, pdfVersion: 1.7},
                "NumCopies": {defaultValue: 1, value: 1, type: "integer", explicitSet: false, valueSet: null, pdfVersion: 1.7}
            };

            var configurationKeys = Object.keys(configurationTemplate);

            var rangeArray = [];
            var i = 0;
            var j = 0;
            var k = 0;
            var isValid;

            var method;
            var value;

            function arrayContainsElement(array, element) {
                var iterator;
                var result = false;

                for (iterator = 0; iterator < array.length; iterator += 1) {
                    if (array[iterator] === element) {
                        result = true;
                    }
                }
                return result;
            }

            if (this.internal.viewerpreferences === undefined) {
                this.internal.viewerpreferences = {};
                this.internal.viewerpreferences.configuration = JSON.parse(JSON.stringify(configurationTemplate));
                this.internal.viewerpreferences.isSubscribed = false;
            }
            configuration = this.internal.viewerpreferences.configuration;

            if (options === "reset" || doReset === true) {
                var len = configurationKeys.length;

                for (k = 0; k < len; k += 1) {
                    configuration[configurationKeys[k]].value = configuration[configurationKeys[k]].defaultValue;
                    configuration[configurationKeys[k]].explicitSet = false;
                }
            }

            if (typeof options === "object") {
                for (method in options) {
                    value = options[method];
                    if (arrayContainsElement(configurationKeys, method) && value !== undefined) {

                        if (configuration[method].type === "boolean" && typeof value === "boolean") {
                            configuration[method].value = value;
                        } else if (configuration[method].type === "name" && arrayContainsElement(configuration[method].valueSet, value)) {
                            configuration[method].value = value;
                        } else if (configuration[method].type === "integer" && Number.isInteger(value)) {
                            configuration[method].value = value;
                        } else if (configuration[method].type === "array") {

                            for (i = 0; i < value.length; i += 1) {
                                isValid = true;
                                if (value[i].length === 1 && typeof value[i][0] === "number") {
                                    rangeArray.push(String(value[i] - 1));
                                } else if (value[i].length > 1) {
                                    for (j = 0; j < value[i].length; j += 1) {
                                        if (typeof value[i][j] !== "number") {
                                            isValid = false;
                                        }
                                    }
                                    if (isValid === true) {
                                        rangeArray.push(([value[i][0] - 1,value[i][1] - 1]).join(" "));
                                    }
                                }
                            }
                            configuration[method].value = "[" + rangeArray.join(" ") + "]";
                        } else {
                            configuration[method].value = configuration[method].defaultValue;
                        }

                        configuration[method].explicitSet = true;
                    }
                }
            }

            if (this.internal.viewerpreferences.isSubscribed === false) {
                this.internal.events.subscribe("putCatalog", function () {
                    var pdfDict = [];
                    var vPref;
                    for (vPref in configuration) {
                        if (configuration[vPref].explicitSet === true) {
                            if (configuration[vPref].type === "name") {
                                pdfDict.push("/" + vPref + " /" + configuration[vPref].value);
                            } else {
                                pdfDict.push("/" + vPref + " " + configuration[vPref].value);
                            }
                        }
                    }
                    if (pdfDict.length !== 0) {
                        this.internal.write("/ViewerPreferences\n<<\n" + pdfDict.join("\n") + "\n>>");
                    }
                });
                this.internal.viewerpreferences.isSubscribed = true;
            }

            this.internal.viewerpreferences.configuration = configuration;
            return this;
        };
    })(jsPDF.API);