/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

var htrace = htrace || {};
htrace.SearchView = Backbone.View.extend({
  initialize : function() {
    this.predicateViews = [];
    this.highestPredicateIndex = 0;
    this.searchInProgress = false;
    this.searchResults = new htrace.SearchResults();
    this.resultsView = new htrace.SearchResultsView({
        searchResults: this.searchResults,
        el: "#resultsView"
    });
  },

  events: {
    "click #searchButton": "searchHandler",
    "click #clearButton": "clearHandler",
    "click .add-field": "dropdownHandler",
    "blur #begin": "blurBeginHandler",
    "blur #end": "blurEndHandler",
    "click #zoomButton": "zoomHandler"
  },

  searchHandler: function(e){
    e.preventDefault();

    this.doSearch(e.ctrlKey);
  },

  clearHandler: function(e){
    e.preventDefault();

    this.resultsView.clearHandler(true);
  },

  doSearch: function(showDebug){
    if (this.searchInProgress) {
      console.log("Can't start a new search while another one is in " +
          "progress.");
      return false;
    }

    // Check if there are no search criteria.
    if (this.predicateViews.length == 0) {
      htrace.showModalWarning("No Search Criteria Specified",
        "You have not specified any search criteria.  " +
        "Use the 'Add Predicate' button to specify what to search for.");
      return false;
    }

    // Build the predicate array.
    predicates = []
    var predicateViewsLen = this.predicateViews.length;
    for (var i = 0; i < predicateViewsLen; i++) {
      var predicateView = this.predicateViews[i];
      try {
        predicates.push(predicateView.getPredicate());
      } catch(err) {
        htrace.showModalWarning("Search Field Validation Error",
          "Invalid search string for the '" + predicateView.ptype.name +
          "' field.<p/>" + err);
        return false;
      }
    }
    var lim = Math.min(parseInt($("#search-lim").val()) || 20, 200);
    $("#search-lim").val(lim.toString());
    var queryJson = {
      pred: predicates,
      lim: lim
    };
    // If there are existing search results, we want results which "come after"
    // those.  So pass the last span we saw as a continuation token.
    if (this.searchResults.size() > 0) {
      queryJson.prev =
          this.searchResults.at(this.searchResults.size() - 1).unparse();
    }
    $("body").css("cursor", "progress");
    var searchView = this;
    var queryResults = new htrace.QueryResults({queryJson: queryJson});
    console.log("Starting span query " + queryResults.url());
    this.searchInProgress = true;
    queryResults.fetch({
      success: function(model, response, options){
        $("body").css("cursor", "default");
        var firstResults = (searchView.searchResults.size() === 0);
        console.log("Success on span query " + queryResults.url() + ": got " +
            queryResults.size() + " result(s).  firstResults=" + firstResults);
        searchView.searchResults.add(queryResults.models);
        if (firstResults) {
          // After the initial search, zoom to fit everything.
          // On subsequent searches, we leave the viewport alone.
          searchView.resultsView.zoomHandler();
        }
        searchView.searchInProgress = false;
        if (showDebug) {
          htrace.showModalWarning("Search Debug",
            "This is the search debug box, accessible by holding down the " +
            "control key while clicking the search button.<p/>" +
            "<h3>Query JSON</h3><pre>" + queryResults.prettyQueryString() +
            "</pre><p/><h3>Response JSON</h3><pre>" +
            JSON.stringify(queryResults, null, 2) + "</pre><p/>");
        } else if (queryResults.size() == 0) {
          if (firstResults) {
            htrace.showModalWarning("No Results Found",
              "No results were found for your query.<p/>");
          } else {
            htrace.showModalWarning("No Additional Results Found",
              "No additional results were found for your query.<p/>");
          }
        }
        searchView.resultsView.render();
      },
      error: function(model, response, options){
        $("body").css("cursor", "default");
        searchView.searchResults.reset();
        var err = "Error " + JSON.stringify(response, null, 2) +
          " on span query " + queryResults.url();
        console.log(err);
        alert(err);
        searchView.searchInProgress = false;
      }
    });
    return false;
  },

  dropdownHandler: function(e){
    e.preventDefault();
    var text = $(e.target).text();
    var ptype = htrace.parsePType(text);
    if (!ptype) {
      alert("Unable to parse predicate type '" + text + "'");
      return false;
    }
    var index = this.highestPredicateIndex;
    this.highestPredicateIndex++;
    var el = "pred" + index;
    $("#predicates").append('<div id="' + el + '"/></div>');
    predicateView = new htrace.PredicateView({
      el: "#" + el,
      index: index,
      ptype: ptype,
      searchView: this
    });
    this.predicateViews.push(predicateView);
    predicateView.render();
    return true;
  },

  blurBeginHandler: function(e) {
    return this.resultsView.handleBeginOrEndChange(e, "begin");
  },

  blurEndHandler: function(e) {
    return this.resultsView.handleBeginOrEndChange(e, "end");
  },

  zoomHandler: function(e) {
    e.preventDefault();
    this.resultsView.zoomHandler();
  },

  removePredicateView: function(predicateView) {
    this.predicateViews = _.without(this.predicateViews, predicateView);
  },

  render: function() {
    this.$el.html(_.template($("#search-view-template").html())
      ({ model : this.model }))
    this.resultsView.render();
    console.log("SearchView#render");
    return this;
  },

  close: function() {
    console.log("SearchView#close")
    while (this.predicateViews.length > 0) {
      this.predicateViews[0].remove();
    }
    this.resultsView.remove();
    this.resultsView = null;
    this.undelegateEvents();
  }
});
