text: /**
   * Copyright (c) 2016 Guyon Roche
   *
   * 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.
   *
   */
  'use strict';
  
  var _ = require('underscore');
  
  var utils = require('../../../utils/utils');
  var colCache = require('../../../utils/col-cache');
  var XmlStream = require('../../../utils/xml-stream');
  
  var BaseXform = require('../base-xform');
  var StaticXform = require('../static-xform');
  var ListXform = require('../list-xform');
  var DefinedNameXform = require('./defined-name-xform');
  var SheetXform = require('./sheet-xform');
  var WorkbookViewXform = require('./workbook-view-xform');
  
  var WorkbookXform = module.exports = function() {
    this.map = {
      fileVersion: WorkbookXform.STATIC_XFORMS.fileVersion,
      workbookPr: WorkbookXform.STATIC_XFORMS.workbookPr,
      bookViews: new ListXform({tag: 'bookViews', count: false, childXform: new WorkbookViewXform()}),
      sheets: new ListXform({tag: 'sheets', count: false, childXform: new SheetXform()}),
      definedNames: new ListXform({tag: 'definedNames', count: false, childXform: new DefinedNameXform()}),
      calcPr: WorkbookXform.STATIC_XFORMS.calcPr
    };
  };
  
  utils.inherits(WorkbookXform, BaseXform, {
    WORKBOOK_ATTRIBUTES: {
      'xmlns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
      'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
      'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
      'mc:Ignorable': 'x15',
      'xmlns:x15': 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main'
    },
    STATIC_XFORMS: {
      fileVersion: new StaticXform({tag: 'fileVersion', $: {appName: 'xl', lastEdited: 5, lowestEdited: 5, rupBuild: 9303}}),
      workbookPr: new StaticXform({tag: 'workbookPr', $: {defaultThemeVersion: 164011, filterPrivacy: 1}}),
      calcPr: new StaticXform({tag: 'calcPr', $: {calcId: 171027}})
    }
  },{
  
    prepare: function(model) {
      model.sheets = model.worksheets;
  
      // collate all the print areas from all of the sheets and add them to the defined names
      var printAreas = [];
      var index = 0; // sheets is sparse array - calc index manually
      _.each(model.sheets, function(sheet) {
        if (sheet.pageSetup && sheet.pageSetup.printArea) {
          var definedName = {
            name: '_xlnm.Print_Area',
            ranges: [sheet.pageSetup.printArea],
            localSheetId: index
          };
          printAreas.push(definedName);
        }
        index++;
      });
      if (printAreas.length) {
        model.definedNames = model.definedNames.concat(printAreas);
      }
    },
  
    render: function(xmlStream, model) {
      xmlStream.openXml(XmlStream.StdDocAttributes);
      xmlStream.openNode('workbook', WorkbookXform.WORKBOOK_ATTRIBUTES);
  
      this.map.fileVersion.render(xmlStream);
      this.map.workbookPr.render(xmlStream);
      this.map.bookViews.render(xmlStream, model.views);
      this.map.sheets.render(xmlStream, model.sheets);
      this.map.definedNames.render(xmlStream, model.definedNames);
      this.map.calcPr.render(xmlStream);
  
      xmlStream.closeNode();
    },
  
    parseOpen: function(node) {
      if (this.parser) {
        this.parser.parseOpen(node);
        return true;
      } else {
        switch(node.name) {
          case 'workbook':
            return true;
          default:
            this.parser = this.map[node.name];
            if (this.parser) {
              this.parser.parseOpen(node);
            }
            return true;
        }
      }
    },
    parseText: function(text) {
      if (this.parser) {
        this.parser.parseText(text);
      }
    },
    parseClose: function(name) {
      if (this.parser) {
        if (!this.parser.parseClose(name)) {
          this.parser = undefined;
        }
        return true;
      } else {
        switch(name) {
          case 'workbook':
            this.model = {
              sheets: this.map.sheets.model
            };
            if (this.map.definedNames.model) {
              this.model.definedNames = this.map.definedNames.model;
            }
            this.model.views = this.map.bookViews.model;
  
            return false;
          default:
            // not quite sure how we get here!
            return true;
        }
      }
    },
  
    reconcile: function(model) {
      var rels = model.workbookRels.reduce(function(map, rel) {
        map[rel.rId] = rel;
        return map;
      }, {});
  
      // reconcile sheet ids, rIds and names
      var worksheets = [];
      var worksheet;
      var index = 0;
      _.each(model.sheets, function(sheet) {
        var rel = rels[sheet.rId];
        if (!rel) {
          return;
        }
        worksheet = model.worksheetHash['xl/' + rel.target];
        worksheet.name = sheet.name;
        worksheet.id = sheet.id;
        worksheets[index++] = worksheet;
      });
  
      // reconcile print areas
      var definedNames = [];
      _.each(model.definedNames, function(definedName) {
        if (definedName.name === '_xlnm.Print_Area') {
          worksheet = worksheets[definedName.localSheetId];
          if (worksheet) {
            if (!worksheet.pageSetup) { worksheet.pageSetup = {}; }
            var range  =  colCache.decodeEx(definedName.ranges[0]);
            worksheet.pageSetup.printArea = range.dimensions;
          }
        } else {
          definedNames.push(definedName);
        }
      });
      model.definedNames = definedNames;
    }
  });
  