'use strict';

Object.defineProperty(exports, "__esModule", {
	value: true
});
exports.JSONLike = exports.NativeValue = undefined;

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

exports.getJSONPath = getJSONPath;
exports.LineItem = LineItem;
exports.getDataInfo = getDataInfo;
exports.Item = Item;

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _invariant = require('invariant');

var _invariant2 = _interopRequireDefault(_invariant);

var _Icon = require('../../Icon');

var _Icon2 = _interopRequireDefault(_Icon);

var _JSONLike = require('./JSONLike.scss');

var _JSONLike2 = _interopRequireDefault(_JSONLike);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }

function noop() {}

var VALIDE_TYPES = ['number', 'string', 'boolean'];
var COMPLEX_TYPES = ['object', 'array'];

function NativeValue(_ref) {
	var data = _ref.data,
	    edit = _ref.edit,
	    _onClick = _ref.onClick,
	    _onChange = _ref.onChange,
	    jsonpath = _ref.jsonpath;

	var type = typeof data === 'undefined' ? 'undefined' : _typeof(data);
	var display = data;
	var inputType = 'number';
	if (type === 'boolean') {
		display = data.toString();
		inputType = 'checkbox';
	} else if (type === 'string') {
		inputType = 'text';
	}
	if (edit) {
		return _react2.default.createElement('input', { type: inputType, value: data, onChange: function onChange(e) {
				return _onChange(e, { jsonpath: jsonpath });
			} });
	}
	return _react2.default.createElement(
		'button',
		{
			type: 'button',
			className: 'btn btn-link btn-xs ' + _JSONLike2.default[type] + ' ' + _JSONLike2.default.native,
			onClick: function onClick(e) {
				return _onClick(e, { data: data, edit: edit, jsonpath: jsonpath });
			}
		},
		display
	);
}

exports.NativeValue = NativeValue;
NativeValue.propTypes = {
	data: _react.PropTypes.oneOfType([_react.PropTypes.bool, _react.PropTypes.number, _react.PropTypes.string]),
	edit: _react.PropTypes.bool,
	onClick: _react.PropTypes.func,
	onChange: _react.PropTypes.func,
	jsonpath: _react.PropTypes.string
};

/**
 * return JSONPath braket notation
 * @param  {string} key    object key
 * @param  {string} prefix current jsonpath
 * @param  {string} type   one of 'array' or 'object'
 * @return {string}        jsonpath
 */
function getJSONPath(key, prefix, type) {
	if (type === 'array') {
		return prefix + '[' + key + ']';
	}
	return prefix + '[\'' + key + '\']';
}

function LineItem(_ref2) {
	var name = _ref2.name,
	    onMouseOver = _ref2.onMouseOver,
	    mouseOverData = _ref2.mouseOverData,
	    children = _ref2.children;

	var props = {};

	if (onMouseOver && onMouseOver !== noop) {
		props.onMouseOver = function (e) {
			return onMouseOver(e, mouseOverData);
		};
	}

	return _react2.default.createElement(
		'span',
		props,
		name ? _react2.default.createElement(
			'span',
			{ className: _JSONLike2.default.name },
			name
		) : null,
		children
	);
}

LineItem.propTypes = {
	name: _react.PropTypes.string,
	onMouseOver: _react.PropTypes.func,
	children: _react.PropTypes.node,
	mouseOverData: _react.PropTypes.object // eslint-disable-line react/forbid-prop-types
};

function getDataInfo(data) {
	var info = {
		type: typeof data === 'undefined' ? 'undefined' : _typeof(data),
		keys: Object.keys(data)
	};

	if (VALIDE_TYPES.indexOf(info.type) === -1) {
		(0, _invariant2.default)(true, 'Type ' + info.type + ' is not supported');
	}

	if (Array.isArray(data)) {
		info.type = 'array';
		info.length = data.length;
	} else if (info.type === 'object') {
		info.keys = Object.keys(data);
		info.length = info.keys.length;
	}

	return info;
}

