// 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.

define([
  'app',
  'api',
  'react',
  'addons/activetasks/stores',
  'addons/activetasks/resources',
  'addons/activetasks/actions',
  'addons/components/react-components.react',
  'addons/fauxton/components.react'
], function (app, FauxtonAPI, React, Stores, Resources, Actions, Components, ComponentsReact) {

  var activeTasksStore = Stores.activeTasksStore;
  var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;

  var ActiveTasksController = React.createClass({

    getStoreState: function () {
      return {
        collection: activeTasksStore.getCollection(),
        searchTerm: activeTasksStore.getSearchTerm(),
        selectedRadio: activeTasksStore.getSelectedRadio(),

        sortByHeader: activeTasksStore.getSortByHeader(),
        headerIsAscending: activeTasksStore.getHeaderIsAscending(),

        setPolling: activeTasksStore.setPolling,
        clearPolling: activeTasksStore.clearPolling
      };
    },

    getInitialState: function () {
      return this.getStoreState();
    },

    componentDidMount: function () {
      this.state.setPolling();
      activeTasksStore.on('change', this.onChange, this);
    },

    componentWillUnmount: function () {
      this.state.clearPolling();
      activeTasksStore.off('change', this.onChange, this);
    },

    onChange: function () {
      this.setState(this.getStoreState());
    },

    setNewSearchTerm: function (searchTerm) {
      Actions.setSearchTerm(searchTerm);
    },

    switchTab: function (newRadioButton) {  //tabs buttons
      Actions.switchTab(newRadioButton);
    },

    tableHeaderOnClick: function (headerClicked) {
      Actions.sortByColumnHeader(headerClicked);
    },

    render: function () {
      var collection = this.state.collection;
      var searchTerm = this.state.searchTerm;
      var selectedRadio = this.state.selectedRadio;
      var sortByHeader = this.state.sortByHeader;
      var headerIsAscending = this.state.headerIsAscending;

      var setSearchTerm = this.setNewSearchTerm;
      var onTableHeaderClick = this.tableHeaderOnClick;

      return (
        <div id="active-tasks-page" className="scrollable">
          <div className="inner">
            <ActiveTasksFilterTabs
              searchTerm={searchTerm}
              selectedRadio={selectedRadio}
              onSearch={setSearchTerm}
              onRadioClick={this.switchTab}/>
            <ActiveTaskTable
              collection={collection}
              searchTerm={searchTerm}
              selectedRadio={selectedRadio}
              onTableHeaderClick={onTableHeaderClick}
              sortByHeader={sortByHeader}
              headerIsAscending={headerIsAscending} />
          </div>
        </div>
      );
    }
  });

  var ActiveTasksFilterTabs = React.createClass({
    getDefaultProps: function () {
      return {
        radioNames : [
          'All Tasks',
          'Replication',
          'Database Compaction',
          'Indexer',
          'View Compaction'
        ]
      };
    },

    checked: function (radioName) {
      return this.props.selectedRadio === radioName;
    },

    onRadioClick: function (e) {
      var radioName = e.target.value;
      this.props.onRadioClick(radioName);
    },

    createFilterTabs: function () {
      return (
        this.props.radioNames.map(function (radioName) {
          var checked = this.checked(radioName);
          var id = radioName.replace(' ', '-');
          var radioClassName = "radio-" + id;
          var radioClick = this.onRadioClick;
          var checkedClassName = checked ? 'active-tasks-checked' : '';

          return (
            <li className={"active-tasks-one-checkbox " + checkedClassName} key={radioName + "li"}>
              <input
                  className="toggle-filter-tab"
                  data-bypass="true"
                  id={id}
                  type="radio"
                  key ={radioName}
                  name="radio-button-active-task-filter-tray"
                  value={radioName}
                  checked={checked}
                  onChange={radioClick} />
              <label htmlFor={id} className="active-tasks-checkbox-label">
              {radioName}
              </label>
            </li>
          );
        }.bind(this))
      );
    },

    searchTermChange: function (e) {
      var searchTerm = e.target.value;
      this.props.onSearch(searchTerm);
    },

    render: function () {
      var filterTabs = this.createFilterTabs();
      return (
        <ul className="nav nav-tabs" id="active-tasks-filter-tabs">
          {filterTabs}
          <li>
            <input
              id="active-tasks-search-box"
              className="searchbox"
              type="text"
              name="search"
              placeholder="Search for databases..."
              value={this.props.searchTerm}
              onChange={this.searchTermChange} />
          </li>
        </ul>);
    }
  });

  var ActiveTaskTable = React.createClass({
    render: function () {
      var collection = this.props.collection;
      var selectedRadio = this.props.selectedRadio;
      var searchTerm = this.props.searchTerm;
      var sortByHeader = this.props.sortByHeader;
      var onTableHeaderClick = this.props.onTableHeaderClick;
      var headerIsAscending = this.props.headerIsAscending;

      return (
        <div id="dashboard-lower-content">
          <table id="active-tasks-table" className="table table-bordered table-striped active-tasks">
            <ActiveTasksTableHeader
              onTableHeaderClick={onTableHeaderClick}
              sortByHeader={sortByHeader}
              headerIsAscending={headerIsAscending}/>
            <ActiveTasksTableBody
              collection={collection}
              selectedRadio={selectedRadio}
              searchTerm={searchTerm}/>
          </table>
        </div>
      );
    }
  });

  var ActiveTasksTableHeader = React.createClass({
    getDefaultProps: function () {
      return {
        headerNames : [
          ['type', 'Type'],
          ['database', 'Database'],
          ['started-on', 'Started on'],
          ['updated-on', 'Updated on'],
          ['pid', 'PID'],
          ['progress', 'Status']
        ]
      };
    },

    createTableHeadingFields: function () {
      var onTableHeaderClick = this.props.onTableHeaderClick;
      var sortByHeader = this.props.sortByHeader;
      var headerIsAscending = this.props.headerIsAscending;
      return this.props.headerNames.map(function (header) {
        return <TableHeader
          headerName={header[0]}
          displayName={header[1]}
          key={header[0]}
          onTableHeaderClick={onTableHeaderClick}
          sortByHeader={sortByHeader}
          headerIsAscending={headerIsAscending} />;
      });
    },

    render: function () {
      return (
        <thead>
          <tr>{this.createTableHeadingFields()}</tr>
        </thead>
      );
    }
  });

  var TableHeader = React.createClass({
    arrow: function () {
      var sortBy = this.props.sortByHeader;
      var currentName = this.props.headerName;
      var headerIsAscending = this.props.headerIsAscending;
      var arrow = headerIsAscending ? 'icon icon-caret-up' : 'icon icon-caret-down';

      if (sortBy === currentName) {
        return <i className={arrow}></i>;
      }
    },

    onTableHeaderClick: function (e) {
      var headerSelected = e.target.value;
      this.props.onTableHeaderClick(headerSelected);
    },

    render: function () {
      var arrow = this.arrow();
      var th_class = 'header-field ' + this.props.headerName;

      return (
        <input
          type="radio"
          name="header-field"
          id={this.props.headerName}
          value={this.props.headerName}
          className="header-field radio"
          onChange={this.onTableHeaderClick}>
          <td className={th_class + " tableheader"} value={this.props.headerName}>
            <label
              className="header-field label-text active-tasks-header noselect"
              htmlFor={this.props.headerName}>
              {this.props.displayName} {arrow}
            </label>
          </td>
        </input>
      );
    }
  });

  var ActiveTasksTableBody = React.createClass({

    getStoreState: function () {
      return {
        filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
      };
    },

    getInitialState: function () {
      return this.getStoreState();
    },

    componentWillReceiveProps: function (nextProps) {
      this.setState({
        filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
      });
    },

    createRows: function () {
      var isThereASearchTerm = this.props.searchTerm.trim() === "";

      if (this.state.filteredTable.length === 0) {
        return isThereASearchTerm ? this.noActiveTasks() : this.noActiveTasksMatchFilter();
      }

      return _.map(this.state.filteredTable, function (item, key) {
        return <ActiveTaskTableBodyContents key={key} item={item} />;
      });
    },

    noActiveTasks: function () {
      var type = this.props.selectedRadio;
      if (type === "All Tasks") {
        type = "";
      }

      return (
        <tr className="no-matching-database-on-search">
          <td  colSpan="6">No active {type} tasks.</td>
        </tr>
      );
    },

    noActiveTasksMatchFilter: function () {
      var type = this.props.selectedRadio;
      if (type === "All Tasks") {
        type = "";
      }

      return (
        <tr className="no-matching-database-on-search">
          <td colSpan="6">No active {type} tasks match with filter: "{this.props.searchTerm}"</td>
        </tr>
      );
    },

    render: function () {
      return (
        <tbody className="js-tasks-go-here">
        {this.createRows()}
        </tbody>
      );
    }
  });

  var ActiveTaskTableBodyContents = React.createClass({
    getInfo: function (item) {
      return {
        type : item.type,
        objectField: activeTasksHelpers.getDatabaseFieldMessage(item),
        started_on: activeTasksHelpers.getTimeInfo(item.started_on),
        updated_on: activeTasksHelpers.getTimeInfo(item.updated_on),
        pid: item.pid.replace(/[<>]/g, ''),
        progress: activeTasksHelpers.getProgressMessage(item),
      };
    },

    multilineMessage: function (messageArray, optionalClassName) {

      if (!optionalClassName) {
        optionalClassName = '';
      }
      var cssClasses = 'multiline-active-tasks-message ' + optionalClassName;

      return messageArray.map(function (msgLine, iterator) {
        return <p key={iterator} className={cssClasses}>{msgLine}</p>;
      });
    },

    render: function () {
      var rowData =  this.getInfo(this.props.item);
      var objectFieldMsg = this.multilineMessage(rowData.objectField, 'to-from-database');
      var startedOnMsg = this.multilineMessage(rowData.started_on, 'time');
      var updatedOnMsg = this.multilineMessage(rowData.updated_on, 'time');
      var progressMsg = this.multilineMessage(rowData.progress);

      return (
        <tr>
          <td>{rowData.type}</td>
          <td>{objectFieldMsg}</td>
          <td>{startedOnMsg}</td>
          <td>{updatedOnMsg}</td>
          <td>{rowData.pid}</td>
          <td>{progressMsg}<ActiveTasksViewSourceSequence item={this.props.item}/></td>
        </tr>
      );
    }
  });

  var ActiveTasksViewSourceSequence = React.createClass({
    onTrayToggle: function (e) {
      e.preventDefault();
      this.refs.view_source_sequence_btn.toggle(function (shown) {
        if (shown) {
          React.findDOMNode(this.refs.view_source_sequence_btn).focus();
        }
      }.bind(this));
    },

    sequences: function (item) {
      if (_.isNumber(item) || _.isString(item)) {
        return <ComponentsReact.ClipboardWithTextField textToCopy={item} uniqueKey={item}/>;
      }

      if (_.isArray(item)) {
        return _.map(item, function (seq, i) {
            return <ComponentsReact.ClipboardWithTextField textToCopy={seq} uniqueKey={i + Math.random(100)} key={i}/>;
          });
      }

      return  <ComponentsReact.ClipboardWithTextField textToCopy="???" uniqueKey='unknownRevision'/>;
    },

    render: function () {

      if (_.has(this.props.item, 'source_seq')) {
        var sequences = this.sequences(this.props.item.source_seq);
        return (
          <div>
            Current source sequence:
            <a href="#"
              className="view-source-sequence-btn"
              onClick={this.onTrayToggle}
              data-bypass="true">
              View
            </a>
            <ComponentsReact.Tray ref="view_source_sequence_btn" className="view-source-sequence-tray">
              <span className="add-on">Source Sequence</span>
              {sequences}
            </ComponentsReact.Tray>
          </div>
        );
      }
      return null;
    }
  });

  var ActiveTasksPollingWidgetController = React.createClass({

    getStoreState: function () {
      return {
        pollingInterval:  activeTasksStore.getPollingInterval(),
        isLoading: activeTasksStore.isLoading()
      };
    },

    getInitialState: function () {
      return this.getStoreState();
    },

    componentDidMount: function () {
      activeTasksStore.on('change', this.onChange, this);
    },

    onChange: function () {
      if (this.isMounted()) {
        this.setState(this.getStoreState());
      }
    },

    pollingIntervalChange: function (event) {
      Actions.changePollingInterval(event.target.value);
    },

    getPluralForLabel: function () {
      return this.state.pollingInterval === "1" ? '' : 's';
    },

    createPollingWidget: function () {
      var pollingInterval = this.state.pollingInterval;
      var s = this.getPluralForLabel();
      var onChangeHandle = this.pollingIntervalChange;

      return (
        <ul className="polling-interval-widget">
          <li className="polling-interval-name">Polling interval
            <label className="polling-interval-time-label" htmlFor="polling-range">
              <span>{pollingInterval}</span> second{s}
            </label>
          </li>
          <li>
            <input
              id="polling-range"
              type="range"
              min="1"
              max="30"
              step="1"
              value={pollingInterval}
              onChange={onChangeHandle}/>
          </li>
        </ul>
      );
    },

    render: function () {
      var pollingWidget = this.createPollingWidget();
      var loadLines = null;

      if (this.state.isLoading || this.state.pollingInterval === "1") {
        // show loading lines constantly if the polling interval is
        // 1 second, so that the lines aren't choppy
        loadLines = <Components.LoadLines />;
      }

      return (
        <div className="active-tasks-loading-lines-container">
          <span className="active-tasks-loading-lines">
            {loadLines}
          </span>
          {pollingWidget}
        </div>
      );
    }
  });

  var activeTasksHelpers = {
    getTimeInfo: function (timeStamp) {
      var timeMessage = [
          app.helpers.formatDate(timeStamp),
          app.helpers.getDateFromNow(timeStamp)
        ];
      return timeMessage;
    },

    getDatabaseFieldMessage: function (item) {
      var type = item.type;
      var databaseFieldMessage = [];

      if (type === 'replication') {
        databaseFieldMessage.push('From: ' + item.source);
        databaseFieldMessage.push('To: ' + item.target);
      } else if (type === 'indexer') {
        databaseFieldMessage.push(item.database);
        databaseFieldMessage.push('(View: ' + item.design_document + ')');
      } else {
        databaseFieldMessage.push(item.database);
      }

      return databaseFieldMessage;
    },

    getProgressMessage: function (item) {
      var progressMessage = [];
      var type = item.type;

      if (_.has(item, 'progress')) {
        progressMessage.push('Progress: ' + item.progress + '%');
      }

      if (type === 'indexer') {
        progressMessage.push(
          'Processed ' + item.changes_done + ' of ' + item.total_changes + ' changes.'
        );
      } else if (type === 'replication') {
        progressMessage.push(item.docs_written + ' docs written.');

        if (_.has(item, 'changes_pending')) {
          progressMessage.push(item.changes_pending + ' pending changes.');
        }
      }

      if (_.has(item, 'changes_done')) {
        progressMessage.push(item.changes_done + ' Changes done.');
      }

      return progressMessage;
    },

    getSourceSequence: function (item) {
      return item.source_seq;
    }

  };

  return {
    ActiveTasksController: ActiveTasksController,
    ActiveTasksFilterTabs: ActiveTasksFilterTabs,

    ActiveTaskTable: ActiveTaskTable,
    ActiveTasksTableHeader: ActiveTasksTableHeader,
    TableHeader: TableHeader,
    ActiveTasksTableBody: ActiveTasksTableBody,
    ActiveTaskTableBodyContents: ActiveTaskTableBodyContents,
    ActiveTasksViewSourceSequence: ActiveTasksViewSourceSequence,

    ActiveTasksPollingWidgetController: ActiveTasksPollingWidgetController
  };

});
