<!DOCTYPE html>
<html>

  <head>
    <script data-require="react@*" data-semver="0.12.2" src="//cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js"></script>
    <script src="https://rawgit.com/rsamec/react-binding/master/dist/react-binding.min.js"></script>
   <script src="https://rawgit.com/flesler/hashmap/master/hashmap.js"></script>
    <script src="https://rawgit.com/rsamec/business-rules-engine/master/dist/business-rules-engine.js"></script>
    <script data-require="underscore.js@1.6.0" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <div id="content"></div>
    <script src="script.js"></script>
  </body>

</html>

var Binder = Binder.default;
var Hobby = React.createClass({
    removeHobby: function(e){
        return this.props.onDelete(this.props.model.value);
    },
    frequencyName:function(){ return "frequency" + this.props.index;},
    hobbyLabel:function(){ return (this.props.index + 1) + ". hobby name";},
    render: function() {
        return (
            <div className="comment">
              <TextBoxInput label={this.hobbyLabel()} model={Binder.bindTo(this.props.model,"HobbyName")} error={this.props.error.HobbyName} />
              <button onClick={this.removeHobby}>Delete</button>

              <RadioGroup name={this.frequencyName()} 
                valueLink={Binder.bindTo(this.props.model,"Frequency")}>
                <div>
                  <label>
                    <input type="radio" value="Daily"  />Daily
                  </label>
                  <label>
                    <input type="radio" value="Weekly" />Weekly
                  </label>
                  <label>
                    <input type="radio" value="Monthly" />Monthly
                  </label>
                </div>
              </RadioGroup>

              <CheckBoxInput label="Is this a paid hobby?" model={Binder.bindTo(this.props.model,"Paid")} />
              <CheckBoxInput label="Would you recommend this hobby to a friend?" model={Binder.bindTo(this.props.model,"Recommendation")} />

            </div>
        );
    }
});

var HobbyForm = React.createClass({
    getInitialState: function() {
        return {
          data: {},
          rules:new FormSchema.JsonSchemaRuleFactory(BusinessRules).CreateRule("Main")
        };
    },
    addHobby:function(e){
      if (this.state.data.Hobbies === undefined)
        this.state.data.Hobbies = []
      this.state.data.Hobbies.push({});
      this.setState({data:this.state.data})
    },
    result:function(){
      if (this.state.rules === undefined) return {Errors:{}};
      return Utils.CompositeDotObject.Transform(this.state.rules.Validate(this.state.data)).Main;
    },
    render: function() {
        return (
            <div className="commentBox">
                <h1>Hobbies form</h1>
                <div style={{"float":"right","width":"400"}}>
                  <PrettyJson json={this.state.data} />
                </div>
                <div >
                  <PersonComponent model={Binder.bindToState(this,"data","Person")} error={this.result().Person}  />

                  <button value="Add" onClick={this.addHobby}>Add</button>
                  <div className="error">{this.result().Hobbies.PropRule.ErrorMessage}</div>
                  <HobbyList  model={Binder.bindArrayToState(this,"data","Hobbies")} errors={this.result().Hobbies.Children} />
                </div>

            </div>
        );
    }
});

var HobbyList = React.createClass({
    handleDelete: function(hobby){
        return this.props.model.remove(hobby);
    },
    render: function() {
        if (this.props.model.items === undefined) return <span>There are no hobbies.</span>;

        var hobbyNodes = this.props.model.items.map(function(hobby, index) {
            return (
                <Hobby model={hobby} key={index} index={index} onDelete={this.handleDelete} error={this.props.errors[index]} />
            );
        },this);
        return (
            <div className="commentList">
                {hobbyNodes}
            </div>
        );
    }
});

var PersonComponent = React.createClass({
  
  render: function() {
      return (
      <div>
        <TextBoxInput label="First name" model={Binder.bindTo(this.props.model,"FirstName")} error={this.props.error.FirstName}  />
        <TextBoxInput label="Last name" model={Binder.bindTo(this.props.model,"LastName")} error={this.props.error.LastName} />
        <TextBoxInput label="Email"  model={Binder.bindTo(this.props.model,"Contact.Email")}  error={this.props.error.Contact.Email}  />
      </div>
    );
  }
});

var TextBoxInput = React.createClass({
  render: function() {
    return (
      <div style={{display:'inline'}}>
        <label  style={{display:'block'}}>{this.props.label}</label>
        <input type='text' valueLink={this.props.model} />
        <div className="error">{this.props.error.ErrorMessage}</div>
      </div>
    )
  }
});

