
/*
 * 
 *   Copyright 2016 RIFT.IO Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
import './button.scss';
import Loader from '../loading-indicator/loadingIndicator.jsx';
var React = require('react');
var ButtonEventListenerMixin = require('../mixins/ButtonEventListener.js');


/**
 *  A generic button component.
 *  It's props values and a brief description below
 *
 *  Label: The label of the button. What it displays at any given time.
 *  Icon: A url for an icon that will be displayed on the button.  Leave blank if no icon required.
 *  Class: Css Classes applied to the element.
 *  sizeOfButton: The preset sizes for the button (small, default, large, xlarge, expand).
 *  minWidth: Minimum Width of the button.
 *  maxWidth: Maximum Width of the button.
 **/
module.exports = React.createClass({
  displayName: "Button",
  mixins:[ButtonEventListenerMixin],
  propTypes: {
    label:           React.PropTypes.string,
    icon:            React.PropTypes.array,
    className:       React.PropTypes.string,
    //sizeOfButton:    React.PropTypes.string,
    minWidth:        React.PropTypes.string,
    maxWidth:        React.PropTypes.string,
    //isActive:        React.PropTypes.bool,
    //isFocused:       React.PropTypes.bool,
    //isHovered:       React.PropTypes.bool,
    isDisabled:      React.PropTypes.bool
  },


  /**
   * Defines default state.
   * sizeOfButton: See Prop type definitions.
   * class: See Prop type definitions.
   * label: See Prop type definitions.
   * isActive: Boolean to indicate if button is active.
   * isHovered: Boolean to indicate if the button is being hovered over.
   * isFocused: Boolean to indicate if the button has been focused.
   * isDisabled: Boolean to indicate if button has been disabled.
   * @returns {{sizeOfButton: (*|string), class: *, isActive: boolean, isHovered: boolean,
   *            isFocused: boolean, isDisabled: (*|boolean), label: *}}
   */
  getInitialState: function() {
    return {
      //sizeOfButton:   this.props.size || '',  //There is no Medium value in CSS, default size is the absence of a value
      className:      this.props.className || 'rw-button-primary', //Default value is 'rw-button-primary' which is the primary one
      label:          this.props.label,
      isActive:       false,
      isHovered:      false,
      isFocused:      false,
      isLoading:      this.props.isLoading || false,
      isDisabled:     this.props.isDisabled || false
    }
  },


  /**
   * If any of the state variables have changed, the component should update.
   * "nextProps" and "nextState" hold the state and property variables as they will be after the update.
   * "this.props" and "this.state" hold the state and property variables as they were before the update.
   * returns true if the state have changed. Otherwise returns false.
   * @param nextProps
   * @param nextState
   * @returns {boolean}
   */
  shouldComponentUpdate: function(nextProps, nextState) {
    var currentStateString = this.state.label + this.state.isDisabled + this.state.isActive + this.state.isFocused +
      this.state.isHovered + this.props.isLoading;
    var nextStateString = nextState.label + nextState.isDisabled + nextState.isActive + nextState.isFocused +
      nextState.isHovered + nextProps.isLoading;

    if (currentStateString == nextStateString) {
      return false;
    }
    return true;
  },


  /**
   * Returns a string reflecting the current state of the button.
   * If the button state "isDisabled" is true, returns a string "disabled".
   * Otherwise returns a string containing a word for each state that has been set to true.
   * (ie "active focused" if the states active and focused are true, but hovered is false).
   * @returns {string}
   */
  setButtonState: function() {
    var ret = "";
    if (this.state.isDisabled) {
      return "disabled";
    }
    if (this.state.isActive) {
      ret += "active ";
    }
    if (this.state.isHovered) {
      ret += "hovered ";
    }
    if (this.state.isFocused) {
      ret += "focused ";
    }
    return ret;
  },



  /**
   * Track the width if set and write into markup using Style attribute
   * Returns the minWidth and maxWidth prop in a string
   * @returns {{}}
   */
  setButtonWidth:function(){ 
    var width = {};  

    if (this.props.minWidth) { 
      width.minWidth = String(this.props.minWidth); 
    } 
    if (this.props.maxWidth) { 
      width.maxWidth = String(this.props.maxWidth); 
    } 

    return width; 
  },



  /**
   * Apply the size of the button to the icon directly
   * Returns a string indicating the icon size.
   * @returns {string}
   */
  /*
  setIconSize:function(){

    var iconClass = "rw-icon";

    if(this.props.size){
      iconClass += "-" + this.props.size;
    }
    return iconClass;
  },
  */



  /**
   * Builds the list of classes.
   * Returns a string holding each class seperated by a space.
   * @returns {string}
   */
  /*
  setButtonClass:function() {
    var buttonClass = "";
    var buttonClassType = "rw-button-primary";
    // If the size is declared, add it in
    if (this.state.sizeOfButton) {
      buttonClass += this.state.sizeOfButton;
    }
    //
    if (typeof(this.props.className) != "undefined") {
      this.props.className.push("rw-button-secondary");

      // Run through the array and check all the values
      for (var i = 0; i < this.props.className.length; i++) {

        if (this.props.className[i].indexOf("secondary") > -1) {
          buttonClassType = "rw-button-secondary";  // If the value of the array is equal to the string "secondary", add a predefined string
        } else {
          buttonClass += " " + this.props.className[i];  // Else just write the value of the array
        }
      }
    }
    buttonClass += " " + buttonClassType;  //Add the button style type either primary or secondary
    return buttonClass;
  },
  */

  /**
   * Builds an array of html elements for the icons and returns them.
   * @returns {Array}
   */
  setIconElement: function() {
    var button_icon = [];

    if (typeof(this.props.icon) != "undefined") {
      for (var i = 0; i < this.props.icon.length; i++) {
        button_icon.push(React.createElement('svg', {
          className: "rw-button__icon",
          key: i,
          dangerouslySetInnerHTML: {__html: '<use xlink:href="#' + this.props.icon[i] + '" />'}  //Using a React method to drop in a hack since React does not support xlink:href yet
        }));
      }
    }
    return button_icon;
  },

  /**
   * Renders the Button Component
   * Returns a react component that constructs the html that houses the button component.
   * @returns {*}
   */
  render: function() {
    var button = null;
    var button_style = this.setButtonWidth();
    var button_state = this.setButtonState();
    var button_class = this.state.className;
    var button_icon = this.setIconElement();
    var display = this.state.label;
    if (this.props.isLoading) {
      display = React.createElement(Loader, {show: true, size: '1rem', color: this.props.loadingColor});
    }

    button = React.createElement("button", {
        className:         button_class,
        "data-state":      button_state,
        style:             button_style,

        // onClick:           this.onClick,
        onClick:           this.props.onClick,
        onMouseUp:         this.onMouseUp,
        onMouseDown:       this.onMouseDown,
        onMouseOver:       this.onMouseOver,
        onMouseEnter:      this.onMouseEnter,
        onMouseLeave:      this.onMouseLeave,
        onMouseOut:        this.onMouseOut,
        onTouchCancel:     this.onTouchCancel,
        onTouchEnd:        this.onTouchEnd,
        onTouchMove:       this.onTouchMove,
        onTouchStart:      this.onTouchStart,
        onKeyDown:         this.onKeyDown,
        onKeyPress:        this.onKeyPress,
        onKeyUp:           this.onKeyUp,
        onFocus:           this.onFocus,
        onBlur:            this.onBlur
      },
      button_icon,
      React.createElement("span", {className: "rw-button__label"}, display)
    );
    return button;
  }
});
