import React from "react";
import { connect } from "redux-bundler-react";
import ReactDataGrid from "react-data-grid";
import _ from "lodash";
import { getLayer } from "../../openlayers-utils/layer-utilities";
import GeoJSON from "ol/format/GeoJSON";
import { Fill, Stroke, Style, Circle as CircleStyle } from "ol/style";
import Cell from "./identify-table-cell";

const style = new Style({
  fill: new Fill({
    color: "rgba(84, 240, 240, 0.1)",
  }),
  stroke: new Stroke({
    color: "rgb(84, 240, 240)",
    width: 1,
  }),
  image: new CircleStyle({
    radius: 5,
    stroke: new Stroke({
      color: "rgb(84, 240, 240)",
      width: 1,
    }),
    fill: new Fill({
      color: "rgba(84, 240, 240, 0.1)",
    }),
  }),
});

const selectStyle = new Style({
  fill: new Fill({
    color: "rgba(244, 241, 66, 0.8)",
  }),
  stroke: new Stroke({
    color: "rgb(244, 241, 66)",
    width: 1,
  }),
  image: new CircleStyle({
    radius: 8,
    stroke: new Stroke({
      color: "rgb(244, 241, 66)",
    }),
    fill: new Fill({
      color: "rgba(244, 241, 66, 0.8)",
    }),
  }),
});

class IdentifyTable extends React.Component {
  constructor(props) {
    super(props);
    const features = props.features;
    const geometryType = features[0].geometry.type;
    const properties = features[0].properties;
    const featureCollection = {
      type: "FeatureCollection",
      features: features,
    };

    this.layer = getLayer({
      serviceType: "LocalVector",
      visible: true,
      geometryType: geometryType,
      style: style,
      zIndex: 1000,
    });

    this.selection = getLayer({
      serviceType: "LocalVector",
      visible: true,
      geometryType: geometryType,
      style: selectStyle,
      zIndex: 1001,
    });

    const geojson = new GeoJSON().readFeatures(featureCollection, {
      dataProjection: "EPSG:4326",
      featureProjection: "EPSG:3857",
    });
    const src = this.layer.getSource();
    src.addFeatures(geojson);

    this.rowGetter = this.rowGetter.bind(this);
    this.onRowsDeselected = this.onRowsDeselected.bind(this);
    this.onRowsSelected = this.onRowsSelected.bind(this);
    this.setRowsFromSource = this.setRowsFromSource.bind(this);
    this.sort = this.sort.bind(this);
    this.generateColumns = this.generateColumns.bind(this);
    this.exportToCSV = this.exportToCSV.bind(this);
    this.identifyCsv = this.identifyCsv.bind(this);
    this.exportToGeoJSON = this.exportToGeoJSON.bind(this);

    this.state = {
      rows: [],
      columns: this.generateColumns(properties),
      source: src,
      minHeight: 200,
      selected: [],
      sortBy: "ol_uid",
      sortDir: 0,
      featureCollection: featureCollection,
    };
  }

  generateColumns(properties) {
    return Object.keys(properties).map((key, i) => {
      // Increase the width for longer column names.
      let width = key && key.length > 15 ? 150 + (key.length -10 ) * 5 : 150;
      return {
        id: i,
        key: key,
        name: key,
        editable: false,
        sortable: true,
        filterable: true,
        width: width,
        resizable: true,
        nullable: true,
        formatter: Cell,
      };
    });
  }

  componentWillUnmount() {
    const { map } = this.props;
    map.removeLayer(this.layer);
    map.removeLayer(this.selection);
  }

  componentDidMount() {
    const { map } = this.props;
    this.setRowsFromSource();
    map.addLayer(this.layer);
    map.addLayer(this.selection);
  }

  rowGetter(i) {
    let { rows, sortBy, sortDir } = this.state;
    if (!sortDir) sortBy = "ol_uid";
    const sortedRows = _.sortBy(rows, [sortBy]);
    if (sortDir === 2) sortedRows.reverse();
    return sortedRows[i];
  }

  onRowsDeselected(e) {
    const { selected } = this.state;
    const src = this.selection.getSource();
    e.forEach((row) => {
      src.removeFeature(row.row.feature);
      const idx = selected.indexOf(row.row.id);
      selected.splice(idx, 1);
    });
    this.setState({ selected: selected.slice() });
  }

  onRowsSelected(e) {
    const { selected } = this.state;
    const ids = [];
    const src = this.selection.getSource();
    e.forEach((row) => {
      src.addFeature(row.row.feature);
      ids.push(row.row.id);
    });
    this.setState({ selected: selected.concat(ids) });
  }

