/**
 * Plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

define(
  'tinymce.plugins.media.Plugin',
  [
    'tinymce.core.html.Node',
    'tinymce.core.PluginManager',
    'tinymce.core.util.Tools',
    'tinymce.plugins.media.core.Nodes',
    'tinymce.plugins.media.core.Sanitize',
    'tinymce.plugins.media.core.UpdateHtml',
    'tinymce.plugins.media.ui.Dialog'
  ],
  function (Node, PluginManager, Tools, Nodes, Sanitize, UpdateHtml, Dialog) {
    var Plugin = function (editor) {
      editor.on('ResolveName', function (e) {
        var name;

        if (e.target.nodeType === 1 && (name = e.target.getAttribute("data-mce-object"))) {
          e.name = name;
        }
      });

      editor.on('preInit', function () {
        // Make sure that any messy HTML is retained inside these
        var specialElements = editor.schema.getSpecialElements();
        Tools.each('video audio iframe object'.split(' '), function (name) {
          specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi');
        });

        // Allow elements
        //editor.schema.addValidElements(
        //  'object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]'
        //);

        // Set allowFullscreen attribs as boolean
        var boolAttrs = editor.schema.getBoolAttrs();
        Tools.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function (name) {
          boolAttrs[name] = {};
        });

        // Converts iframe, video etc into placeholder images
        editor.parser.addNodeFilter('iframe,video,audio,object,embed,script',
          Nodes.placeHolderConverter(editor));

        // Replaces placeholder images with real elements for video, object, iframe etc
        editor.serializer.addAttributeFilter('data-mce-object', function (nodes, name) {
          var i = nodes.length;
          var node;
          var realElm;
          var ai;
          var attribs;
          var innerHtml;
          var innerNode;
          var realElmName;
          var className;

          while (i--) {
            node = nodes[i];
            if (!node.parent) {
              continue;
            }

            realElmName = node.attr(name);
            realElm = new Node(realElmName, 1);

            // Add width/height to everything but audio
            if (realElmName !== "audio" && realElmName !== "script") {
              className = node.attr('class');
              if (className && className.indexOf('mce-preview-object') !== -1) {
                realElm.attr({
                  width: node.firstChild.attr('width'),
                  height: node.firstChild.attr('height')
                });
              } else {
                realElm.attr({
                  width: node.attr('width'),
                  height: node.attr('height')
                });
              }
            }

            realElm.attr({
              style: node.attr('style')
            });

            // Unprefix all placeholder attributes
            attribs = node.attributes;
            ai = attribs.length;
            while (ai--) {
              var attrName = attribs[ai].name;

              if (attrName.indexOf('data-mce-p-') === 0) {
                realElm.attr(attrName.substr(11), attribs[ai].value);
              }
            }

            if (realElmName === "script") {
              realElm.attr('type', 'text/javascript');
            }

            // Inject innerhtml
            innerHtml = node.attr('data-mce-html');
            if (innerHtml) {
              innerNode = new Node('#text', 3);
              innerNode.raw = true;
              innerNode.value = Sanitize.sanitize(editor, unescape(innerHtml));
              realElm.append(innerNode);
            }

            node.replace(realElm);
          }
        });
      });

      editor.on('click keyup', function () {
        var selectedNode = editor.selection.getNode();

        if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
          if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
            selectedNode.setAttribute('data-mce-selected', '2');
          }
        }
      });

      editor.on('ObjectSelected', function (e) {
        var objectType = e.target.getAttribute('data-mce-object');

        if (objectType === "audio" || objectType === "script") {
          e.preventDefault();
        }
      });

      editor.on('objectResized', function (e) {
        var target = e.target;
        var html;

        if (target.getAttribute('data-mce-object')) {
          html = target.getAttribute('data-mce-html');
          if (html) {
            html = unescape(html);
            target.setAttribute('data-mce-html', escape(
              UpdateHtml.updateHtml(html, {
                width: e.width,
                height: e.height
              })
            ));
          }
        }
      });

      this.showDialog = function () {
        Dialog.showDialog(editor);
      };

      editor.addButton('media', {
        tooltip: 'Insert/edit media',
        onclick: this.showDialog,
        stateSelector: ['img[data-mce-object]', 'span[data-mce-object]', 'div[data-ephox-embed-iri]']
      });

      editor.addMenuItem('media', {
        icon: 'media',
        text: 'Media',
        onclick: this.showDialog,
        context: 'insert',
        prependToContext: true
      });

      editor.on('setContent', function () {
        // TODO: This shouldn't be needed there should be a way to mark bogus
        // elements so they are never removed except external save
        editor.$('span.mce-preview-object').each(function (index, elm) {
          var $elm = editor.$(elm);

          if ($elm.find('span.mce-shim', elm).length === 0) {
            $elm.append('<span class="mce-shim"></span>');
          }
        });
      });

      editor.addCommand('mceMedia', this.showDialog);
    };

    PluginManager.add('media', Plugin);

    return function () { };
  }
);

