/**
 * ---------------------------------------------------------------------
 * GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2015-2021 Teclib' and contributors.
 *
 * http://glpi-project.org
 *
 * based on GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2003-2014 by the INDEPNET Development Team.
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * GLPI is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * GLPI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GLPI. If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------
 */

/* global fileType, getExtIcon, getSize, isImage, stopEvent, Uint8Array */

function uploadFile(file, editor, input_name) {
   var returnTag = false;

   //Create formdata from file to send with ajax request
   var formdata = new FormData();
   formdata.append('filename[0]', file, file.name);
   formdata.append('name', 'filename');

   // upload file with ajax
   $.post({
      url: CFG_GLPI.root_doc+'/ajax/fileupload.php',
      data: formdata,
      processData: false,
      contentType: false,
      dataType: 'JSON',
      async: false,
      success: function(data) {
         $.each(data, function(index, element) {
            if (element[0].error === undefined) {
               returnTag = '';
               var tag = getFileTag(element);
               //if is an image add tag
               if (isImage(file)) {
                  returnTag = tag.tag;
               }
               //display uploaded file
               displayUploadedFile(element[0], tag, editor, input_name);
            } else {
               returnTag = false;
               alert(element[0].error);
            }
         });
      },

      error: function (request) {
         // If this is an error on the return
         if ("responseText" in request && request.responseText.length > 0) {
            alert(request.responseText);
         } else {
            // Error before sending request #3866
            alert(request.statusText);
         }
      }
   });

   return returnTag;
}

/**
 * Gets the file tag.
 *
 * @param      {(boolean|string)}  data receive from uploadFile
 * @return     {(boolean|string)}  The file tag.
 */
var getFileTag = function(data) {
   var returnString = '';

   $.ajax({
      type: 'POST',
      url: CFG_GLPI.root_doc+'/ajax/getFileTag.php',
      data: {'data':data},
      dataType: 'JSON',
      async: false,
      success: function(data) {
         returnString = data[0];
      },
      error: function (request) {
         console.warn(request.responseText);
         returnString=false;
      }
   });

   return returnString;
};

/**
 * Display list of uploaded file with their size
 *
 * @param      {JSON}    file          The file
 * @param      {String}  tag           The tag
 * @param      {Object}  editor        The TinyMCE editor instance
 * @param      {String}  input_name    Name of generated input hidden (default filename)
 */
var fileindex = 0;
var displayUploadedFile = function(file, tag, editor, input_name) {
   // default argument(s)
   input_name = (typeof input_name === 'undefined' || input_name == null) ? 'filename' : input_name;

   // find the nearest fileupload_info where to append file list
   var current_dom_point = $(editor.targetElm);
   var iteration = 0;
   var filecontainer;
   do {
      current_dom_point = current_dom_point.parent();
      filecontainer = current_dom_point.find('.fileupload_info');
      iteration++;
   } while (filecontainer.length <= 0 && iteration < 30);

   if (filecontainer.length) {
      var ext = file.name.split('.').pop();

      var p = $('<p></p>')
         .attr('id',file.id)
         .html(
            getExtIcon(ext)
            + '&nbsp;'
            + '<b>'+file.display
            + '</b>'
            + '&nbsp;('
            + getSize(file.size)+')&nbsp;'
         ).appendTo(filecontainer);

      // File
      $('<input/>')
         .attr('type', 'hidden')
         .attr('name', '_'+input_name+'['+fileindex+']')
         .attr('value', file.name).appendTo(p);

      // Prefix
      $('<input/>')
         .attr('type', 'hidden')
         .attr('name', '_prefix_'+input_name+'['+fileindex+']')
         .attr('value', file.prefix).appendTo(p);

      // Tag
      $('<input/>')
         .attr('type', 'hidden')
         .attr('name', '_tag_'+input_name+'['+fileindex+']')
         .attr('value', tag.name)
         .appendTo(p);

      // Delete button
      var elementsIdToRemove = {0:file.id, 1:file.id+'2'};
      $('<span class="fa fa-times-circle pointer"></span>').click(function() {
         deleteImagePasted(elementsIdToRemove, tag.tag, editor);
      }).appendTo(p);

      fileindex++;
   }
};

