text: // @flow
  
  import React, { Component } from 'react';
  import { connect } from 'react-redux';
  import get from 'lodash/get';
  import difference from 'lodash/difference';
  
  import DataGrid from './DataGrid';
  
  import {
  	setCellValueRequest,
  	setCurrentIds,
  	setArrayFields,
  } from '../../actions';
  import { getAppname } from '../../reducers/app';
  import {
  	getVisibleColumns,
  	getNestedVisibleColumns,
  	getNestedColumns,
  	getTypePropertyMapping,
  } from '../../reducers/mappings';
  import { getIsShowingNestedColumns } from '../../reducers/nestedColumns';
  import {
  	getNestedArrayField,
  	updateIndexTypeMapping,
  } from '../../utils/mappings';
  import { getMode } from '../../reducers/mode';
  import { getPageSize } from '../../reducers/pageSize';
  import { isEqualArray, isEmptyObject } from '../../utils';
  
  type State = {
  	data: any[],
  };
  
  type Props = {
  	data: any[],
  	mappings: any,
  	setCellValue: (string, string, any, string, string) => void,
  	nestedVisibleColumns: string[],
  	onSetCurrentIds: any => void,
  	isShowingNestedColumns: boolean,
  	nestedColumns: string[],
  	appName: string,
  	onSetArrayFields: (string[], string[], any, string, any) => void,
  	typePropertyMapping: any,
  	visibleColumns: string[],
  	mode: string,
  	pageSize: number,
  	height: number,
  	width: number,
  	headerRef: any,
  };
  
  class DataTable extends Component<Props, State> {
  	isMounted = false;
  
  	state = {
  		data: this.props.data,
  	};
  
  	componentDidMount() {
  		this.isMounted = true;
  		this.props.onSetCurrentIds(this.props.data.map(item => item._id));
  	}
  
  	shouldComponentUpdate(nextProps, nextState) {
  		return (
  			!isEqualArray(this.state.data, nextState.data) ||
  			!isEqualArray(this.props.data, nextProps.data) ||
  			this.props.visibleColumns.length !==
  				nextProps.visibleColumns.length ||
  			this.props.isShowingNestedColumns !==
  				nextProps.isShowingNestedColumns ||
  			this.props.nestedVisibleColumns.length !==
  				nextProps.nestedVisibleColumns.length ||
  			this.props.mode !== nextProps.mode ||
  			this.props.pageSize !== nextProps.pageSize
  		);
  	}
  
  	componentDidUpdate(prevProps) {
  		const {
  			isShowingNestedColumns,
  			mappings,
  			nestedColumns,
  			nestedVisibleColumns,
  			data,
  			appName,
  			onSetArrayFields,
  			typePropertyMapping,
  		} = this.props;
  		if (
  			prevProps.isShowingNestedColumns !== isShowingNestedColumns &&
  			isShowingNestedColumns
  		) {
  			const {
  				fieldsToBeDeleted,
  				parentFields,
  				indexTypeMap,
  			} = getNestedArrayField(data, mappings.nestedProperties);
  
  			if (
  				!isEmptyObject(parentFields) &&
  				difference(
  					Object.keys(parentFields),
  					Object.keys(mappings.nestedProperties),
  				).length > 0
  			) {
  				const diffAllFields = difference(
  					nestedColumns,
  					Object.keys(fieldsToBeDeleted),
  				);
  
  				const diffVisibleFields = difference(
  					nestedVisibleColumns,
  					Object.keys(fieldsToBeDeleted),
  				);
  
  				const parentFieldsMapping = {};
  				Object.keys(parentFields).forEach(key => {
  					parentFieldsMapping[key] = get(
  						mappings.properties,
  						key.split('.').join('.properties.'),
  					);
  				});
  
  				const newTypePropertyMapping = updateIndexTypeMapping(
  					typePropertyMapping,
  					indexTypeMap,
  					Object.keys(fieldsToBeDeleted),
  					mappings,
  				);
  
  				onSetArrayFields(
  					[...diffAllFields, ...Object.keys(parentFields)],
  					[...diffVisibleFields, ...Object.keys(parentFields)],
  					parentFieldsMapping,
  					appName,
  					newTypePropertyMapping,
  				);
  			}
  		}
  
  		if (!isEqualArray(data, prevProps.data)) {
  			this.setData(data);
  		}
  	}
  
  	componentWillUnmount() {
  		this.isMounted = false;
  	}
  
  	setData = data => {
  		this.setState({
  			data,
  		});
  		this.props.onSetCurrentIds(data.map(item => item._id));
  	};
  
  	handleCellChange = (row, column, value) => {
  		const { setCellValue } = this.props;
  		const { data } = this.state;
  
  		const nextData = [
  			...data.slice(0, row),
  			{
  				...data[row],
  				[column]: value,
  			},
  			...data.slice(row + 1),
  		];
  		this.setState({
  			data: nextData,
  		});
  		const record = data[row];
  		setCellValue(record._id, column, value, record._index, record._type);
  	};
  
  	render() {
  		const { data } = this.state;
  		const {
  			mappings,
  			visibleColumns,
  			mode,
  			nestedVisibleColumns,
  			isShowingNestedColumns,
  			height,
  			width,
  			headerRef,
  		} = this.props;
  
  		return (
  			<DataGrid
  				data={data}
  				mappings={mappings}
  				onCellChange={this.handleCellChange}
  				visibleColumns={visibleColumns}
  				mode={mode}
  				nestedVisibleColumns={nestedVisibleColumns}
  				isShowingNestedColumns={isShowingNestedColumns}
  				height={height}
  				width={width}
  				headerRef={headerRef}
  			/>
  		);
  	}
  }
  
  const mapStateToProps = state => ({
  	nestedVisibleColumns: getNestedVisibleColumns(state),
  	nestedColumns: getNestedColumns(state),
  	appName: getAppname(state),
  	typePropertyMapping: getTypePropertyMapping(state),
  	isShowingNestedColumns: getIsShowingNestedColumns(state),
  	visibleColumns: getVisibleColumns(state),
  	mode: getMode(state),
  	pageSize: getPageSize(state),
  });
  
  const mapDispatchToProps = {
  	setCellValue: setCellValueRequest,
  	onSetCurrentIds: setCurrentIds,
  	onSetArrayFields: setArrayFields,
  };
  
  export default connect(
  	mapStateToProps,
  	mapDispatchToProps,
  )(DataTable);
  