import React from 'react'
import matchMedia from 'matchmedia'
import hyphenate  from 'hyphenate-style-name'
import mediaQuery from './mediaQuery'
import toQuery  from './toQuery'


const defaultTypes = {
  component: React.PropTypes.node,
  query: React.PropTypes.string,
  values: React.PropTypes.shape(mediaQuery.matchers),
  children: React.PropTypes.oneOfType([ React.PropTypes.node, React.PropTypes.function ])
}
const mediaKeys = Object.keys(mediaQuery.all)
const excludedQueryKeys = Object.keys(defaultTypes)
const excludedPropKeys = excludedQueryKeys.concat(mediaKeys)

function omit(object, keys) {
  const newObject = { ...object }
  keys.forEach(key => delete newObject[key])
  return newObject
}

export default class MediaQuery extends React.Component {
  static displayName = 'MediaQuery'
  static defaultProps = {
    values: {}
  }

  state = { matches: false }

  componentWillMount() {
    this.updateQuery(this.props)
  }

  componentWillReceiveProps(nextProps) {
    this.updateQuery(nextProps)
  }

  updateQuery(props) {
    let values
    if (props.query) {
      this.query = props.query
    } else {
      this.query = toQuery(omit(props, excludedQueryKeys))
    }

    if (!this.query) {
      throw new Error('Invalid or missing MediaQuery!')
    }

    if (props.values) {
      values = Object.keys(props.values)
        .reduce(function (result, key) {
          result[hyphenate(key)] = props.values[key]
          return result
        }, {})
    }

    if (this._mql) {
      this._mql.removeListener(this.updateMatches)
    }

    this._mql = matchMedia(this.query, values)
    this._mql.addListener(this.updateMatches)
    this.updateMatches()
  }


  componentWillUnmount() {
    this._mql.removeListener(this.updateMatches)
  }

  updateMatches = () => {
    if (this._mql.matches === this.state.matches) {
      return
    }
    this.setState({
      matches: this._mql.matches
    })
  }

  render() {
    if(typeof this.props.children === 'function') {
      return this.props.children(this.state.matches)
    }

    if (this.state.matches === false) {
      return null
    }
    const props = omit(this.props, excludedPropKeys)
    const hasMergeProps = Object.keys(props).length > 0
    const childrenCount = React.Children.count(this.props.children)
    const wrapChildren = this.props.component ||
      childrenCount > 1 ||
      typeof this.props.children === 'string' ||
      Array.isArray(this.props.children) && childrenCount == 1 ||
      this.props.children === undefined
    if (wrapChildren) {
      return React.createElement(
        this.props.component || 'div',
        props,
        this.props.children
      )
    } else if (hasMergeProps) {
      return React.cloneElement(
        this.props.children,
        props
      )
    } else if (childrenCount) {
      return this.props.children
    }
    else {
      return null
    }
  }
}

@@ -19,16 +19,51 @@
 'react'%0A
+import PropTypes from 'prop-types'%0A
 import m
@@ -245,29 +245,23 @@
 ponent: 
-React.
 Prop
-Typ
+tyP
 es.node,
@@ -270,29 +270,23 @@
  query: 
-React.
 Prop
-Typ
+tyP
 es.strin
@@ -298,29 +298,23 @@
 values: 
-React.
 Prop
-Typ
+tyP
 es.shape
@@ -348,29 +348,23 @@
 ildren: 
-React.
 Prop
-Typ
+tyP
 es.oneOf
@@ -370,29 +370,23 @@
 fType(%5B 
-React.
 Prop
-Typ
+tyP
 es.node,
@@ -390,21 +390,15 @@
 de, 
-React.
 Prop
-Typ
+tyP
 es.f

Replace react proptypes