/**
 * Remove image pasted or droped
 *
 * @param      {Array}   elementsIdToRemove  The elements identifier to remove
 * @param      {string}  tagToRemove         The tag to remove
 * @param      {Object}  editor              The editor
 */
var deleteImagePasted = function(elementsIdToRemove, tagToRemove, editor) {
   // Remove file display lines
   $.each(elementsIdToRemove, function (index, element) {
      $('#'+element).remove();
   });

   if (typeof editor !== "undefined"
       && typeof editor.dom !== "undefined") {
      editor.setContent(editor.getContent().replace('<p>'+tagToRemove+'</p>', ''));

      var regex = new RegExp('#', 'g');
      editor.dom.remove(tagToRemove.replace(regex, ''));
   }
};

/**
 * Insert an (uploaded) image in the the tinymce 'editor'
 *
 * @param  {Object}   TinyMCE editor instance
 * @param  {Blob}     fileImg
 * @param  {string}   tag
 */
var insertImgFromFile = function(editor, fileImg, tag) {
   var urlCreator = window.URL || window.webkitURL;
   var imageUrl   = urlCreator.createObjectURL(fileImg);
   var regex      = new RegExp('#', 'g');
   var maxHeight  = $(tinyMCE.activeEditor.getContainer()).height() - 60;
   var maxWidth   = $(tinyMCE.activeEditor.getContainer()).width()  - 120;

   if (window.FileReader && window.File && window.FileList && window.Blob ) {
      // indicate loading in tinymce
      editor.setProgressState(true);

      var reader = new FileReader();
      reader.onload = (function(theFile) {
         var image    = new Image();
         image.src    = theFile.target.result;
         image.onload = function() {
            // access image size here
            var imgWidth  = this.width;
            var imgHeight = this.height;
            var ratio     = 0;

            if (imgWidth > maxWidth) {
               ratio     = maxWidth / imgWidth; // get ratio for scaling image
               imgHeight = imgHeight * ratio;   // Reset height to match scaled image
               imgWidth  = imgWidth * ratio;    // Reset width to match scaled image
            }

            // Check if current height is larger than max
            if (imgHeight > maxHeight) {
               ratio     = maxHeight / imgHeight; // get ratio for scaling image
               imgWidth  = imgWidth * ratio;      // Reset width to match scaled image
               imgHeight = imgHeight * ratio;     // Reset height to match scaled image
            }

            editor.execCommand(
               'mceInsertContent',
               false,
               "<img width='"+imgWidth+"' height='"+imgHeight+"'' id='"+tag.replace(regex,'')+"' src='"+imageUrl+"'>"
            );

            // loading done, remove indicator
            editor.setProgressState(false);
         };
      });
      reader.readAsDataURL(fileImg);

   } else {
      console.warn('thanks to update your browser to get preview of image');
   }
};

/**
 * Convert dataURI to BLOB
 *
 * @param      {Object}  dataURI  The data uri
 * @return     {Blob}    { description_of_the_return_value }
 */
var dataURItoBlob = function(dataURI) {
   // convert base64/URLEncoded data component to raw binary data held in a string
   var byteString;
   if (dataURI.split(',')[0].indexOf('base64') >= 0) {
      byteString = atob(dataURI.split(',')[1]);
   } else {
      byteString = unescape(dataURI.split(',')[1]);
   }

   // separate out the mime component
   var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
   var imgExt = mimeString.split('/')[1];

   // write the bytes of the string to a typed array
   var ia = new Uint8Array(byteString.length);
   for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
   }

   var file = new Blob([ia], {type:mimeString});
   file.name = 'image_paste' + Math.floor((Math.random() * 10000000) + 1) + '.' + imgExt;

   return file;
};

/**
* Function to check if data paste on TinyMCE is an image
*
* @param      String content  The img tag
* @return     String mimeType   return mimeType of data
*/
var isImageFromPaste = function(content) {
   return content.match(new RegExp('<img.*data:image/')) !== null;
};

