import React from 'react';
import StylePropable from '../mixins/style-propable';
import WindowListenable from '../mixins/window-listenable';
import DateTime from '../utils/date-time';
import DatePickerDialog from './date-picker-dialog';
import TextField from '../text-field';
import getMuiTheme from '../styles/getMuiTheme';
import deprecated from '../utils/deprecatedPropType';
import warning from 'warning';

const DatePicker = React.createClass({

  propTypes: {
    /**
     * Constructor for time formatting.
     * Follow this specificaction: ECMAScript Internationalization API 1.0 (ECMA-402).
     */
    DateTimeFormat: React.PropTypes.func,

    /**
     * If true, automatically accept and close the picker on select a date.
     */
    autoOk: React.PropTypes.bool,

    /**
     * Used to control how the DatePicker will be displayed when a user tries to set a date.
     * `dialog` (default) displays the DatePicker as a dialog with a modal.
     * `inline` displays the DatePicker below the input field (similar to auto complete).
     */
    container: React.PropTypes.oneOf(['dialog', 'inline']),

    /**
     * This is the initial date value of the component.
     * If either `value` or `valueLink` is provided they will override this
     * prop with `value` taking precedence.
     */
    defaultDate: React.PropTypes.object,

    /**
     * Disables the year selection in the date picker.
     */
    disableYearSelection: React.PropTypes.bool,

    /**
     * Disables the DatePicker.
     */
    disabled: React.PropTypes.bool,

    /**
     * Used to change the first day of week. It drastically varies from
     * Saturday to Monday (could even be Friday) between different locales.
     * The allowed range is 0 (Sunday) to 6 (Saturday).
     */
    firstDayOfWeek: React.PropTypes.number,

    /**
     * This function is called to format the date to display in the input box.
     * By default, date objects are formatted to MM/DD/YYYY.
     */
    formatDate: React.PropTypes.func,

    /**
     * Locale used for formatting date. If you are not using the default value, you
     * have to provide a DateTimeFormat that supports it. You can use Intl.DateTimeFormat
     * if it's supported by your environment.
     * https://github.com/andyearnshaw/Intl.js is a good polyfill.
     */
    locale: React.PropTypes.string,

    /**
     * The ending of a range of valid dates. The range includes the endDate.
     * The default value is current date + 100 years.
     */
    maxDate: React.PropTypes.object,

    /**
     * The beginning of a range of valid dates. The range includes the startDate.
     * The default value is current date - 100 years.
     */
    minDate: React.PropTypes.object,

    /**
     * Tells the component to display the picker in portrait or landscape mode.
     */
    mode: React.PropTypes.oneOf(['portrait', 'landscape']),

    /**
     * Callback function that is fired when the date value changes. Since there
     * is no particular event associated with the change the first argument
     * will always be null and the second argument will be the new Date instance.
     */
    onChange: React.PropTypes.func,

    /**
     * Fired when the datepicker dialog is dismissed.
     */
    onDismiss: React.PropTypes.func,

    /**
     * Callback function that is fired when the datepicker field gains focus.
     */
    onFocus: React.PropTypes.func,

    /**
     * Fired when the datepicker dialog is shown.
     */
    onShow: React.PropTypes.func,

    /**
     * Called when touch tap event occurs on text-field.
     */
    onTouchTap: React.PropTypes.func,

    /**
     * Called during render time of a given day. If this method returns
     * false the day is disabled otherwise it is displayed normally.
     */
    shouldDisableDate: React.PropTypes.func,

    /**
     *  Enables the year selection in the date picker.
     */
    showYearSelector: deprecated(React.PropTypes.bool,
          'Instead, use disableYearSelection.'),

    /**
     * Override the inline-styles of the root element.
     */
    style: React.PropTypes.object,

    /**
     * Override the inline-styles of DatePicker's TextField element.
     */
    textFieldStyle: React.PropTypes.object,

    /**
     * Sets the date for the Date Picker programmatically.
     */
    value: React.PropTypes.any,

    /**
     * Creates a ValueLink with the value of date picker.
     */
    valueLink: React.PropTypes.object,

    /**
     * Wordings used inside the button of the dialog.
     */
    wordings: React.PropTypes.object,
  },

  contextTypes: {
    muiTheme: React.PropTypes.object,
  },

  //for passing default theme context to children
  childContextTypes: {
    muiTheme: React.PropTypes.object,
  },

  mixins: [
    StylePropable,
    WindowListenable,
  ],

  getDefaultProps() {
    return {
      formatDate: DateTime.format,
      autoOk: false,
      disableYearSelection: false,
      style: {},
      firstDayOfWeek: 0,
      disabled: false,
    };
  },

  getInitialState() {
    return {
      date: this._isControlled() ? this._getControlledDate() : this.props.defaultDate,
      dialogDate: new Date(),
      muiTheme: this.context.muiTheme || getMuiTheme(),
    };
  },

  getChildContext() {
    return {
      muiTheme: this.state.muiTheme,
    };
  },

  componentWillReceiveProps(nextProps, nextContext) {
    if (nextContext.muiTheme) {
      this.setState({muiTheme: nextContext.muiTheme});
    }

    if (this._isControlled()) {
      let newDate = this._getControlledDate(nextProps);
      if (!DateTime.isEqualDate(this.state.date, newDate)) {
        this.setState({
          date: newDate,
        });
      }
    }
  },

  windowListeners: {
    keyup: '_handleWindowKeyUp',
  },

  getDate() {
    return this.state.date;
  },

  setDate(date) {
    warning(false, `setDate() method is deprecated. Use the defaultDate property instead.
      Or use the DatePicker as a controlled component with the value property.`);

    this.setState({
      date: date,
    });
  },

  /**
   * Open the date-picker dialog programmatically from a parent.
   */
  openDialog() {
    this.setState({
      dialogDate: this.getDate(),
    }, this.refs.dialogWindow.show);
  },

  /**
   * Alias for `openDialog()` for an api consistent with TextField.
   */
  focus() {
    this.openDialog();
  },

  _handleDialogAccept(date) {
    if (!this._isControlled()) {
      this.setState({
        date: date,
      });
    }
    if (this.props.onChange) this.props.onChange(null, date);
    if (this.props.valueLink) this.props.valueLink.requestChange(date);
  },

  _handleInputFocus(e) {
    e.target.blur();
    if (this.props.onFocus) this.props.onFocus(e);
  },

  _handleInputTouchTap: function _handleInputTouchTap(event) {
    if (this.props.onTouchTap) this.props.onTouchTap(event);

    if (!this.props.disabled)
      setTimeout(() => {
        this.openDialog();
      }, 0);
  },

  _handleWindowKeyUp() {
    //TO DO: open the dialog if input has focus
  },

  _isControlled() {
    return this.props.hasOwnProperty('value') ||
      this.props.hasOwnProperty('valueLink');
  },

  _getControlledDate(props = this.props) {
    if (DateTime.isDateObject(props.value)) {
      return props.value;
    } else if (props.valueLink && DateTime.isDateObject(props.valueLink.value)) {
      return props.valueLink.value;
    }
  },

  render() {
    let {
      container,
      DateTimeFormat,
      locale,
      wordings,
      autoOk,
      defaultDate,
      formatDate,
      maxDate,
      minDate,
      mode,
      onDismiss,
      onFocus,
      onShow,
      onTouchTap,
      disableYearSelection,
      style,
      textFieldStyle,
      valueLink,
      firstDayOfWeek,
      ...other,
    } = this.props;

    return (
      <div style={this.prepareStyles(style)}>
        <TextField
          {...other}
          style={textFieldStyle}
          ref="input"
          value={this.state.date ? formatDate(this.state.date) : undefined}
          onFocus={this._handleInputFocus}
          onTouchTap={this._handleInputTouchTap}
        />
        <DatePickerDialog
          container={container}
          ref="dialogWindow"
          DateTimeFormat={DateTimeFormat}
          locale={locale}
          wordings={wordings}
          mode={mode}
          initialDate={this.state.dialogDate}
          onAccept={this._handleDialogAccept}
          onShow={onShow}
          onDismiss={onDismiss}
          minDate={minDate}
          maxDate={maxDate}
          autoOk={autoOk}
          disableYearSelection={disableYearSelection}
          shouldDisableDate={this.props.shouldDisableDate}
          firstDayOfWeek={firstDayOfWeek}
        />
      </div>
    );
  },

});

export default DatePicker;
