text: import React, {Component} from 'react';
  import {
    View,
    ViewPropTypes,
  } from 'react-native';
  import PropTypes from 'prop-types';
  
  import XDate from 'xdate';
  import dateutils from '../dateutils';
  import {xdateToData, parseDate} from '../interface';
  import styleConstructor from './style';
  import Day from './day/basic';
  import UnitDay from './day/interactive';
  import CalendarHeader from './header';
  import shouldComponentUpdate from './updater';
  
  //Fallback when RN version is < 0.44
  const viewPropTypes = ViewPropTypes || View.propTypes;
  
  const EmptyArray = [];
  
  class Calendar extends Component {
    static propTypes = {
      // Specify theme properties to override specific styles for calendar parts. Default = {}
      theme: PropTypes.object,
      // Collection of dates that have to be marked. Default = {}
      markedDates: PropTypes.object,
  
      // Specify style for calendar container element. Default = {}
      style: viewPropTypes.style,
  
      selected: PropTypes.array,
  
      // Initially visible month. Default = Date()
      current: PropTypes.any,
      // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
      minDate: PropTypes.any,
      // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
      maxDate: PropTypes.any,
  
      // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
      firstDay: PropTypes.number,
  
      // Date marking style [simple/interactive]. Default = 'simple'
      markingType: PropTypes.string,
  
      // Hide month navigation arrows. Default = false
      hideArrows: PropTypes.bool,
      // Display loading indicador. Default = false
      displayLoadingIndicator: PropTypes.bool,
      // Do not show days of other months in month page. Default = false
      hideExtraDays: PropTypes.bool,
  
      // Handler which gets executed on day press. Default = undefined
      onDayPress: PropTypes.func,
      // Handler which gets executed when visible month changes in calendar. Default = undefined
      onMonthChange: PropTypes.func,
      onVisibleMonthsChange: PropTypes.func,
      // Replace default arrows with custom ones (direction can be 'left' or 'right')
      renderArrow: PropTypes.func,
      // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
      monthFormat: PropTypes.string,
      // Disables changing month when click on days of other months (when hideExtraDays is false). Default = false
      disableMonthChange: PropTypes.bool,
      //Hide day names. Default = false
      hideDayNames: PropTypes.bool
    };
  
    constructor(props) {
      super(props);
      this.style = styleConstructor(this.props.theme);
      let currentMonth;
      if (props.current) {
        currentMonth = parseDate(props.current);
      } else {
        currentMonth = props.selected && props.selected[0] ? parseDate(props.selected[0]) : XDate();
      }
      this.state = {
        currentMonth
      };
  
      this.updateMonth = this.updateMonth.bind(this);
      this.addMonth = this.addMonth.bind(this);
      this.isSelected = this.isSelected.bind(this);
      this.pressDay = this.pressDay.bind(this);
      this.shouldComponentUpdate = shouldComponentUpdate;
    }
  
    componentWillReceiveProps(nextProps) {
      const current= parseDate(nextProps.current);
      if (current && current.toString('yyyy MM') !== this.state.currentMonth.toString('yyyy MM')) {
        this.setState({
          currentMonth: current.clone()
        });
      }
    }
  
    updateMonth(day, doNotTriggerListeners) {
      if (day.toString('yyyy MM') === this.state.currentMonth.toString('yyyy MM')) {
        return;
      }
      this.setState({
        currentMonth: day.clone()
      }, () => {
        if (!doNotTriggerListeners) {
          const currMont = this.state.currentMonth.clone();
          if (this.props.onMonthChange) {
            this.props.onMonthChange(xdateToData(currMont));
          }
          if (this.props.onVisibleMonthsChange) {
            this.props.onVisibleMonthsChange([xdateToData(currMont)]);
          }
        }
      });
    }
  
    pressDay(day) {
      const minDate = parseDate(this.props.minDate);
      const maxDate = parseDate(this.props.maxDate);
      if (!(minDate && !dateutils.isGTE(day, minDate)) && !(maxDate && !dateutils.isLTE(day, maxDate))) {
        const shouldUpdateMonth = this.props.disableMonthChange === undefined || !this.props.disableMonthChange;
        if (shouldUpdateMonth) {
          this.updateMonth(day);
        }
        if (this.props.onDayPress) {
          this.props.onDayPress(xdateToData(day));
        }
      }
    }
  
    addMonth(count) {
      this.updateMonth(this.state.currentMonth.clone().addMonths(count, true));
    }
  
    isSelected(day) {
      let selectedDays = [];
      if (this.props.selected) {
        selectedDays = this.props.selected;
      }
      for (let i = 0; i < selectedDays.length; i++) {
        if (dateutils.sameDate(day, parseDate(selectedDays[i]))) {
          return true;
        }
      }
      return false;
    }
  
    renderDay(day, id) {
      const minDate = parseDate(this.props.minDate);
      const maxDate = parseDate(this.props.maxDate);
      let state = '';
      if (this.isSelected(day)) {
        state = 'selected';
      } else if ((minDate && !dateutils.isGTE(day, minDate)) || (maxDate && !dateutils.isLTE(day, maxDate))) {
        state = 'disabled';
      } else if (!dateutils.sameMonth(day, this.state.currentMonth)) {
        state = 'disabled';
      } else if (dateutils.sameDate(day, XDate())) {
        state = 'today';
      }
      let dayComp;
      if (!dateutils.sameMonth(day, this.state.currentMonth) && this.props.hideExtraDays) {
        if (this.props.markingType === 'interactive') {
          dayComp = (<View key={id} style={{flex: 1}}/>);
        } else {
          dayComp = (<View key={id} style={{width: 32}}/>);
        }
      } else {
        const DayComp = this.props.markingType === 'interactive' ? UnitDay : Day;
        const markingExists = this.props.markedDates ? true : false;
        dayComp = (
          <DayComp
              key={id}
              state={state}
              theme={this.props.theme}
              onPress={this.pressDay}
              day={day}
              marked={this.getDateMarking(day)}
              markingExists={markingExists}
            >
              {day.getDate()}
            </DayComp>
          );
      }
      return dayComp;
    }
  
    getDateMarking(day) {
      if (!this.props.markedDates) {
        return false;
      }
      const dates = this.props.markedDates[day.toString('yyyy-MM-dd')] || EmptyArray;
      if (dates.length || dates) {
        return dates;
      } else {
        return false;
      }
    }
  
    renderWeek(days, id) {
      const week = [];
      days.forEach((day, id2) => {
        week.push(this.renderDay(day, id2));
      }, this);
      return (<View style={this.style.week} key={id}>{week}</View>);
    }
  
    render() {
      //console.log('render calendar ');
      const days = dateutils.page(this.state.currentMonth, this.props.firstDay);
      const weeks = [];
      while (days.length) {
        weeks.push(this.renderWeek(days.splice(0, 7), weeks.length));
      }
      let indicator;
      const current = parseDate(this.props.current);
      if (current) {
        const lastMonthOfDay = current.clone().addMonths(1, true).setDate(1).addDays(-1).toString('yyyy-MM-dd');
        if (this.props.displayLoadingIndicator &&
            !(this.props.markedDates && this.props.markedDates[lastMonthOfDay])) {
          indicator = true;
        }
      }
      return (
        <View style={[this.style.container, this.props.style]}>
          <CalendarHeader
            theme={this.props.theme}
            hideArrows={this.props.hideArrows}
            month={this.state.currentMonth}
            addMonth={this.addMonth}
            showIndicator={indicator}
            firstDay={this.props.firstDay}
            renderArrow={this.props.renderArrow}
            monthFormat={this.props.monthFormat}
            hideDayNames={this.props.hideDayNames}
          />
          {weeks}
        </View>);
    }
  }
  
  export default Calendar;
  