var CheckBoxInput = React.createClass({
  render: function() {
    var valueModel = this.props.model;
    var handleChange = function(e){
      valueModel.value = e.target.checked;
    }

    return (
      <label>
        <input type='checkbox' onChange={handleChange} checked={valueModel.value} />
        {this.props.label}
      </label>
    )
  }
});


var PrettyJson = React.createClass({
  replacer: function (match, pIndent, pKey, pVal, pEnd) {
    var key = '<span class=json-key>';
    var val = '<span class=json-value>';
    var str = '<span class=json-string>';
    var r = pIndent || '';
    if (pKey)
      r = r + key + pKey.replace(/[": ]/g, '') + '</span>: ';
    if (pVal)
      r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
    return r + (pEnd || '');
  },

  prettyPrint: function (obj) {
    var jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
    return JSON.stringify(obj, null, 3)
      .replace(/&/g, '&amp;').replace(/\\"/g, '&quot;')
      .replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(jsonLine, this.replacer);

  },
  render: function () {
    return (<pre dangerouslySetInnerHTML={{__html: this.prettyPrint(this.props.json)}}></pre>);
  }
})

var RadioGroup = React.createClass({displayName: 'RadioGroup',
  getInitialState: function() {
    // check the first block of comment in `setCheckedRadio`
    return {defaultValue: this.props.defaultValue};
  },

  componentDidMount: function() {
    this.setRadioNames();
    this.setCheckedRadio();
  },

  componentDidUpdate: function() {
    this.setRadioNames();
    this.setCheckedRadio();
  },

  render: function() {
    return (
      React.DOM.div({ onChange:this.props.onChange },
        this.props.children
      )
    );
  },

  setRadioNames: function() {
    // stay DRY and don't put the same `name` on all radios manually. Put it on
    // the tag and it'll be done here
    var $radios = this.getRadios();
    for (var i = 0, length = $radios.length; i < length; i++) {
      $radios[i].setAttribute('name', this.props.name);
    }
  },

  getRadios: function() {
    return this.getDOMNode().querySelectorAll('input[type="radio"]');
  },

  setCheckedRadio: function() {
    var $radios = this.getRadios();
    // if `value` is passed from parent, always use that value. This is similar
    // to React's controlled component. If `defaultValue` is used instead,
    // subsequent updates to defaultValue are ignored. Note: when `defaultValue`
    // and `value` are both passed, the latter takes precedence, just like in
    // a controlled component
    var destinationValue = this.props.value != null
      ? this.props.value
      : this.state.defaultValue;

    for (var i = 0, length = $radios.length; i < length; i++) {
      var $radio = $radios[i];

      // intentionally use implicit conversion for those who accidentally used,
      // say, `valueToChange` of 1 (integer) to compare it with `value` of "1"
      // (auto conversion to valid html value from React)
      if ($radio.value == destinationValue) {
        $radio.checked = true;
      }
    }
  },

  getCheckedValue: function() {
    var $radios = this.getRadios();

    for (var i = 0, length = $radios.length; i < length; i++) {
      if ($radios[i].checked) {
        return $radios[i].value;
      }
    }

    return null;
  }
});

var BusinessRules = {
  "Person": {
    "type": "object",
    "properties": {
      "FirstName": {
        "type": "string",
        "title": "First name",
        "required": "true",
        "maxLength": "15"
      },
      "LastName": {
        "type": "string",
        "title": "Last name",
        "required": "true",
        "maxLength": "15"
      },
      "Contact": {
        "type": "object",
        "properties": {
          "Email": {
            "type": "string",
            "title": "Email",
            "required": "true",
            "maxLength": 100,
            "email": "true"
          }
        }
      }
    }
  },
  "Hobbies": {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "HobbyName": {
          "type": "string",
          "title": "HobbyName",
          "required": "true",
          "maxLength": 100
        },
        "Frequency": {
          "type": "string",
          "title": "Frequency",
          "enum": ["Daily", "Weekly", "Monthly"]
        },
        "Paid": {
          "type": "boolean",
          "title": "Paid"
        },
        "Recommedation": {
          "type": "boolean",
          "title": "Recommedation"
        }
      }
    },
    "maxItems": 4,
    "minItems": 2
  }
};

React.render(
    <HobbyForm />,
    document.getElementById('content')
);
/* Styles go here */

.error{
    color: darkred;
}