var React = require('react');
var KeyCode = require('../utils/key-code');
var Classable = require('../mixins/classable');
var UniqueId = require('../utils/unique-id');
var WindowListenable = require('../mixins/window-listenable');
var FocusRipple = require('./ripples/focus-ripple');
var TouchRipple = require('./ripples/touch-ripple');
var Paper = require('./paper');

var EnhancedSwitch = React.createClass({

	mixins: [Classable, WindowListenable],

	propTypes: {
	    id: React.PropTypes.string,
	    inputType: React.PropTypes.string.isRequired,
	    switchElement: React.PropTypes.element.isRequired,
	    iconClassName: React.PropTypes.string.isRequired,
	    name: React.PropTypes.string,
	    value: React.PropTypes.string,
	    label: React.PropTypes.string,
	    onSwitch: React.PropTypes.func,
	    required: React.PropTypes.bool,
	    disabled: React.PropTypes.bool,
	    defaultSwitched: React.PropTypes.bool,
	    labelPosition: React.PropTypes.oneOf(['left', 'right']),
	    disableFocusRipple: React.PropTypes.bool,
	    disableTouchRipple: React.PropTypes.bool
	},

	windowListeners: {
	  'keydown': '_handleWindowKeydown',
	  'keyup': '_handleWindowKeyup'
	},

	getDefaultProps: function() {
		return {
			iconClassName: ''
		};
	},

	getInitialState: function() {
		return {
			switched: this.props.defaultSwitched || (this.props.valueLink && this.props.valueLink.value),
			isKeyboardFocused: false
		};
	},

	componentDidMount: function() {
		var inputNode = this.refs.checkbox.getDOMNode();
		this.setState({switched: inputNode.checked});
	},

	componentWillReceiveProps: function(nextProps) {
		var hasCheckedLinkProp = nextProps.hasOwnProperty('checkedLink');
		var hasCheckedProp = nextProps.hasOwnProperty('checked');
		var hasToggledProp = nextProps.hasOwnProperty('toggled');
		var hasNewDefaultProp = (nextProps.hasOwnProperty('defaultSwitched') && (nextProps.defaultSwitched != this.props.defaultSwitched));

		var newState = {};
		if (hasCheckedProp) {
		  newState.switched = nextProps.checked;
		} else if (hasToggledProp) {
		  newState.switched = nextProps.toggled;
		} else if (hasCheckedLinkProp) {
		  newState.switched = nextProps.checkedLink.value;
		}

		if (newState) {
			this.setState(newState);
		};
	},


	render: function() {

		var {
		  type,
		  name,
		  value,
		  label,
		  onSwitch,
		  defaultSwitched,
		  onBlur,
		  onFocus,
		  onMouseUp,
		  onMouseDown,
		  onMouseOut,
		  onTouchStart,
		  onTouchEnd,
		  disableTouchRipple,
		  disableFocusRipple,
		  iconClassName,
		  ...other
		} = this.props;

		var classes = this.getClasses('dig-enhanced-switch', {
			'dig-is-switched': this.state.switched,
			'dig-is-disabled': this.props.disabled,
			'dig-is-required': this.props.required
		});

		var inputId = this.props.id || UniqueId.generate();

		var labelElement = this.props.label ? (
			<label className='dig-switch-label' htmlFor={inputId}>
				{this.props.label}
			</label>
		) : null;

		var inputProps = {
			ref: "checkbox",
			type: this.props.inputType,
			name: this.props.name,
			value: this.props.value,
			defaultChecked: this.props.defaultSwitched,
			onBlur: this._handleBlur,
			onFocus: this._handleFocus
		};

		var hideTouchRipple = this.props.disabled || disableTouchRipple;

		if (!hideTouchRipple) {
			inputProps.onMouseUp = this._handleMouseUp;
			inputProps.onMouseDown = this._handleMouseDown;
			inputProps.onMouseOut = this._handleMouseOut;
			inputProps.onTouchStart = this._handleTouchStart;
			inputProps.onTouchEnd = this._handleTouchEnd;
		};

		if (!this.props.hasOwnProperty('checkedLink')) {
		  inputProps.onChange = this._handleChange;
		}

		var inputElement = (
			<input 
				{...other}
				{...inputProps}
				className="dig-enhanced-switch-input" />
		);

		var touchRipple = (
			<TouchRipple
				ref="touchRipple"
				key="touchRipple"
				centerRipple={true} />
		);

		var focusRipple = (
			<FocusRipple
				key="focusRipple"
				show={this.state.isKeyboardFocused} />
		);

		var ripples = [
			hideTouchRipple ? null : touchRipple,
			this.props.disabled || disableFocusRipple ? null : focusRipple
		];

		iconClassName += ' dig-enhanced-switch-wrap';

		var switchElement = (this.props.iconClassName.indexOf("toggle") == -1) ? (
		    <div className={iconClassName}>
		      {this.props.switchElement}
		      {ripples}
		    </div>
		  ) : (
		    <div className={iconClassName}>
		      <div className="dig-toggle-track" />
		      <Paper className="dig-toggle-thumb" zDepth={1}> {ripples} </Paper>
		    </div>
		);

		var labelPositionExist = this.props.labelPosition;

		// Position is left if not defined or invalid.
		var elementsInOrder = (labelPositionExist &&
		  (this.props.labelPosition.toUpperCase() === "RIGHT")) ? (
		    <div>
		      {switchElement}
		      {labelElement}
		    </div>
		  ) : (
		    <div>
		      {labelElement}
		      {switchElement}
		    </div>
		);

		return (
			<div className={classes}>
	            {inputElement}
	            {elementsInOrder}
	        </div>
		);
	},

	isSwitched: function() {
	  return this.refs.checkbox.getDOMNode().checked;
	},

	// no callback here because there is no event
	setSwitched: function(newSwitchedValue) {
	  if (!this.props.hasOwnProperty('checked') || this.props.checked === false) {
	    this.setState({switched: newSwitchedValue});
	    this.refs.checkbox.getDOMNode().checked = newSwitchedValue;
	  } else if (process.NODE_ENV !== 'production') {
	    var message = 'Cannot call set method while checked is defined as a property.';
	    console.error(message);
	  }
	},

	getValue: function() {
	  return this.refs.checkbox.getDOMNode().value;
	},

	isKeyboardFocused: function() {
	  return this.state.isKeyboardFocused;
	},

	_handleChange: function(e) {

	  this._tabPressed = false;
	  this.setState({
	    isKeyboardFocused: false
	  });

	  var isInputChecked = this.refs.checkbox.getDOMNode().checked;

	  if (!this.props.hasOwnProperty('checked')) this.setState({switched: isInputChecked});
	  if (this.props.onSwitch) this.props.onSwitch(e, isInputChecked);
	},

	/**
	 * Because both the ripples and the checkbox input cannot share pointer
	 * events, the checkbox input takes control of pointer events and calls
	 * ripple animations manually.
	 */

	// Checkbox inputs only use SPACE to change their state. Using ENTER will
	// update the ui but not the input.
	_handleWindowKeydown: function(e) {
	  if (e.keyCode == KeyCode.TAB) this._tabPressed = true;
	  if (e.keyCode == KeyCode.SPACE && this.state.isKeyboardFocused) {
	    this._handleChange(e);
	  }
	},

	_handleWindowKeyup: function(e) {
	  if (e.keyCode == KeyCode.SPACE && this.state.isKeyboardFocused) {
	    this._handleChange(e);
	  }
	},

	_handleMouseDown: function(e) {
	  //only listen to left clicks
	  if (e.button === 0) this.refs.touchRipple.start(e);
	},

	_handleMouseUp: function(e) {
	  this.refs.touchRipple.end();
	},

	_handleMouseOut: function(e) {
	  this.refs.touchRipple.end();
	},

	_handleTouchStart: function(e) {
	  this.refs.touchRipple.start(e);
	},

	_handleTouchEnd: function(e) {
	  this.refs.touchRipple.end();
	},

	_handleBlur: function(e) {
	  this.setState({
	    isKeyboardFocused: false
	  });

	  if (this.props.onBlur) this.props.onBlur(e);
	},

	_handleFocus: function(e) {
	  //setTimeout is needed becuase the focus event fires first
	  //Wait so that we can capture if this was a keyboard focus
	  //or touch focus
	  setTimeout(function() {
	    if (this._tabPressed) {
	      this.setState({
	        isKeyboardFocused: true
	      });
	    }
	  }.bind(this), 150);

	  if (this.props.onFocus) this.props.onFocus(e);
	}
});

module.exports = EnhancedSwitch;