import React from 'react';
import { observable, computed, action, decorate } from "mobx";
import { inject, observer } from 'mobx-react';
import styled from 'react-emotion';

import { router as routerService } from '../services';
import AutomataManager from '../libs/automata';

import OneDimensionViewerInTwoDimensions from '../libs/viewer/OneDimensionInTwoDimensions';
import TwoDimensionViewerInTwoDimensions from '../libs/viewer/TwoDimensionInTwoDimensions';
import TwoDimensionViewerInThreeDimensions from '../libs/viewer/TwoDimensionInThreeDimensions';
import ThreeDimensionViewerInThreeDimensions from '../libs/viewer/ThreeDimensionInThreeDimensions';

const Container = styled('div')`
  position: fixed;
  z-index: 0;
  width: 100vw;
  height: 100vh;
  background-color: white;
`;

class Component extends React.Component {
  constructor(props) {
    super(props)

    this.elID = 'view-player-runner';
    this.viewer = undefined;

    this.automataManager = new AutomataManager();
    this.state = {
      dimension: undefined,
      viewer: undefined,
      populationShape: undefined,
    }

    this.retrieveNextGeneration = this.retrieveNextGeneration.bind(this);
  }

  componentDidMount() {
    const { automataStore: { dimension, viewer, populationShape }, location } = this.props;

    this.initalizeViewer(dimension.value, viewer.value)
    if (routerService.isAtView(location)) {
      this.runSimulation();
    }

    this.setState({
      dimension: dimension.value,
      viewer: viewer.value,
      populationShape: populationShape.value,
    });
  }

  componentDidUpdate({ automataStore: { dimension: nextDimension, viewer: nextViewer }, location: nextLocation }) {
    console.log('updating')
    const { location: currentLocation } = this.props;
    const { dimension: currentDimension, viewer: currentViewer } = this.state;

    const currentlyAtView = routerService.isAtView(currentLocation);
    const willBeAtView = routerService.isAtView(nextLocation);
    if (currentlyAtView !== willBeAtView && willBeAtView) {
      this.runSimulation();
    }

    if (nextDimension.value !== currentDimension || nextViewer.value !== currentViewer) {
      console.log('changing viewer')
      this.initalizeViewer(nextDimension.value, nextViewer.value, true)
      this.setState({
        dimension: nextDimension.value,
        viewer: nextViewer.value,
      });
    }

  }

  retrieveNextGeneration() {
    return this.automataManager.run();
  }

  runSimulation() {
    this.viewer.turnSimulationOn();
  }

  stopSimulation() {
    this.viewer.turnSimulationOff();
  }

  createGenesisGeneration() {
    const { automataStore: { populationShape } } = this.props;

    this.automataManager.populationShape = populationShape.shape;
    this.automataManager.getSeedPopulation();
  }

  bulkCreateGenerations(numberOfVisibleGenerations) {
    let generationCount;
    for (generationCount = 0; generationCount < numberOfVisibleGenerations; generationCount++ ) {
      this.viewer.addGeneration();
    }
  }

  initalizeViewer(populationDimension, viewerDimension, shouldRun = false) {
    const { automataStore: { populationShape } } = this.props;

    const viewerConfig = {
      containerElId: this.elID,
      populationShape: populationShape.shape,
      retrieveNextGeneration: this.retrieveNextGeneration,
    };

    if (populationDimension === 1 && viewerDimension === 2) {
      if (this.viewer && this.viewer.type === 'one-dimension') return;
      if (this.viewer) this.viewer.quit();
      this.viewer = new OneDimensionViewerInTwoDimensions(viewerConfig);
      this.automataManager.useOneDimensionGenerator();
      this.automataManager.generationHistorySize = 1500;
    }

    else if (populationDimension === 2 && viewerDimension === 2) {
      if (this.viewer && this.viewer.type === 'two-dimension-in-two-dimensions') return;
      if (this.viewer) this.viewer.quit();
      this.viewer = new TwoDimensionViewerInTwoDimensions(viewerConfig);
      this.automataManager.useLifeLikeGenerator();
      this.automataManager.generationHistorySize = 2;
    }

    else if (populationDimension === 2 && viewerDimension === 3) {
      if (this.viewer && this.viewer.type === 'two-dimension-in-three-dimensions') return;
      if (this.viewer) this.viewer.quit();
      this.viewer = new TwoDimensionViewerInThreeDimensions(viewerConfig);
      this.automataManager.useLifeLikeGenerator();
      this.automataManager.generationHistorySize = 20;
    }

    else if (populationDimension === 3 && viewerDimension === 3) {
      if (this.viewer && this.viewer.type === 'three-dimension-in-three-dimensions') return;
      if (this.viewer) this.viewer.quit();
      this.viewer = new ThreeDimensionViewerInThreeDimensions(viewerConfig);
      this.automataManager.useThreeDimensionGenerator();
      this.automataManager.generationHistorySize = 20;
    }

    if (this.viewer !== undefined) {
      this.viewer.createScene();
      this.createGenesisGeneration();
      this.viewer.type === 'one-dimension' && this.bulkCreateGenerations(this.viewer.maxGenerationsToShow * 2);
      if (shouldRun) this.runSimulation();
    }
  }

  render() {
    const { automataStore } = this.props;
    const { dimension, viewer, populationShape } = automataStore;


    return (
      <Container id={this.elID}>
        { /* TODO correctly configure mobx to not need this trigger mobx update observation hack */}
        <div dimension={dimension.value} viewer={viewer.value} populationshape={populationShape.value} />
      </Container>
    );
  }
}
decorate(Component, {
  componentWillUpdate: observable,
  // current: observable,
  // render: computed,
  // render: action
});
export default inject('automataStore')(observer(Component));

@@ -1548,20 +1548,20 @@
 onShape.
-valu
+shap
 e,%0A    %7D
@@ -1652,16 +1652,54 @@
 xtViewer
+, populationShape: nextPopulationShape
  %7D, loca
@@ -1725,36 +1725,8 @@
 %7D) %7B
-%0A    console.log('updating')
 %0A   
@@ -1838,16 +1838,57 @@
 ntViewer
+, populationShape: currentPopulationShape
  %7D = thi
@@ -2116,32 +2116,92 @@
 ation();%0A    %7D%0A%0A
+    // handle dimension updates (will need a viewer change)%0A
     if (nextDime
@@ -2278,45 +2278,8 @@
 ) %7B%0A
-      console.log('changing viewer')%0A
     
@@ -2459,16 +2459,314 @@
 %0A    %7D%0A%0A
+    // handle population shape updates%0A    if (JSON.stringify(nextPopulationShape.shape) !== JSON.stringify(currentPopulationShape)) %7B%0A      this.automataManager.populationShape = nextPopulationShape.shape;%0A      this.setState(%7B%0A        populationShape: nextPopulationShape.shape,%0A      %7D);%0A    %7D%0A%0A
   %7D%0A%0A  r
@@ -5886,20 +5886,20 @@
 onShape.
-valu
+shap
 e%7D /%3E%0A  
@@ -5932,137 +5932,8 @@
 %7D%0A%7D%0A
-decorate(Component, %7B%0A  componentWillUpdate: observable,%0A  // current: observable,%0A  // render: computed,%0A  // render: action%0A%7D);
 %0Aexp

add population shape update to viewer