'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _createClass = require('@babel/runtime/helpers/createClass');
var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn');
var _getPrototypeOf = require('@babel/runtime/helpers/getPrototypeOf');
var _inherits = require('@babel/runtime/helpers/inherits');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
require('core-js/modules/es.symbol.js');
require('core-js/modules/es.symbol.description.js');
require('core-js/modules/es.array.concat.js');
require('core-js/modules/es.array.filter.js');
require('core-js/modules/es.array.find-index.js');
require('core-js/modules/es.array.map.js');
require('core-js/modules/es.function.name.js');
require('core-js/modules/es.object.to-string.js');
require('core-js/modules/es.object.values.js');
require('core-js/modules/es.reflect.construct.js');
require('core-js/modules/es.string.trim.js');
var React = require('react');
var PropTypes = require('prop-types');
var react = require('@carbon/react');
var Settings = require('../../constants/Settings.js');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var _createClass__default = /*#__PURE__*/_interopDefault(_createClass);
var _classCallCheck__default = /*#__PURE__*/_interopDefault(_classCallCheck);
var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefault(_possibleConstructorReturn);
var _getPrototypeOf__default = /*#__PURE__*/_interopDefault(_getPrototypeOf);
var _inherits__default = /*#__PURE__*/_interopDefault(_inherits);
var _defineProperty__default = /*#__PURE__*/_interopDefault(_defineProperty);
var React__default = /*#__PURE__*/_interopDefault(React);
var PropTypes__default = /*#__PURE__*/_interopDefault(PropTypes);