/**
* Function to check if data paste on TinyMCE is an image
*
* @param      String content  The img tag
* @return     String mimeType   return mimeType of data
*/
var isImageBlobFromPaste = function(content) {
   return content.match(new RegExp('<img.*src=[\'"]blob:')) !== null;
};

/**
* Function to extract src tag from img tag process by TinyMCE
*
* @param  {string}  content  The img tag
* @return {string}  Source of image or empty string.
*/
var extractSrcFromImgTag = function(content) {
   var foundImage = $('<div></div>').append(content).find('img');
   if (foundImage.length > 0) {
      return foundImage.attr('src');
   }

   return '';
};

/**
 * Insert an image file into the specified tinyMce editor
 * @param  {Object} editor The tinyMCE editor
 * @param  {Blob}   image  The image to insert
 */
var insertImageInTinyMCE = function(editor, image) {
   //make ajax call for upload doc
   var input_name = $(editor.targetElm).attr('name');
   var tag = uploadFile(image, editor, input_name);
   if (tag !== false) {
      insertImgFromFile(editor, image, tag);
   }

   return tag;
};

/**
 * Plugin for tinyMce editor who intercept paste event
 * to check if a file upload can be proceeded
 * @param  {[Object]} editor TinyMCE editor
 */
if (typeof tinyMCE != 'undefined') {
   tinyMCE.PluginManager.add('glpi_upload_doc', function(editor) {
      editor.on('PastePreProcess', function(event) {
         //Check if data is an image
         if (isImageFromPaste(event.content)) {
            stopEvent(event);

            //extract base64 data
            var base64 = extractSrcFromImgTag(event.content);

            //transform to blob and insert into editor
            if (base64.length) {
               var file = dataURItoBlob(base64);

               insertImageInTinyMCE(editor, file);
            }

         } else if (isImageBlobFromPaste(event.content)) {
            stopEvent(event);

            var src = extractSrcFromImgTag(event.content);

            var xhr = new XMLHttpRequest();
            xhr.open('GET', src, true);
            xhr.responseType = 'arraybuffer';
            xhr.onload = function() {
               if (this.status !== 200) {
                  console.error("paste error");
                  return;
               }

               var imgData = new Uint8Array(this.response);
               // fileType.fromBuffer() returns a promise (async method)
               fileType.fromBuffer(imgData).then(function(imgType) {
                  if (!imgType || !imgType.ext || !imgType.mime) {
                     // Unable to retrieve file ext
                     console.error("paste error");
                     return;
                  }

                  var file  = new Blob([imgData.buffer], {type: imgType.mime});
                  file.name = 'image_paste' + Math.floor((Math.random() * 10000000) + 1) + '.' + imgType.ext;

                  insertImageInTinyMCE(editor, file);
               });
            };
            xhr.send();
         }
      });
   });
}


$(function() {
   // set a function to track drag hover event
   $(document).bind('dragover', function (event) {
      event.preventDefault();

      var dropZone = $('.dropzone');
      var foundDropzone;
      var timeout = window.dropZoneTimeout;

      if (!timeout) {
         dropZone.addClass('dragin');
      } else {
         clearTimeout(timeout);
      }

      var found = false;
      var node = event.target;

      do {
         if ($(node).hasClass('draghoverable')) {
            found = true;
            foundDropzone = $(node);
            break;
         }

         node = node.parentNode;
      } while (node !== null);

      dropZone.removeClass('dragin draghover');

      if (found) {
         foundDropzone.addClass('draghover');
      }
   });

   // remove dragover styles on drop
   $(document).bind('drop', function(event) {
      event.preventDefault();
      $('.draghoverable').removeClass('draghover');

      // if file present, insert it in filelist
      if (typeof event.originalEvent.dataTransfer.files !== 'undefined') {
         $.each(event.originalEvent.dataTransfer.files, function(index, element) {
            var input_name = null;
            var input_file = $(event.target).find('input[type=file][name]');
            if (input_file.length) {
               input_name = input_file.attr('name').replace('[]', '');
            }
            uploadFile(
               element,
               {targetElm: $(event.target).find('.fileupload_info')},
               input_name
            );
         });
      }
   });
});
