;(function(undefined) {
  'use strict';

  /**
   * Sigma SVG Exporter
   * ===================
   *
   * This plugin is designed to export a graph to a svg file that can be
   * downloaded or just used elsewhere.
   *
   * Author: Guillaume Plique (Yomguithereal)
   * Version: 0.0.1
   */

  // Terminating if sigma were not to be found
  if (typeof sigma === 'undefined')
    throw 'sigma.renderers.snapshot: sigma not in scope.';


  /**
   * Polyfills
   */
  var URL = this.URL || this.webkitURL || this;


  /**
   * Utilities
   */
  function createBlob(data) {
    return new Blob(
      [data],
      {type: 'image/svg+xml;charset=utf-8'}
    );
  }

  function download(string, filename) {

    // Creating blob href
    var blob = createBlob(string);

    // Anchor
    var o = {};
    o.anchor = document.createElement('a');
    o.anchor.setAttribute('href', URL.createObjectURL(blob));
    o.anchor.setAttribute('download', filename);

    // Click event
    var event = document.createEvent('MouseEvent');
    event.initMouseEvent('click', true, false, window, 0, 0, 0 ,0, 0,
      false, false, false, false, 0, null);

    URL.revokeObjectURL(blob);

    o.anchor.dispatchEvent(event);
    delete o.anchor;
  }


  /**
   * Defaults
   */
  var DEFAULTS = {
    size: '1000',
    width: '1000',
    height: '1000',
    classes: true,
    labels: true,
    data: false,
    download: false,
    filename: 'graph.svg'
  };

  var XMLNS = 'http://www.w3.org/2000/svg';


  /**
   * Subprocesses
   */
  function optimize(svg, prefix, params) {
    var nodeColorIndex = {},
        edgeColorIndex = {},
        count = 0,
        color,
        style,
        styleText = '',
        f,
        i,
        l;

    // Creating style tag if needed
    if (params.classes) {
      style = document.createElementNS(XMLNS, 'style');
      style.setAttribute('type', 'text/css')
      svg.insertBefore(style, svg.firstChild);
    }

    // Iterating over nodes
    var nodes = svg.querySelectorAll('[id="' + prefix + '-group-nodes"] > [class="' + prefix + '-node"]');

    for (i = 0, l = nodes.length, f = true; i < l; i++) {
      color = nodes[i].getAttribute('fill');

      if (!params.data)
        nodes[i].removeAttribute('data-node-id');

      if (params.classes) {

        if (!(color in nodeColorIndex)) {
          nodeColorIndex[color] = (f ? prefix + '-node' : 'c-' + (count++));
          styleText += '.' + nodeColorIndex[color] + '{fill: ' + color + '}';
        }

        if (nodeColorIndex[color] !== prefix + '-node')
          nodes[i].setAttribute('class', nodes[i].getAttribute('class') + ' ' + nodeColorIndex[color]);
        nodes[i].removeAttribute('fill');
      }

      f = false;
    }

    // Iterating over edges
    var edges = svg.querySelectorAll('[id="' + prefix + '-group-edges"] > [class="' + prefix + '-edge"]');

    for (i = 0, l = edges.length, f = true; i < l; i++) {
      color = edges[i].getAttribute('stroke');

      if (!params.data)
        edges[i].removeAttribute('data-edge-id');

      if (params.classes) {

        if (!(color in edgeColorIndex)) {
          edgeColorIndex[color] = (f ? prefix + '-edge' : 'c-' + (count++));
          styleText += '.' + edgeColorIndex[color] + '{stroke: ' + color + '}';
        }

        if (edgeColorIndex[color] !== prefix + '-edge')
          edges[i].setAttribute('class', edges[i].getAttribute('class') + ' ' + edgeColorIndex[color]);
        edges[i].removeAttribute('stroke');
      }

      f = false;
    }

    if (params.classes)
      style.appendChild(document.createTextNode(styleText));
  }


  /**
   * Extending prototype
   */
  sigma.prototype.toSVG = function(params) {
    params = params || {};

    var prefix = this.settings('classPrefix'),
        w = params.size || params.width || DEFAULTS.size,
        h = params.size || params.height || DEFAULTS.size;

    // Creating a dummy container
    var container = document.createElement('div');
    container.setAttribute('width', w);
    container.setAttribute('height', h);
    container.setAttribute('style', 'position:absolute; top: 0px; left:0px; width: ' + w + 'px; height: ' + h + 'px;');

    // Creating a camera
    var camera = this.addCamera();

    // Creating a svg renderer
    var renderer = this.addRenderer({
      camera: camera,
      container: container,
      type: 'svg',
      forceLabels: !!params.labels
    });

    // Refreshing
    renderer.resize(w, h);
    this.refresh();

    // Dropping camera and renderers before something nasty happens
    this.killRenderer(renderer);
    this.killCamera(camera);

    // Retrieving svg
    var svg = container.querySelector('svg');
    svg.removeAttribute('style');
    svg.setAttribute('width', w + 'px');
    svg.setAttribute('height', h + 'px');
    svg.setAttribute('x', '0px');
    svg.setAttribute('y', '0px');
    // svg.setAttribute('viewBox', '0 0 1000 1000');

    // Dropping labels
    if (!params.labels) {
      var labelGroup = svg.querySelector('[id="' + prefix + '-group-labels"]');
      svg.removeChild(labelGroup);
    }

    // Dropping hovers
    var hoverGroup = svg.querySelector('[id="' + prefix + '-group-hovers"]');
    svg.removeChild(hoverGroup);

    // Optims?
    params.classes = (params.classes !== false);
    if (!params.data || params.classes)
      optimize(svg, prefix, params);

    // Retrieving svg string
    var svgString = svg.outerHTML;

    // Paranoid cleanup
    container = null;

    // Output string
    var output = '<?xml version="1.0" encoding="utf-8"?>\n';
    output += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
    output += svgString;

    if (params.download)
      download(output, params.filename || DEFAULTS.filename);

    return output;
  };
}).call(this);
