/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, bitwise: true, node: true, regexp: true */
/*jshint unused: true */
/*global document: true, window: true, require:true, _:true, $:true, module: true */

"use strict";

var Backbone = require('backbone'),
    _  = require("underscore"),
    Strings = require("./LocStrings"),
    Template = require("./TemplateLoader"),
    Headlights = require("./utils/Headlights"),
    constrainer = require("./constrainer"),
    rounder = require("./rounder"),
    filePathSanitizer = require("shared/FilePathSanitizer");


var GenSettingView = Backbone.View.extend({
    initialize: function () {
        this.listenTo(this.model, "change:file", this.updateName);
        this.listenTo(this.model, "change:errorMessage", this.updateErrorMessage);
        this.listenTo(this.model, "change:disabled", this.updateDisabledState);
        this.listenTo(this.model, "change:selected", this.updateSelectedState);
        this.listenTo(this.model, "change:subselected", this.updateSubSelectedState);
        this.listenTo(this.model, "change:settingsVisible", this.renderSettingsVisible);
        this.listenTo(this.model, "change:originalDimensions", this.renderPlaceholderDimensions);
        this.listenTo(this.model, "change:originalDimensions change:scale", this.renderWidthAndHeightFromScale);
        this.listenTo(this.model, "change:canvasWidth change:canvasHeight change:scale change:originalDimensions", this.renderCanvasSizes);
        
        this.lastValidValue = {
            width: "",
            height: "",
            canvasWidth: "",
            canvasHeight: "",
            scale: "100",
            imageQuality: "100%"
        };
    },

    events: {
        "change .export-format": "changeExportFormat",
        "blur .quality-text-input": "changeQualityText",
        "keyup .quality-text-input": "keyupQualityText",
        "keydown .quality-text-input": "keyboardQualityChange",
        "mousedown .quality-range-input": "mouseDownQualityRange",
        "mouseup .quality-range-input": "togglePercentageView",
        "blur .quality-range-input": "togglePercentageView",
        "blur .title": "commitEdit",
        "change .options input[name='width']": "handleDimensionScaleChange",
        "change .options input[name='height']": "handleDimensionScaleChange",
        "change .options input[name='scale']": "changeScaleText",
        "change .options input[name='canvasWidth']": "handleDimensionScaleChange",
        "change .options input[name='canvasHeight']": "handleDimensionScaleChange",
        "change .scale-select": "changeScaleSel",
        "change .select-interpolation": "changeInterpolationSel",
        "click .options label.checkbox.transparency": "changeTransparency",
        "click .reset-canvas-dimensions": "resetCanvasDimensions",
        "change .quality-range-input": "changeQualityRange",
        "keydown .quality-range-input": "mouseDownQualityRange",
        "click .percentage": "togglePercentageView",
        "keydown .title": "handleInputKey",
        "keyup .title": "handleInputKey"
    },
    _pngregex: /(png)-?(24|32|8)?/,
    cacheElements: function () {
        this.$errorIndicator = this.$('.icon-info');
        this.$elName = this.$(".title");
        this.$elExportFormat = this.$(".export-format");
        this.$elQualityText = this.$(".quality-text-input");
        this.$elQualitySlider = this.$(".percentage-range");
        this.$elQualityRange = this.$(".quality-range-input");
        this.$elQualityRow = this.$(".quality-row");
        this.$elSvgWarningRow = this.$(".svg-warning-row");
        this.$elInterpolationSel = this.$(".select-interpolation");
        this.$elTransparencyCheckbox = this.$("input[value='transparency']");
        this.$elTransparencyRow = this.$(".transparency-row");
        this.$options = this.$(".options");
        this.$layer = this.$(".layer");
        this.$disclosureArrow = this.$(".disclosure-arrow");
        this.$width =  this.$options.find("input[name='width']");
        this.$height =  this.$options.find("input[name='height']");
        this.$scaleSel = this.$(".scale-select");
        this.$scaleText = this.$options.find("input[name='scale']");
        this.$canvasWidth = this.$("input[name='canvasWidth']");
        this.$canvasHeight = this.$("input[name='canvasHeight']");
        this.$resetCanvasDimensions = this.$(".reset-canvas-dimensions");
    },
    "class": "asset",
    extSupportsQuality: {
        "jpg": true
    },
    template: _.template(Template.loadTemplate("../templates/genSettingView.html")),
    render: function () {
        var context, pngBits, pngMatch,
            ext = this.model.get("extension") ? this.model.get("extension").toLowerCase() : "",
            extDisplay = ext,
            quality = this.model.get("quality"),
            naturalDimensions = this.model.getNaturalImageDimensions();
    
        this.transparencyEnabled = false;
        this.transparencySupported = true;
        
        if (this.extSupportsQuality[ext]) {
            this.qualityEnabled = true;
        } else {
            if (ext.indexOf("png") > -1) {
                if (ext === "png") {
                    pngBits = (quality) ? quality.toString() : "";
                    if (pngBits === "8") {
                        extDisplay = "png-8";
                    } else {
                        extDisplay = "png";
                        this.transparencyEnabled = true;
                        if (pngBits === "24") {
                            this.transparencySupported = false;
                        }
                    }
                } else {
                    pngMatch = ext.match(this._pngregex);
                    pngBits = pngMatch[2];
                    if (pngBits !== "8") {
                        extDisplay = "png";
                        this.transparencyEnabled = true;
                        if (pngBits === "24") {
                            this.transparencySupported = false;
                        }
                    }
                }
            }
            this.qualityEnabled = false;
        }

        context = Template.createTemplateContext(Strings, {
            name: this.model.get("name"),
            file: this.model.get("file"),
            width: this.model.get("width") || "",
            height: this.model.get("height") || "",
            placeHolderWidth: Math.ceil(naturalDimensions.width),
            placeHolderHeight: Math.ceil(naturalDimensions.height),
            quality: parseInt(quality, 10),
            qualityEnabled: this.qualityEnabled,
            transparencyEnabled: this.transparencyEnabled,
            transparencySupported: this.transparencySupported,
            errorMessage: this.model.get("errorMessage")
        });
        this.$el.html(this.template(context));
        this.cacheElements();
        
        this.$elExportFormat.val(extDisplay);
        this.$elTransparencyCheckbox.prop("checked", this.transparencySupported);
        this.renderWidthAndHeightFromScale();
        this.renderCanvasSizes();
        this.$elInterpolationSel.val(this.model.get("interpolationType"));
        
        this.updateSubSelectedState();
        this.updateSelectedState();
        this.updateDisabledState();
        this.updateErrorMessage();

        return this;
    },
    
    renderCanvasSizes: function () {
        var dim = this.getScaledDimensions(),
            cnvW = this.model.get("canvasWidth"),
            cnvH = this.model.get("canvasHeight"),
            canReset = (cnvW || cnvH) ? true : false;
        this.$canvasHeight.val(cnvH || "").attr("placeholder", dim.height);
        this.$canvasWidth.val(cnvW || "").attr("placeholder", dim.width);
        this.lastValidValue.canvasHeight = this.$canvasHeight.val();
        this.lastValidValue.canvasWidth = this.$canvasWidth.val();
        this.$resetCanvasDimensions.prop("disabled", !canReset);
    },
    
    renderWidthAndHeightFromScale: function () {
        var scale = this.model.get("scale"),
            w = this.model.get("width"),
            h = this.model.get("height");
        if (!_.isFinite(scale) && !_.isFinite(w) && !_.isFinite(h)) {
            scale = 1;
        }
        if (_.isFinite(scale) && scale > 0) {
            var scaleInPercent = rounder(scale * 100, 2);
            this.updateScaleVals(String(scaleInPercent), (scale === 1 ? "100" :""));
            this.changeScaleVal(scaleInPercent);
        }
    },
    
    handleInputKey: function (e) {
        var keyCode = e.keyCode;
        var isKeyDown = (e.type === "keydown");
        // TAB or RETURN
        if (keyCode === 9 || keyCode === 13) {
            if (keyCode !== 9) {
                e.preventDefault();
                e.stopPropagation();
            }
            if (isKeyDown) {
                this.commitEdit();
            }
        } else if (keyCode === 27) {  // ESC
            e.preventDefault();
            e.stopPropagation();
            if (isKeyDown) {
                this.$elName.val(this.origFileName);
                this.commitEdit();
            }
        }
        
        // on keyup for RETURN and ESC, defocus the input
        if (!isKeyDown && (keyCode === 13 || keyCode === 27)) {
            this.$elName.blur();
        }
       
    },
    commitEdit: function () {
        var newName = this.validateFileName(this.$elName.val());
        if (this.origFileName && this.origFileName !== newName) { // only update the name if the user started an edit
            this.$elName.val(newName);
            this.setFileName(newName);
        }
        this.$elName.prop("disabled", true)
                    .removeClass("editing")
                    .scrollLeft(0);
        this.origFileName = "";
    },
    
    setFileName: function (newName) {
        this.model.set({
            "name": newName,
            "file": newName
        });
        this.model.unset("desiredBaseName");
    },
    
    // This assumes that we aren't showing a validation message and just does the fixup
    validateFileName: function (newName) {
        var curExt = this.model.get("extension"),
            validatedName = newName.trim(),
            ext;
        
        //check for invalid character and replace with _

        validatedName = filePathSanitizer.sanitize(validatedName);
             
        //check that it uses the current ext, and add it if it's missing
        ext = validatedName.split('.').pop();
        if (curExt && ext !== curExt) {
            validatedName += "." + curExt;
        }
        
        return validatedName;
    },
    
    updateName: function () {
        this.$elName.val(this.model.get("file"));
    },
    
    updateErrorMessage: function () {
        var msg = this.model.get('errorMessage');
        var ext = this.model.get("extension") ? this.model.get("extension").toLowerCase() : "";
        var fontErrorDetected = false;
        
        if (msg && ext === "svg") {
            this.$errorIndicator.attr('aria-label', msg).addClass('active');
            if( msg.indexOf("Fonts") > -1 ) {
                fontErrorDetected = true;
            }
        } else {
            this.$errorIndicator.removeClass('active');
        }

        this.$elSvgWarningRow.toggleClass("hide", !fontErrorDetected);
    },
    
    mouseDownQualityRange: function () {
        this._disarmMouseDown = true;
    },

    renderSettingsVisible: function () {
        var active = this.model.get("settingsVisible");
        this.$disclosureArrow.toggleClass("active", active);
        this.$options.toggleClass("active", !active);
    },

    _listenForMouseDownOutsideSlider: function () {
        var self = this;
        
        this._fnEvtMouseDown = function () {
            if (self._disarmMouseDown) {
                self._disarmMouseDown = false;
            } else {
                self.$elQualitySlider.toggleClass('show');
            }
            self._cleanupMouseDownOutsideSlider();
        };

        document.addEventListener("mousedown", this._fnEvtMouseDown);
    },

    fixUpInvalidInput: function ($inputEl) {
        var val = $inputEl.val().trim(),
            parsedVal = parseFloat(val, 10),
            name = $inputEl.attr("name");

        if (_.isNaN(parsedVal)) {
            if (val !== "") {
                parsedVal = val.replace(/[^\d.]/g, '').trim();
                if (parsedVal === "") {
                    // all chars invalid -- reset to last valid
                    parsedVal = this.lastValidValue[name];
                }
            } else {
                parsedVal = val;
            }
        } else if (!_.isFinite(parsedVal) || (parsedVal === 0 && name !== "imageQuality")) {
            // 0 is valid only for quality
            parsedVal = this.lastValidValue[name];
        } else {
            if (parsedVal < 0) {
                parsedVal = -parsedVal;
            }
        }
        return (parsedVal === undefined ? undefined : parsedVal.toString());
    },

    updateScaleVals: function (newTextScale, newSelScale) {
        this.$scaleText.val(newTextScale + "%");
        this.lastValidValue.scale = newTextScale;
        this.$scaleSel.val(newSelScale);
    },

    constrainDimensions: function (e) {
        var $inputEl = $(e.target),
            toConstrain = {},
            name = $inputEl.attr("name"),
            toUpdate = name === "width" ? "height" : "width",
            elToUpdate =  this["$" + toUpdate],
            toAdd;
        
        if ($inputEl.val()) {
            toConstrain[name] = $inputEl.val();
            var newValues = constrainer(toConstrain, this.model.getNaturalImageDimensions(), name);
            toAdd = Math.ceil(newValues[toUpdate]);
            elToUpdate.val(toAdd);
            this.lastValidValue[toUpdate] = toAdd.toString();
            this.updateScaleVals(newValues.scale, "");
        } else {
            elToUpdate.val("");
            this.lastValidValue[toUpdate] = "";
            this.updateScaleVals("100", "100");
        }

        this.persistOptions();
    },
    
    // Compare the two passed strings; return true if they're the same other than an
    // extra trailing '%' char on str2
    sameButTrailingPerc: function (str1, str2) {
        if (str2 === str1 + "%") {
            return true;
        }

        return false;
    },
    
    handleDimensionScaleChange: function (e) {
        var $inputEl = $(e.target),
            name = $inputEl.attr("name"),
            beforeStringVal = this.lastValidValue[name],
            editedStringVal = $inputEl.val(),
            finalStringVal = this.fixUpInvalidInput($inputEl),
            parsedVal = parseFloat(finalStringVal, 10),
            invalidValue = false,
            correctedValue = false,
            decPlaces,
            min,
            max,
            maxImageDim;

        if (name === "scale") {
            // we want to round to 2 decimal places, so we'll multiply by 100 before we round
            decPlaces = 2;
            min = 1;
            max = this.model.getMaxScale() || 500;
            // we don't want to allow empty value for scale
            if (finalStringVal === "") {
                finalStringVal = beforeStringVal;
            }
        } else if (name === "width" || name === "canvasWidth") {
            // Note that canvasWidth/canvasHeight is not constrained to image aspect ratio
            // like width/height, so they could exceed these limits without exceeding max
            // pixels, but it doesn't seem common enough to handle separately.
            min = 1;
            maxImageDim = this.model.getMaxImageDimensions();
            max = maxImageDim && maxImageDim.width || 9999;
        } else if (name === "height" || name === "canvasHeight") {
            min = 1;
            maxImageDim = this.model.getMaxImageDimensions();
            max = maxImageDim && maxImageDim.height || 9999;
        }

        if (finalStringVal === beforeStringVal) {
            invalidValue = true;
        } else if (this.sameButTrailingPerc(finalStringVal, editedStringVal)) {
            // clear the trailing %
            this.$scaleText.val(finalStringVal);
        } else if (finalStringVal !== editedStringVal) {
            correctedValue = true;
        }

        if (finalStringVal === "") {
            // valid -- update last valid
            this.lastValidValue[name] = "";
        } else if (_.isNaN(parsedVal)) {
            invalidValue = true;
        } else {
            if (min && parsedVal < min) {
                // clip to min, if appropriate
                parsedVal = min;
                correctedValue = true;
            } else if (max && parsedVal > max) {
                // clip to max, if appropriate
                parsedVal = max;
                correctedValue = true;
            } else if (parsedVal !== Math.floor(parsedVal)) {
                if (decPlaces) {
                    // Round to appropriate number of places
                    var newVal = rounder(parsedVal, decPlaces);
                    if (newVal !== parsedVal) {
                        parsedVal = newVal;
                        correctedValue = true;
                    }
                }
                else {
                    // Truncate fractional values
                    parsedVal = Math.floor(parsedVal);
                    correctedValue = true;
                }
            }
            if (correctedValue) {
                finalStringVal = parsedVal.toString();
            }
            
            // valid -- update last valid
            this.lastValidValue[name] = finalStringVal;
        }

        if (invalidValue) {
            // reset to last valid
            $inputEl.val(beforeStringVal);
            if (name === "scale") {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_SCALE_INVALID);
                Headlights.logData(Headlights.SETTINGS_GROUP, Headlights.SETTING_SCALE_INVALID, editedStringVal);
            } else {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_WH_INVALID);
            }
        } else if (correctedValue) {
            $inputEl.val(parsedVal);
            if (name === "scale") {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_SCALE_CORRECTED);
                Headlights.logData(Headlights.SETTINGS_GROUP, Headlights.SETTING_SCALE_CORRECTED, editedStringVal);
            } else {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_WH_CORRECTED);
            }
        } else if (finalStringVal !== beforeStringVal) {
            if (name === "scale") {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_SCALE_VALID);
                Headlights.logData(Headlights.SETTINGS_GROUP, Headlights.SETTING_SCALE_VALID, editedStringVal);
            } else if (finalStringVal === "") {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_WH_CLEARED);
            } else {
                Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_WH_VALID);
            }
        }
        
        if (!invalidValue && (name === "width" || name === "height")) {
            this.constrainDimensions(e);
        } else if (name === "canvasWidth" || name === "canvasHeight") {
            if (invalidValue) {
                this.renderCanvasSizes();
            } else if (finalStringVal === "") {
                this.model.unset(name);
            } else {
                this.model.set(name, parsedVal);
            }
        }
    },
    
    _cleanupMouseDownOutsideSlider: function () {
        //clean up event listener
        if (this._fnEvtMouseDown) {
            document.removeEventListener("mousedown", this._fnEvtMouseDown);
            this._fnEvtMouseDown = null;
        }
    },
    
    _scrollQualitySliderIntoView: function ($parentList, preShowHeight) {
        if (!$parentList.length) {
            return;
        }
        var self = this,
            scrollHeight = $parentList[0].scrollHeight,
            fnScrollIntoView = function () {
                var sliderBottom = self.$elQualityText.offset().top + self.$elQualityText.height(),
                    parentListHeight = $parentList.height(),
                    parentScrollTop = $parentList.scrollTop(),
                    scrollPos;
                scrollPos = parentScrollTop + sliderBottom - parentListHeight;
                
                if (parentScrollTop < scrollPos) {
                    $parentList.scrollTop(scrollPos);
                }
            };
            
        if (preShowHeight < scrollHeight) {
            window.setTimeout(fnScrollIntoView, 100);
        } else {
            fnScrollIntoView();
        }
    },

    togglePercentageView: function () {
        var wasShowing = false,
            self = this,
            preShowHeight,
            $parentList = self.$el.parents(".scroller");
        
        if (this.$elQualitySlider.hasClass('show')) {
            wasShowing = true;
        }
        
        if (!wasShowing) {
            if (!this.qualityEnabled) {
                return;
            }
            this._listenForMouseDownOutsideSlider();
            this.$elQualityText.focus();
            
            if ($parentList.length) {
                preShowHeight = $parentList[0].scrollHeight;
            }
            
        } else {
            this._cleanupMouseDownOutsideSlider();
        }
        
        //actually toggle
        this.$elQualitySlider.toggleClass('show');
        
        if (wasShowing) {
            window.setTimeout(function () {
                self.$elQualityText.blur();
            }, 10);
        } else if ($parentList.length) {
            this._scrollQualitySliderIntoView($parentList, preShowHeight);
        }
    },

    updateDisabledState: function () {
        var disabled = this.model.get("disabled");
        this.$("input, button, select").prop("disabled", disabled);
        this.$("label.checkbox").toggleClass("disabled", disabled);
        if (!disabled) {
            this.renderCanvasSizes();
        }
    },

    updateSelectedState: function () {
        this.$layer.toggleClass("selected", !!this.model.get("selected"));
    },

    updateSubSelectedState: function () {
        this.$layer.toggleClass("subselected", !!this.model.get("subselected"));
    },

    changeExportFormat: function () {
        var exFmt = this.$elExportFormat.val().toLowerCase(),
            ext = exFmt,
            quality,
            extIn = this.model.get("extension"),
            fileName = this.model.get("file"),
            baseName,
            desiredBaseName = this.model.get("desiredBaseName"),
            pngMatch = exFmt.match(this._pngregex);
        
        this.transparencyEnabled = true;
        this.transparencySupported = true;
        
        if (this.extSupportsQuality[ext]) {
            quality = parseInt(this.$elQualityRange.val(), 10);
            this.qualityEnabled = true;
            this.$elQualityRow.removeClass("hide");
            this.transparencyEnabled = false;
            
            if (/^png/.test(extIn) && (quality === 8 || quality === 24 || quality === 32)) {
                // png format overloads quality prop, so reset that here
                quality = 100;
                this.$elQualityRange.val(100);
                this.$elQualityRange.change();
            }
        } else {
            this.qualityEnabled = false;
            
            if (pngMatch) {
                if (pngMatch[2] === "8") {
                    this.transparencyEnabled = false;
                    quality = 8;
                } else {
                    ext = "png-32";
                    quality = 32;
                }
            } else {
                this.transparencyEnabled = false;
            }
            
            this.$elQualityRange.val(100);
            this.$elQualityRange.change();
            
            this.$elQualityRow.addClass("hide");
        }

        if (!this._isSVG(ext)) {
            this.$elSvgWarningRow.addClass("hide");
        }

        if (this.transparencyEnabled) {
            this.$elTransparencyRow.removeClass("hide");
            this.$elTransparencyCheckbox.prop("checked", this.transparencySupported);
        } else {
            this.$elTransparencyRow.addClass("hide");
        }
        
        var isPng = function (ext) {
                ext = ext.replace(/png-\d+$/, "png");
                return ext === "png";
            },
            pngToPng = isPng(extIn) && isPng(ext);

        // If the model has a "desiredBasename", it doesn't yet have generator syntax (no existing file ext)
        // so we'll always add the appropriate extension to the base.
        // Otherwise, we'll add the new extension when we actually save the file, but won't change the layer name.
        if (desiredBaseName) {
            baseName = desiredBaseName;
        } else {
            baseName = fileName.slice(0, -1 * (extIn.length + 1));
        }

        if (!pngToPng) {
            if (desiredBaseName && desiredBaseName.trim() !== baseName) {
                baseName = desiredBaseName.trim();
            }
        }
        fileName = baseName + "." + ext;
        this.model.set({
            "file": fileName,
            "extension": ext,
            "quality": quality
        });
    },
    
    changeTransparency: function (e) {
        var pngBits, fileName;
        
        if (this.transparencyEnabled) {
            this.transparencySupported = !this.transparencySupported;
            pngBits = (this.transparencySupported) ? "32" : "24";
            fileName = this.model.get("file");
            fileName = fileName.replace(/\.png(-\d+)?$/, ".png-" + pngBits);
            this.model.set({
                "extension": "png-" + pngBits,
                "file": fileName,
                "quality": pngBits
            });
            this.$elTransparencyCheckbox.prop("checked", this.transparencySupported);
            e.preventDefault();
            e.stopPropagation();
        }
    },

    getScaledDimensions: function (percent) {
        if (!percent) {
            percent = (this.model.get("scale") || 1) * 100;
        }
        
        var origDim = this.model.getNaturalImageDimensions();
        
        return {
            height: Math.ceil(origDim.height * percent / 100),
            width: Math.ceil(origDim.width * percent / 100)
        };
        
    },

    changeScaleVal: function (newScale) {
        var dim = this.getScaledDimensions(newScale);

        this.$height.val(dim.height);
        this.$width.val(dim.width);
        this.lastValidValue.height = dim.height.toString();
        this.lastValidValue.width = dim.width.toString();
        this.persistOptions();
    },
    
    changeScaleSel: function () {
        var newScale = this.$scaleSel.val();
        newScale = String(Math.min(newScale, this.model.getMaxScale()));
        Headlights.logEvent(Headlights.CREMA_ACTION, Headlights.SETTING_SCALE_SELECTOR);
        Headlights.logData(Headlights.SETTINGS_GROUP, Headlights.SETTING_SCALE_SELECTOR, newScale);
        this.lastValidValue.scale = newScale;
        this.changeScaleVal(newScale);
        this.$scaleText.val(newScale + "%");
    },

    changeScaleText: function (e) {
        this.handleDimensionScaleChange(e);

        var newScale = this.$scaleText.val();
        this.changeScaleVal(newScale);
        this.$scaleText.val(newScale + "%");
        this.$scaleSel.val("");
    },
    
    changeInterpolationSel: function () {
        this.model.set("interpolationType", this.$elInterpolationSel.val());
    },

    keyupQualityText: function (evt) {
        if (evt.which === 13 || evt.which === 27) { //enter or esc
            if (this.$elQualitySlider.hasClass('show')) {
                this.togglePercentageView();
                evt.stopPropagation();
            } else if (evt.which === 13) {//enter
                this.$elQualityText.blur();
                evt.stopPropagation();
            }
        }
    },
    
    persistOptions: function () {
        this.model.set({
            scale: parseFloat(this.lastValidValue.scale) / 100
        });
    },
    getQualityValue: function () {
        var value = this.fixUpInvalidInput(this.$elQualityText);
        value = parseInt(value, 10);
        if (value > 100) {
            value = 100;
        }
        return value;
    },

    keyboardQualityChange: function (e) {
        var delta = 0,
            intVal = this.getQualityValue(),
            slideIsOpen = this.$elQualitySlider.hasClass('show');

        if (e.keyCode === 40 || (e.keyCode === 37 && slideIsOpen)) {
            delta = -1;
        }
        if (e.keyCode === 38 || (e.keyCode === 39 && slideIsOpen)) {
            delta = 1;
        }
        if (delta !== 0) {
            this.$elQualityRange.val(intVal + delta);
            this.$elQualityRange.trigger("change");
            e.preventDefault();
        }
    },

    changeQualityText: function () {
        var intVal = this.getQualityValue();
        if (_.isFinite(intVal)) {
            this.$elQualityRange.val(intVal);
            this.$elQualityRange.trigger("change");
            this.$elQualityText.removeClass("bad-input");
        } else {
            //TBD: force it into a good range?
            
            //bad input
            this.$elQualityText.addClass("bad-input");
        }
        
        this.model.set("quality", intVal);
    },
    
    renderPlaceholderDimensions: function () {
        var newDim = this.model.getNaturalImageDimensions();
        this.$width.attr("placeholder", Math.ceil(newDim.width));
        this.$height.attr("placeholder", Math.ceil(newDim.height));
    },

    debouncedSetQuality: _.debounce(function (model, rngVal) {
        model.set("quality", rngVal);
    }, 500),

    changeQualityRange: function () {
        if (!this.qualityEnabled) {
            return;
        }
        var rngVal = parseInt(this.$elQualityRange.val(), 10);
        
        this.$elQualityText.val(rngVal + "%");
        this.debouncedSetQuality(this.model, rngVal);
    },
    
    resetCanvasDimensions: function () {
        this.model.unset("canvasWidth");
        this.model.unset("canvasHeight");
    },

    _isSVG: function (ext) {
        return (ext.indexOf("svg") > -1);
    }
});

module.exports = GenSettingView;