function _callSuper(t, o, e) { return o = _getPrototypeOf__default.default(o), _possibleConstructorReturn__default.default(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf__default.default(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
var iotPrefix = Settings.settings.iotPrefix,
  prefix = Settings.settings.prefix;
var FILE_TYPES = {
  TEXT: 'TEXT',
  BINARY: 'BINARY'
};
var propTypes = {
  /** DOM ID */
  id: PropTypes__default.default.string,
  /** Title text  */
  title: PropTypes__default.default.string,
  /** Description text of file uploader */
  description: PropTypes__default.default.string,
  /** Optionally show the uploaded files */
  showFiles: PropTypes__default.default.bool,
  /** Button label  */
  buttonLabel: PropTypes__default.default.string,
  /** can multiple files be uploaded */
  multiple: PropTypes__default.default.bool,
  /** File types that are accepted */
  accept: PropTypes__default.default.arrayOf(PropTypes__default.default.string),
  /** Componet is drag/drop */
  kind: PropTypes__default.default.oneOf(['browse', 'drag-and-drop']),
  /** Callback to return the loaded file(s) data */
  onData: PropTypes__default.default.func,
  /** Callback for file load errors */
  onError: PropTypes__default.default.func,
  dragAndDropLabel: PropTypes__default.default.string,
  /** file type either TEXT or BINARY to determine the correct encoding */
  fileType: PropTypes__default.default.oneOf(Object.values(FILE_TYPES)),
  testId: PropTypes__default.default.string
};
/* istanbul ignore next */
var defaultProps = {
  id: 'FileUploader',
  buttonLabel: 'Add files',
  title: null,
  description: null,
  kind: 'browse',
  multiple: true,
  showFiles: true,
  accept: [],
  onData: function onData() {},
  onError: function onError() {},
  dragAndDropLabel: 'Drag and drop your file here or ',
  fileType: FILE_TYPES.BINARY,
  testId: 'file-drop'
};

/**
 * Carbon File Uploader with added ability to have drag and drop
 */
var FileDrop = /*#__PURE__*/function (_React$Component) {
  function FileDrop() {
    var _this;
    _classCallCheck__default.default(this, FileDrop);
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _callSuper(this, FileDrop, [].concat(args));
    _defineProperty__default.default(_this, "fileInput", null);
    _defineProperty__default.default(_this, "nodes", []);
    _defineProperty__default.default(_this, "readers", {});
    _defineProperty__default.default(_this, "state", {
      files: [],
      hover: false
    });
    /* Drag hover event */
    _defineProperty__default.default(_this, "fileDragHover", function (evt) {
      evt.preventDefault();
      var rect = evt.currentTarget.getBoundingClientRect();
      var x = evt.pageX - window.pageXOffset;
      var y = evt.pageY - window.pageYOffset;
      var inArea = !(x < rect.left || x > rect.right || y < rect.top || y > rect.bottom);
      _this.setState({
        hover: inArea && evt.type !== 'drop'
      });
    });
    /* Drop event */
    _defineProperty__default.default(_this, "fileDrop", function (evt) {
      evt.stopPropagation();
      _this.fileDragHover(evt);
      var files = evt.target.files || evt.dataTransfer.files;
      _this.addNewFiles(files);
    });
    /**
     * takes a array of File javascript objects https://developer.mozilla.org/en-US/docs/Web/API/File
     * and creates a FileReader for each one, setting up the appropriate onload, onerror handlers, and then
     * actually calls the readAsBinaryString method to trigger the loading of the file.
     */
    _defineProperty__default.default(_this, "readFileContent", function (files) {
      var fileType = _this.props.fileType;
      Array.prototype.forEach.call(files, function (file) {
        _this.readers[file.name] = new FileReader();
        _this.readers[file.name].onload = function () {
          return _this.handleFileLoad(file);
        };
        _this.readers[file.name].onerror = function (evt) {
          return _this.handleFileError(evt, file);
        };
        if (fileType === FILE_TYPES.BINARY) {
          _this.readers[file.name].readAsBinaryString(file);
        } else {
          _this.readers[file.name].readAsText(file);
        }
      });
    });
    /**
     * In the error handler if calls the onError once for any file where content load fails and clears the reader
     */
    _defineProperty__default.default(_this, "handleFileError", function (evt, file) {
      delete _this.readers[file.name];
      return _this.props.onError(evt);
    });
    /**
     * After the file is read in the success handler, it updates the state with the file contents.
     * After the last one is read it calls the onData callback to update the parent.
     *
     * Finally it clears the reader
     */
    _defineProperty__default.default(_this, "handleFileLoad", function (file) {
      _this.setState(function (state) {
        var newState = {
          files: state.files.map(function (i) {
            return i.name === file.name // only change the new reader result, preserve the rest
            ? {
              name: i.name,
              uploadState: 'edit',
              contents: _this.readers[file.name].result
            } : i;
          })
        };
        if (newState.files.filter(function (i) {
          return i.contents === null;
        }).length === 0) {
          // all data is loaded, trigger callback
          _this.props.onData(newState.files.map(function (i) {
            return {
              name: i.name,
              contents: i.contents
            };
          }));
        }
        return newState;
      }, function () {
        delete _this.readers[file.name];
      });
    });
    _defineProperty__default.default(_this, "addNewFiles", function (files) {
      var multiple = _this.props.multiple;
      var filenames = Array.prototype.map.call(files, function (f) {
        return f.name;
      });
      _this.setState(function (state) {
        return {
          files: (multiple ? state.files : [] // if we're not multiple, always restart
          ).concat(filenames.map(function (name) {
            return {
              name: name,
              uploadState: 'uploading',
              contents: null
            };
          })).filter(function (elem, index, arr) {
            return index === arr.findIndex(function (indexFound) {
              return indexFound.name === elem.name;
            }) && (multiple || index === 0);
          } // only support the first if set to multiple=false
          )
        };
      });
      _this.readFileContent(files);
    });
    _defineProperty__default.default(_this, "clearFile", function (filename) {
      return _this.setState(function (state) {
        var newState = {
          files: state.files.filter(function (_ref) {
            var name = _ref.name;
            return name !== filename;
          })
        };
        _this.props.onData(newState.files.map(function (i) {
          return {
            name: i.name,
            contents: i.contents
          };
        }));
        return newState;
      });
    });
    /** This job is to add new files based on a fileDrop event */
    _defineProperty__default.default(_this, "handleChange", function (evt) {
      evt.stopPropagation();
      _this.addNewFiles(evt.target.files);
    });
    /** This handlers job is to request a file deletion based on the clicked index */
    _defineProperty__default.default(_this, "handleClick", function (evt, index) {
      var filename = _this.nodes[index].innerText.trim();
      _this.clearFile(filename);
    });
    _defineProperty__default.default(_this, "render", function () {
      var _this$props = _this.props,
        id = _this$props.id,
        title = _this$props.title,
        description = _this$props.description,
        buttonLabel = _this$props.buttonLabel,
        accept = _this$props.accept,
        kind = _this$props.kind,
        multiple = _this$props.multiple,
        showFiles = _this$props.showFiles,
        className = _this$props.className,
        dragAndDropLabel = _this$props.dragAndDropLabel,
        testId = _this$props.testId;
      var hover = _this.state.hover;
      var linkElement = /*#__PURE__*/React__default.default.createElement("div", null, dragAndDropLabel, /*#__PURE__*/React__default.default.createElement("span", {
        onClick: function onClick() {
          if (_this.fileInput) {
            if (!multiple) {
              _this.setState({
                files: []
              });
            }
            _this.fileInput.files = null;
            _this.fileInput.value = null;
            _this.fileInput.click();
          }
        },
        role: "presentation"
      }, /*#__PURE__*/React__default.default.createElement("button", {
        "data-testid": "".concat(testId, "-link-button"),
        type: "button",
        className: "".concat(iotPrefix, "--file-drop__link-button")
      }, buttonLabel)), /*#__PURE__*/React__default.default.createElement("div", null, description));
      var fileNameElements = /*#__PURE__*/React__default.default.createElement("div", {
        className: "".concat(prefix, "--file-container")
      }, _this.state.files.length === 0 ? null : _this.state.files.map(function (_ref2, index) {
        var name = _ref2.name,
          uploadState = _ref2.uploadState;
        return /*#__PURE__*/React__default.default.createElement("span", {
          key: "".concat(name, "-").concat(index),
          className: "".concat(prefix, "--file__selected-file ").concat(iotPrefix, "--file-drop__selected-file"),
          ref: function ref(node) {
            _this.nodes[index] = node;
          }
        }, /*#__PURE__*/React__default.default.createElement("p", {
          className: "".concat(prefix, "--file-filename")
        }, name), /*#__PURE__*/React__default.default.createElement("span", {
          className: "".concat(prefix, "--file__state-container")
        }, /*#__PURE__*/React__default.default.createElement(react.Filename, {
          "data-testid": "".concat(testId, "-file-").concat(name),
          status: uploadState,
          onKeyDown: function onKeyDown(evt) {
            if (evt.key === 'Enter' || evt.key === 'Space') {
              _this.handleClick(evt, index);
            }
          },
          onClick: function onClick(evt) {
            if (uploadState === 'edit') {
              _this.handleClick(evt, index);
            }
          }
        })));
      }));
      return kind === 'drag-and-drop' ? /*#__PURE__*/React__default.default.createElement("div", {
        "data-testid": testId,
        className: className
      }, /*#__PURE__*/React__default.default.createElement("strong", {
        "data-testid": "".concat(testId, "-title"),
        className: "".concat(prefix, "--label")
      }, title), /*#__PURE__*/React__default.default.createElement("input", {
        style: {
          visibility: 'hidden'
        },
        type: "file",
        ref: function ref(_ref3) {
          return _this.fileInput = _ref3;
        } // eslint-disable-line no-return-assign
        ,
        accept: accept,
        multiple: multiple,
        onChange: _this.handleChange,
        "data-testid": "".concat(testId, "-file-input")
      }), /*#__PURE__*/React__default.default.createElement("div", {
        className: "".concat(iotPrefix, "--file-drop__text"),
        style: hover ? {
          border: '1px solid #3D70B2'
        } : {
          border: '1px dashed #8C8C8C'
        },
        onDragOver: _this.fileDragHover,
        onDragLeave: _this.fileDragHover,
        onDrop: _this.fileDrop,
        "data-testid": "".concat(testId, "-drop-zone")
      }, linkElement), showFiles ? fileNameElements : null) : /*#__PURE__*/React__default.default.createElement("div", {
        "data-testid": testId,
        id: id,
        className: "".concat(prefix, "--form-item")
      }, title ? /*#__PURE__*/React__default.default.createElement("strong", {
        "data-testid": "".concat(testId, "-title"),
        className: "".concat(prefix, "--label")
      }, title) : null, description ? /*#__PURE__*/React__default.default.createElement("p", {
        "data-testid": "".concat(testId, "-description"),
        className: "".concat(prefix, "--label-description")
      }, description) : null, /*#__PURE__*/React__default.default.createElement(react.FileUploaderButton, {
        labelText: buttonLabel,
        multiple: multiple,
        buttonKind: "secondary",
        onChange: _this.handleChange,
        disableLabelChanges: true,
        accept: accept,
        "data-testid": "".concat(testId, "-uploader-button")
      }), showFiles ? fileNameElements : null);
    });
    return _this;
  }
  _inherits__default.default(FileDrop, _React$Component);
  return _createClass__default.default(FileDrop);
}(React__default.default.Component);
FileDrop.propTypes = propTypes;
FileDrop.defaultProps = defaultProps;
FileDrop.__docgenInfo = {
  "description": "Carbon File Uploader with added ability to have drag and drop",
  "methods": [{
    "name": "fileDragHover",
    "docblock": null,
    "modifiers": [],
    "params": [{
      "name": "evt",
      "type": null
    }],
    "returns": null
  }, {
    "name": "fileDrop",
    "docblock": null,
    "modifiers": [],
    "params": [{
      "name": "evt",
      "type": null
    }],
    "returns": null
  }, {
    "name": "readFileContent",
    "docblock": "takes a array of File javascript objects https://developer.mozilla.org/en-US/docs/Web/API/File\nand creates a FileReader for each one, setting up the appropriate onload, onerror handlers, and then\nactually calls the readAsBinaryString method to trigger the loading of the file.",
    "modifiers": [],
    "params": [{
      "name": "files"
    }],
    "returns": null,
    "description": "takes a array of File javascript objects https://developer.mozilla.org/en-US/docs/Web/API/File\nand creates a FileReader for each one, setting up the appropriate onload, onerror handlers, and then\nactually calls the readAsBinaryString method to trigger the loading of the file."
  }, {
    "name": "handleFileError",
    "docblock": "In the error handler if calls the onError once for any file where content load fails and clears the reader",
    "modifiers": [],
    "params": [{
      "name": "evt"
    }, {
      "name": "file"
    }],
    "returns": null,
    "description": "In the error handler if calls the onError once for any file where content load fails and clears the reader"
  }, {
    "name": "handleFileLoad",
    "docblock": "After the file is read in the success handler, it updates the state with the file contents.\nAfter the last one is read it calls the onData callback to update the parent.\n\nFinally it clears the reader",
    "modifiers": [],
    "params": [{
      "name": "file"
    }],
    "returns": null,
    "description": "After the file is read in the success handler, it updates the state with the file contents.\nAfter the last one is read it calls the onData callback to update the parent.\n\nFinally it clears the reader"
  }, {
    "name": "addNewFiles",
    "docblock": null,
    "modifiers": [],
    "params": [{
      "name": "files",
      "type": null
    }],
    "returns": null
  }, {
    "name": "clearFile",
    "docblock": null,
    "modifiers": [],
    "params": [{
      "name": "filename",
      "type": null
    }],
    "returns": null
  }, {
    "name": "handleChange",
    "docblock": "This job is to add new files based on a fileDrop event",
    "modifiers": [],
    "params": [{
      "name": "evt"
    }],
    "returns": null,
    "description": "This job is to add new files based on a fileDrop event"
  }, {
    "name": "handleClick",
    "docblock": "This handlers job is to request a file deletion based on the clicked index",
    "modifiers": [],
    "params": [{
      "name": "evt"
    }, {
      "name": "index"
    }],
    "returns": null,
    "description": "This handlers job is to request a file deletion based on the clicked index"
  }, {
    "name": "render",
    "docblock": null,
    "modifiers": [],
    "params": [],
    "returns": null
  }],
  "displayName": "FileDrop",
  "props": {
    "id": {
      "defaultValue": {
        "value": "'FileUploader'",
        "computed": false
      },
      "description": "DOM ID",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "buttonLabel": {
      "defaultValue": {
        "value": "'Add files'",
        "computed": false
      },
      "description": "Button label",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "title": {
      "defaultValue": {
        "value": "null",
        "computed": false
      },
      "description": "Title text",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "description": {
      "defaultValue": {
        "value": "null",
        "computed": false
      },
      "description": "Description text of file uploader",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "kind": {
      "defaultValue": {
        "value": "'browse'",
        "computed": false
      },
      "description": "Componet is drag/drop",
      "type": {
        "name": "enum",
        "value": [{
          "value": "'browse'",
          "computed": false
        }, {
          "value": "'drag-and-drop'",
          "computed": false
        }]
      },
      "required": false
    },
    "multiple": {
      "defaultValue": {
        "value": "true",
        "computed": false
      },
      "description": "can multiple files be uploaded",
      "type": {
        "name": "bool"
      },
      "required": false
    },
    "showFiles": {
      "defaultValue": {
        "value": "true",
        "computed": false
      },
      "description": "Optionally show the uploaded files",
      "type": {
        "name": "bool"
      },
      "required": false
    },
    "accept": {
      "defaultValue": {
        "value": "[]",
        "computed": false
      },
      "description": "File types that are accepted",
      "type": {
        "name": "arrayOf",
        "value": {
          "name": "string"
        }
      },
      "required": false
    },
    "onData": {
      "defaultValue": {
        "value": "() => {}",
        "computed": false
      },
      "description": "Callback to return the loaded file(s) data",
      "type": {
        "name": "func"
      },
      "required": false
    },
    "onError": {
      "defaultValue": {
        "value": "() => {}",
        "computed": false
      },
      "description": "Callback for file load errors",
      "type": {
        "name": "func"
      },
      "required": false
    },
    "dragAndDropLabel": {
      "defaultValue": {
        "value": "'Drag and drop your file here or '",
        "computed": false
      },
      "description": "",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "fileType": {
      "defaultValue": {
        "value": "'BINARY'",
        "computed": false
      },
      "description": "file type either TEXT or BINARY to determine the correct encoding",
      "type": {
        "name": "enum",
        "value": [{
          "value": "\"BINARY\"",
          "computed": false
        }, {
          "value": "\"TEXT\"",
          "computed": false
        }]
      },
      "required": false
    },
    "testId": {
      "defaultValue": {
        "value": "'file-drop'",
        "computed": false
      },
      "description": "",
      "type": {
        "name": "string"
      },
      "required": false
    }
  }
};
var FileDrop$1 = FileDrop;

exports.FILE_TYPES = FILE_TYPES;
exports.default = FileDrop$1;