  setRowsFromSource() {
    const { source } = this.state;
    const rows = [];
    source.forEachFeature((feature) => {
      const row = {
        id: feature.ol_uid,
        ol_uid: feature.ol_uid,
        feature: feature,
      };
      const properties = feature.getProperties();
      rows.push(Object.assign(row, properties));
    });
    this.setState({ rows: rows });
  }

  sort(newSortBy) {
    const { sortBy, sortDir } = this.state;
    const newSortDir = newSortBy === sortBy ? (sortDir + 1) % 3 : 1;
    this.setState({
      sortBy: newSortBy,
      sortDir: newSortDir,
    });
  }
  exportToCSV() {
    const { columns, rows, sortBy, sortDir, selected } = this.state;
    const csvHeader = _.map(columns, "name");
    const sortOrder = sortDir === 0 || sortDir === 1 ? "asc" : "desc";
    let iRows = [];
    let rowsRaw = [];

    if (selected.length) {
      selected.forEach((selection) => {
        rows.forEach((row) => {
          if (selection === row.id) {
            iRows.push(row.feature.getProperties());
          }
        });
      });
      rowsRaw = _.orderBy(iRows, [sortBy], [sortOrder]);
    } else {
      rows.forEach((row) => {
        iRows.push(row.feature.getProperties());
      });
      rowsRaw = _.orderBy(iRows, [sortBy], [sortOrder]);
    }

    this.identifyCsv(csvHeader, rowsRaw);
  }
  identifyCsv(header, rows) {
    const { doGenerateCsv } = this.props;
    let csvArray = [header];

    rows.forEach((row, i) => {
      let rowValues = [];
      header.forEach((column) => {
        rowValues.push(row[column]);
      });
      csvArray.push(rowValues);
    });

    doGenerateCsv(csvArray);
  }

  exportToGeoJSON() {
    const { featureCollection, rows, selected } = this.state;
    const { doGenerateGeoJSON } = this.props;
    let featureCollectionWork = {
      type: "FeatureCollection",
      features: [],
    };
    let selectedObjectIDs = [];

    if (selected.length) {
      selected.forEach((selection) => {
        rows.forEach((row) => {
          if (selection === row.id) {
            selectedObjectIDs.push(row.objectid);
          }
        });
        featureCollection.features.forEach((feature) => {
          if (selectedObjectIDs.includes(feature.id)) {
            featureCollectionWork.features.push(feature);
          }
        });
      });
    } else {
      featureCollectionWork = featureCollection;
    }
    doGenerateGeoJSON(featureCollectionWork);
  }

  render() {
    const { rows, columns, selected } = this.state;
    const { doToggleIdentifyView } = this.props;
    const container = document.getElementsByClassName("south-container")[0];
    const minHeight = container ? container.clientHeight - 65 : 200;

    return (
      <div>
        <div
          className="text-right"
          style={{ padding: "2px", marginRight: "15px" }}
        >
          <button
            type="button"
            className="cm-btn cm-btn-xs cm-btn-default"
            style={{ marginRight: "5px" }}
            title="Sidebar View"
            onClick={() => {
              doToggleIdentifyView("sidebar");
            }}
          >
            SIDEBAR VIEW
          </button>
          <div className="cm-btn-group">
            <button
              type="button"
              className="cm-btn cm-btn-xs cm-btn-primary"
              title="Export to csv"
              onClick={this.exportToCSV}
            >
              Export to csv
            </button>
            <button
              type="button"
              className="cm-btn cm-btn-xs cm-btn-primary"
              title="Export to geoJSON"
              onClick={this.exportToGeoJSON}
            >
              Export to geoJSON
            </button>
          </div>
        </div>
        <ReactDataGrid
          enableCellSelect={true}
          columns={columns}
          rowGetter={this.rowGetter}
          rowsCount={rows.length}
          minHeight={minHeight}
          onGridSort={this.sort}
          rowSelection={{
            showCheckbox: true,
            enableShiftSelect: false,
            onRowsSelected: this.onRowsSelected,
            onRowsDeselected: this.onRowsDeselected,
            selectBy: {
              keys: {
                rowKey: "ol_uid",
                values: selected,
              },
            },
          }}
        />
      </div>
    );
  }
}

export default connect(
  "selectMap",
  "selectIdentifyResults",
  "selectCmLayerNames",
  "doSouthPanelCloseChild",
  "doGenerateCsv",
  "doGenerateGeoJSON",
  "doToggleIdentifyView",
  IdentifyTable
);
