text: /*
   * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
   *  
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"), 
   * to deal in the Software without restriction, including without limitation 
   * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
   * and/or sell copies of the Software, and to permit persons to whom the 
   * Software is furnished to do so, subject to the following conditions:
   *  
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *  
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
   * DEALINGS IN THE SOFTWARE.
   * 
   */
  
  (function () {
      "use strict";
  
      var parse = require("./parser").parse;
  
      /**
       * The ParserManager manages parsing, normalization and analysis of layer
       * names into asset specifications. The config parameter can be used to enable
       * svg and webp parsing if the "svg-enabled" and "webp-enabled" parameters are
       * set, resp.
       * 
       * @constructor
       * @param {object} config
       */
      function ParserManager(config) {
          this._config = config || {};
  
          this._supportedUnits = {
              "in": true,
              "cm": true,
              "px": true,
              "mm": true
          };
  
          this._supportedExtensions = {
              "jpg": true,
              "png": true,
              "gif": true,
              "svg": this._config.hasOwnProperty("svg-enabled") ? !!this._config["svg-enabled"] : true,
              "webp": !!this._config["webp-enabled"]
          };
      }
  
      /**
       * Set of supported units of measurement.
       * 
       * @type {{string: boolean}}
       */
      ParserManager.prototype._supportedUnits = null;
  
      /**
       * Set of supported units of file extensions.
       * 
       * @type {{string: boolean}}
       */
      ParserManager.prototype._supportedExtensions = null;
  
      /**
       * Parse a layer name into a non-empty array of file specification parts.
       * If a given layer specification part can be parsed into a file specification,
       * then the resulting object has at least "file" and "extension" properties,
       * and possibly also "quality", "width", "height", "widthUnit" and "heightUnit"
       * properties as well. Otherwise, if a given layer name part (or the entire
       * layer name) can't be parsed into a file specification, then the resulting
       * object just has a single "name" property, which is the same as the input
       * string.
       * 
       * @private
       * @param {string} layerName
       * @returns {Array.<{name: string} | {file: string, extension: string}>}
       */
      ParserManager.prototype._parseLayerName = function (layerName) {
          return parse(layerName);
      };
  
      /**
       * Normalize the properties of the given component. Updates the object in place.
       * 
       * @private
       * @param {Component} component
       */
      ParserManager.prototype._normalizeComponent = function (component) {
          if (component.hasOwnProperty("extension")) {
              var extension = component.extension.toLowerCase();
  
              if (extension === "jpeg") {
                  extension = "jpg";
              }
  
              component.extension = extension;
  
              if (component.hasOwnProperty("quality")) {
                  var quality = component.quality;
                  if (quality[quality.length - 1] === "%") {
                      quality = parseInt(quality.substring(0, quality.length - 1), 10);
                  } else if (extension === "png" && quality[quality.length - 1] === "a") {
                      // normalize png24a -> png32
                      quality = parseInt(quality.substring(0, quality.length - 1), 10);
                      quality += 8;
                  } else {
                      quality = parseInt(quality, 10);
  
                      if (extension !== "png") {
                          quality *= 10;
                      }
                  }
  
                  component.quality = quality;
              }
          }
  
          if (component.hasOwnProperty("widthUnit")) {
              component.widthUnit = component.widthUnit.toLowerCase();
          }
  
          if (component.hasOwnProperty("heightUnit")) {
              component.heightUnit = component.heightUnit.toLowerCase();
          }
      };
  
      /**
       * Analyze the component, returning a list of errors.
       * 
       * @private
       * @param {Component} component
       * @return {Array.<string>} The possibly empty list of analysis errors. 
       */
      ParserManager.prototype._analyzeComponent = function (component) {
          var errors = [];
  
          if (component.scale === 0) {
              errors.push("Invalid scale: 0%");
          }
  
          if (component.width === 0) {
              errors.push("Invalid width: 0");
          }
  
          if (component.height === 0) {
              errors.push("Invalid height: 0");
          }
  
          if (component.widthUnit && !this._supportedUnits[component.widthUnit]) {
              errors.push("Invalid width unit: " + component.widthUnit);
          }
          
          if (component.heightUnit && !this._supportedUnits[component.heightUnit]) {
              errors.push("Invalid height unit: " + component.heightUnit);
          }
  
          if (component.extension && !this._supportedExtensions[component.extension]) {
              errors.push("Unsupported extension: " + component.extension);
          }
  
          if (component.hasOwnProperty("quality")) {
              var quality = component.quality,
                  invalidQuality = false;
  
              switch (component.extension) {
              case "jpg":
              case "webp":
                  if (quality < 1 || quality > 100) {
                      invalidQuality = true;
                  }
                  break;
              case "png":
                  if (!(quality === 8 || quality === 24 || quality === 32)) {
                      invalidQuality = true;
                  }
                  break;
              default:
                  invalidQuality = true;
              }
  
              if (invalidQuality) {
                  errors.push("Invalid quality: " + quality);
              }
          }
  
          return errors;
      };
  
      /**
       * Parse a layer name, returning a list of objects that contain a parsed
       * component and a list of errors encountered while analyzing that component.
       * The component denotes a valid asset iff there are no analysis errors and
       * the component contains either a "file" property (if it is a "basic"
       * component that describes a single asset) or a "default" property (if it
       * is default component that is used to derive non-basic components.)
       *
       * @param {string} layerName
       * @return {Array.<{component: Component, errors: Array.<string>}>}
       */
      ParserManager.prototype.analyzeLayerName = function (layerName) {
          var components;
  
          try {
              components = this._parseLayerName(layerName);
          } catch (parseError) {
              return [{
                  component: { name: layerName },
                  errors: [parseError.message]
              }];
          }
  
          return components.map(function (component) {
              this._normalizeComponent(component);
  
              return {
                  component: component,
                  errors: this._analyzeComponent(component)
              };
          }, this);
      };
  
      module.exports = ParserManager;
  }());
  