var React = require('react');
var pathToRegexp = require('path-to-regexp');
var assign = require('object-assign');
var zipObject = require('lodash/array/zipObject');
var clone = require('lodash/lang/clone');
var pluck = require('lodash/collection/pluck');

var DOM = React.DOM;
var createClass = React.createClass;
var PropTypes = React.PropTypes;
var Children = React.Children;
var cloneElement = React.cloneElement;

var SmallRouter = {
  // Private, singleton store for all routes
  // TODO: add scope to props of route element?
  routes: [],
  listeners: [],

  navigateTo: function (path) {

    window.location.hash = path;
  },

  currentPath: function () {

    var rawPath = window.location.hash.split('#')[1];

    if (rawPath === undefined) {
      rawPath = '';
    }

    return rawPath;
  },

  currentPathMatches: function (path) {

    return path === SmallRouter.currentPath();
  }
};

// No need to remove this event listener. It needs
// to live as long as the app does
window.addEventListener('hashchange', function () {

  SmallRouter.listeners.forEach(function (fn) {

    fn();
  });
});

function onHashChange (fn) {

  SmallRouter.listeners.push(fn);
}

SmallRouter.Link = createClass({

  propTypes: {
    path: PropTypes.string.isRequired,
    activeClassName: PropTypes.string,
    activeStyle: PropTypes.object
  },

  getDefaultProps: function () {

    return {
      activeClassName: 'active',
      activeStyle: {}
    };
  },

  getInitialState: function () {

    return {
      active: false
    };
  },

  componentDidMount () {

    this.setActiveClassName();
  },

  setActiveClassName () {

    if (SmallRouter.currentPath() === this.props.path) {
      this.setState({
        active: true
      });
    }
  },

  gotoPath: function (e) {

    e.preventDefault();
    SmallRouter.navigateTo(this.props.path);
    this.setActiveClassName();
  },

  render: function () {

    let style = assign({
      cursor: 'pointer'
    }, this.state.active ? this.props.activeStyle : {});

    return (
      <a
        style={style}
        onClick={this.gotoPath}
        className={this.state.active ? this.props.activeClassName : null} >
          {this.props.children}
      </a>
    );
  }
});

SmallRouter.Route = createClass({

  propTypes: {
    path: PropTypes.string.isRequired,
    paramsAsProps: PropTypes.object,
    willRender: PropTypes.func
  },

  getDefaultProps: function () {

    return {
      paramsAsProps: {},
      willRender: function () {}
    }
  },

  getInitialState: function () {

    return {
      path: this.parseHash()
    }
  },

  componentDidMount: function () {

    SmallRouter.routes.push({
      path: this.props.path
    });

    onHashChange(this.hashChange);
  },

  hashChange: function () {

    var path = this.parseHash();
    this.setState({path: path});
  },

  parseHash: function () {

    return SmallRouter.currentPath();
  },

  shouldRender: function () {

    return pathToRegexp(this.props.path).exec(this.parseHash());
  },

  parseParams: function () {

    var pathRegex = pathToRegexp(this.props.path);
    var parsedPath = pathToRegexp.parse(this.props.path);

    var keys = pluck(parsedPath.slice(1), 'name');
    var values = this.parseHash().match(pathRegex).slice(1);

    return zipObject(keys, values);
  },

  render: function () {

    var element = null;
    var self = this;


    if (this.shouldRender()) {

      var params = this.parseParams();

      this.props.willRender(params);

      // For now, cloning the element and adding the router
      // information to the props is the only way to get
      // information into the children.
      // Hopefully we can change this in the future.
      var children = Children.map(this.props.children, function (child) {

        if (typeof child === 'string') {
          return child;
        }

        // Map params from paramsAs
        var paramsAsProps = {};

        Object.keys(self.props.paramsAsProps)
        .forEach(function (key) {

            var mapToKey = self.props.paramsAsProps[key]
            paramsAsProps[mapToKey] = params[key];
          });

        var props = assign(clone(self.props), {
          router: {
            params: params
          }
        }, paramsAsProps);

        return cloneElement(child, props);
      });

      element = DOM.div(null, children);
    }

    return element;
  }
});

module.exports = SmallRouter;

@@ -1928,18 +1928,27 @@
  assign(
-%7B
 %0A
+      %7B%0A  
       cu
@@ -1967,18 +1967,69 @@
 er'%0A    
-%7D,
+  %7D,%0A      this.props.style, // TODO: test this%0A     
  this.st
@@ -2068,18 +2068,22 @@
 yle : %7B%7D
+%0A    
 )
-;
 %0A%0A    re
@@ -2091,21 +2091,16 @@
 urn 
-(%0A      %3Ca%0A  
+DOM.a(%7B%0A
     
@@ -2110,19 +2110,17 @@
 tyle
-=%7B
+: 
 style
-%7D%0A  
+,%0A
     
@@ -2128,18 +2128,18 @@
  onClick
-=%7B
+: 
 this.got
@@ -2143,20 +2143,18 @@
 gotoPath
-%7D%0A  
+,%0A
       cl
@@ -2164,10 +2164,10 @@
 Name
-=%7B
+: 
 this
@@ -2219,23 +2219,16 @@
 null
-%7D %3E
 %0A    
-      %7B
+%7D, 
 this
@@ -2246,25 +2246,8 @@
 dren
-%7D%0A      %3C/a%3E%0A    
 );%0A 

use DOM api. Fixes #4