function Item(_ref3) {
	var data = _ref3.data,
	    name = _ref3.name,
	    opened = _ref3.opened,
	    edited = _ref3.edited,
	    jsonpath = _ref3.jsonpath,
	    props = _objectWithoutProperties(_ref3, ['data', 'name', 'opened', 'edited', 'jsonpath']);

	if (data === undefined) {
		return null;
	}
	var info = getDataInfo(data);
	var isNativeType = COMPLEX_TYPES.indexOf(info.type) === -1;
	var isEdited = edited.indexOf(jsonpath) !== -1 && !!props.onChange;
	var isOpened = opened.indexOf(jsonpath) !== -1 || props.onClick === noop;

	if (isNativeType) {
		return _react2.default.createElement(
			LineItem,
			{
				name: name,
				onMouseOver: props.onMouseOver,
				mouseOverData: { data: data, isOpened: isOpened, isEdited: isEdited }
			},
			_react2.default.createElement(NativeValue, {
				data: data,
				edit: isEdited,
				jsonpath: jsonpath,
				onClick: props.onClick,
				onChange: props.onChange
			})
		);
	}

	var iconName = isOpened ? 'talend-caret-down' : 'talend-chevron-left';
	var iconTransform = isOpened ? null : 'rotate-180';
	var btn = (0, _classnames2.default)('btn btn-xs btn-link', _JSONLike2.default.btn);

	return _react2.default.createElement(
		LineItem,
		{ name: name, mouseOverData: { data: data, isOpened: isOpened, isEdited: isEdited } },
		_react2.default.createElement(
			'span',
			{ className: _JSONLike2.default.hierarchical },
			_react2.default.createElement(
				'button',
				{
					type: 'button',
					className: btn,
					onClick: function onClick(e) {
						return props.onClick(e, { data: data, isOpened: isOpened, jsonpath: jsonpath });
					}
				},
				_react2.default.createElement(_Icon2.default, { name: iconName, transform: iconTransform }),
				info.type,
				_react2.default.createElement(
					'sup',
					{ className: 'badge' },
					info.length
				)
			),
			_react2.default.createElement(
				'ul',
				{ className: !isOpened ? 'hidden' : null },
				info.keys.map(function (key, i) {
					var jpath = getJSONPath(key, jsonpath, info.type);
					return _react2.default.createElement(
						'li',
						{ key: i },
						_react2.default.createElement(Item, _extends({}, props, {
							data: data[key],
							name: key,
							jsonpath: jpath,
							opened: opened,
							edited: edited
						}))
					);
				})
			)
		)
	);
}

Item.propTypes = {
	data: _react.PropTypes.oneOfType([_react.PropTypes.bool, _react.PropTypes.number, _react.PropTypes.string, _react.PropTypes.object, _react.PropTypes.array]),
	name: _react.PropTypes.string,
	opened: _react.PropTypes.arrayOf(_react.PropTypes.string),
	edited: _react.PropTypes.arrayOf(_react.PropTypes.string),
	jsonpath: _react.PropTypes.string,
	onMouseOver: _react.PropTypes.func,
	onClick: _react.PropTypes.func,
	onSubmit: _react.PropTypes.func,
	onChange: _react.PropTypes.func
};

Item.defaultProps = {
	opened: [],
	edited: [],
	jsonpath: '$',
	onMouseOver: noop,
	onClick: noop
};

/**
 * display a tree view json like.
 * this is an indented list of item where each item render 'id: type #items'
 * @param {object} props react
 */
function JSONLike(_ref4) {
	var _onSubmit = _ref4.onSubmit,
	    props = _objectWithoutProperties(_ref4, ['onSubmit']);

	if (_onSubmit) {
		return _react2.default.createElement(
			'form',
			{
				className: 'tc-object-viewer ' + _JSONLike2.default.container,
				onSubmit: function onSubmit(event) {
					_onSubmit(event);
					event.preventDefault();
				}
			},
			_react2.default.createElement(Item, props)
		);
	}
	return _react2.default.createElement(
		'div',
		{ className: 'tc-object-viewer ' + _JSONLike2.default.container },
		_react2.default.createElement(Item, props)
	);
}

exports.JSONLike = JSONLike;
JSONLike.propTypes = {
	onSubmit: _react.PropTypes.func
};

exports.default = JSONLike;