// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import TransitionGroup from 'react-addons-transition-group';
import classnames from 'classnames';

const CLASS_ROOT = 'animate';

class AnimateChild extends Component {
  constructor (props) {
    super(props);
    this.state = {
      enterClass: '',
      leaveClass: ''
    };
  }

  componentWillAppear (callback) {
    this.enter(callback);
  }

  componentWillEnter (callback) {
    this.enter(callback);
  }

  componentDidAppear () {
    this.entered();
  }

  componentDidEnter () {
    this.entered();
  }

  componentWillLeave (callback) {
    this.leave(callback);
  }

  enter (callback) {
    const {
      enter: {
        animation: enterAnimation,
        delay
      },
      leave: {
        animation: leaveAnimation
      }
    } = this.props;
    const node = ReactDOM.findDOMNode(this);

    const enterClass = enterAnimation;
    const leaveClass = leaveAnimation || enterAnimation;
    this.setState({enterClass});
    this.setState({leaveClass});

    node.style.transitionDuration = '';
    node.classList.remove('animate', `${leaveClass}--leave`);
    node.classList.add(`${enterClass}--enter`);
    setTimeout(callback, delay);
  }

  entered () {
    const { enter: { duration } } = this.props;
    const node = ReactDOM.findDOMNode(this);
    const enterClass = this.state.enterClass;
    node.classList.remove(`${enterClass}--enter`);
    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }
    node.classList.add('animate', `${enterClass}--enter-active`);
    setTimeout(() => {
      node.style.transitionDuration = '';
      node.classList.remove('animate');
    }, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
  }

  leave (callback) {
    const { leave: { duration, delay } } = this.props;
    const node = ReactDOM.findDOMNode(this);

    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }

    return setTimeout(() => {
      node.classList.remove(`${this.state.enterClass}--enter-active`);
      node.classList.add('animate', `${this.state.leaveClass}--leave`);
      setTimeout(callback, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
    }, delay);
  }

  render () {
    return this.props.children;
  }
};

AnimateChild.defaultProps = {
  enter: {},
  leave: {}
};


class Animate extends Component {
  constructor (props) {
    super(props);
    this.state = {
      animationState: 'enter',
      animation: props.enter.animation
    };
  }

  componentWillReceiveProps (nextProps) {
    const { visible, keep } = this.props;
    const { animationState } = this.state;

    if (keep && visible !== nextProps.visible) {
      let state = '';
      if (!nextProps.visible) {
        state = (animationState === 'leave') ? 'enter' : 'leave';
      }
      this.setState({
        animationState: state,
        animation: state ? nextProps[state].animation : ''
      });

      // Reset animation state back to enter after leave animation is finished
      if (state === 'leave') {
        const node = ReactDOM.findDOMNode(this);
        clearTimeout(this.animationTimer);
        this.animationTimer = setTimeout(() => {
          this.setState({
            animationState: 'enter',
            animation: nextProps.enter.animation
          });
        }, (parseFloat(getComputedStyle(node).transitionDuration) +
        parseFloat(getComputedStyle(node).transitionDelay)) * 1000);
      }
    }
  }

  render () {
    const {
      enter,
      leave,
      className,
      children,
      component,
      visible,
      keep,
      style,
      ...props
    } = this.props;

    const animateChildren = React.Children.map(children, (child, index) => {
      const key = (child && child.key) ? child.key : `animate-${index}`;
      return (
        <AnimateChild
          key={key}
          enter={enter}
          leave={leave}
        >
          {child}
        </AnimateChild>
      );
    });

    let classes = className;
    let styles = {...style};
    if (keep) {
      classes = classnames(
        CLASS_ROOT,
        className,
        {
          [`${this.state.animation}--${this.state.animationState}`]: !visible
        }
      );
      styles = {
        ...style,
        transitionDuration: `${enter.duration}ms`,
        transitionDelay: `${enter.delay}ms`
      };
    }

    return (
      <TransitionGroup
        {...props}
        className={classes}
        component={component}
        style={styles}
      >
        {(visible || visible === undefined || keep) &&
          animateChildren
        }
      </TransitionGroup>
    );
  }
};

export default Animate;

@@ -1109,24 +1109,42 @@
 veClass%7D);%0A%0A
+    if (node) %7B%0A  
     node.sty
@@ -1171,24 +1171,26 @@
 n = '';%0A    
+ 
+ 
 node.classLi
@@ -1235,24 +1235,26 @@
 eave%60);%0A    
+  
 node.classLi
@@ -1281,32 +1281,34 @@
 %7D--enter%60);%0A    
+ 
+ 
 setTimeout(callb
@@ -1316,24 +1316,30 @@
 ck, delay);%0A
+    %7D%0A
   %7D%0A%0A  enter

Check node exists before changing properties