import React, {Component} from 'react';
import './Grid.css';
import GridComponent from './GridComponent/GridComponent';

const DEFAULT_GRID_SIZE = 4;

export default class extends Component {
  resizeTimeout;
  state = {
    calculated: false,
    dimensions: {
      columns: 0,
      rows: 0
    }
  };

  calculateDimensions = size => {
    return {
      columns: Math.floor(size.width / this.getGridSize()),
      rows: Math.floor(size.height / this.getGridSize())
    };
  };

  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
    this.updateSizeAsync();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
    clearInterval(this.resizeTimeout);
  };

  getGridSize = () => {
    return this.props.gridSize || DEFAULT_GRID_SIZE;
  };

  getGridSizePx = () => {
    return this.getGridSize() + 'px ';
  };

  getSize = () => {
    const elem = this.refs.GridOwner;
    return {
      height: elem ? elem.offsetHeight : 0,
      width: elem ? elem.offsetWidth : 0
    };
  };

  handleResize = () => {
    clearTimeout(this.resizeTimeout);
    this.resizeTimeout = setTimeout(this.updateSizeAsync, 10);
  };

  updateSize = () => {
    const state = {
      ...this.state
    };
    const size = this.getSize();
    const dimensions = this.calculateDimensions(size);
    if (state.dimensions !== dimensions) {
      this.setState({
        calculated: true,
        dimensions: dimensions
      })
    }
  };

  updateSizeAsync = () => {
    return new Promise(() => {
      this.updateSize();
    });
  };

  render() {
    let children = null;
    const dimensions = this.state.dimensions;
    if (this.state.calculated) {
      children = React.Children.map(this.props.children, (child, i) => {
        if (child) {
          let row = child.props.row || 0;
          if (typeof(row) === 'function') {
            row = row(dimensions);
          }

          let col = child.props.col || 0;
          if (typeof(col) === 'function') {
            col = col(dimensions);
          }

          let rowSpan = child.props.rowSpan;
          if (typeof(rowSpan) === 'function') {
            rowSpan = rowSpan(dimensions.rows - row, dimensions.rows);
          }

          let colSpan = child.props.colSpan;
          if (typeof(colSpan) === 'function') {
            colSpan = colSpan(dimensions.columns - col, dimensions.columns);
          }

          rowSpan = rowSpan ? (rowSpan === 'remain' ? (dimensions.rows - row) : rowSpan) : null;
          colSpan = colSpan ? (colSpan === 'remain' ? dimensions.columns - col : colSpan) : null;

          return (
            <GridComponent row={row}
                           col={col}
                           rowSpan={rowSpan}
                           colSpan={colSpan}
                           key={'gc_' + i}>
              {child}
            </GridComponent>
          );
        } else {
          return null;
        }
      });
    }

    const gridSizePx = this.getGridSizePx();
    let style = {
      style: {
        gridTemplateColumns: gridSizePx.repeat(dimensions.columns),
        gridTemplateRows: gridSizePx.repeat(dimensions.rows),
        gridAutoColumns: gridSizePx,
        gridAutoRows: gridSizePx,
      }
    };

    if (this.props.noScroll) {
      style['style'].overflowX = 'visible';
      style['style'].overflowY = 'visible';
    }

    return (
      <div
        ref='GridOwner'
        className={'GridOwner'}>
        <div className={'Grid'} {...style}>
          {children}
        </div>
      </div>
    )
  }
};