/**
 * Copyright (c) 2017 Google Inc. All Rights Reserved.
 *
 * 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.
 */

(function($, moment) {

/**
 * Display the log links in a modal window.
 * @param linkList A list of [name, url] tuples representing log links.
 */
function showLinks(container, linkList) {
  if (!linkList || linkList.length == 0) return;

  var logCollection = $('<ul class="collection"></ul>');
  var entries = linkList.reduce(function(acc, entry) {
    if (!entry || entry.length == 0) return acc;
    var link = '<a href="' + entry[1] + '"';
    link += 'class="collection-item">' + entry[0] + '</li>';
    return acc + link;
  }, '');
  logCollection.html(entries);

  if (container.find('#info-modal').length == 0) {
    var modal =
        $('<div id="info-modal" class="modal modal-fixed-footer"></div>');
    var content = $('<div class="modal-content"></div>');
    content.append('<h4>Links</h4>');
    content.append('<div class="info-container"></div>');
    content.appendTo(modal);
    var footer = $('<div class="modal-footer"></div>');
    footer.append('<a class="btn-flat modal-close">Close</a></div>');
    footer.appendTo(modal);
    modal.appendTo(container);
  }
  var infoContainer = $('#info-modal>.modal-content>.info-container');
  infoContainer.empty();
  logCollection.appendTo(infoContainer);
  $('#info-modal').modal({dismissible: true});
  $('#info-modal').modal('open');
}

/**
 * Get the nickname for a test case result.
 *
 * Removes the result prefix and suffix, extracting only the result name.
 *
 * @param testCaseResult The string name of a VtsReportMessage.TestCaseResult.
 * @returns the string nickname of the result.
 */
function getNickname(testCaseResult) {
  return testCaseResult.replace('TEST_CASE_RESULT_', '')
      .replace('_RESULT', '')
      .trim()
      .toLowerCase();
}

/**
 * Get the badge color from ratio value.
 *
 * @param the percentage value.
 * @returns the string of color for the badge.
 */
function getBadgeColor(ratio) {
  var color = "orange";
  if (ratio <= 20) {
    color = "red";
  } else if (ratio >= 70) {
    color = "green";
  }
  return color;
}

/**
 * Get the rounded value.
 *
 * @param the percentage value.
 * @returns the rounded value from percentage value.
 */
function getRoundValue(ratio) {
    return Math.round(ratio * 1000) / 10;
}

/**
 * Display test data in the body beneath a test run's metadata.
 * @param container The jquery object in which to insert the test metadata.
 * @param data The json object containing the columns to display.
 * @param lineHeight The height of each list element.
 */
function displayTestDetails(container, data, lineHeight) {
  var nCol = data.length;
  var width = 's' + (12 / nCol);
  test = container;
  var maxLines = 0;
  data.forEach(function(column, index) {
    if (column.data == undefined || column.name == undefined) {
      return;
    }
    var classes = 'col test-col grey lighten-5 ' + width;
    if (index != nCol - 1) {
      classes += ' bordered';
    }
    if (index == 0) {
      classes += ' left-most';
    }
    if (index == nCol - 1) {
      classes += ' right-most';
    }
    var colContainer = $('<div class="' + classes + '"></div>');
    var col = $('<div class="test-case-container"></div>');
    colContainer.appendTo(container);
    var count = column.data.length;
    var head = $('<h5 class="test-result-label white"></h5>')
                   .text(getNickname(column.name))
                   .appendTo(colContainer)
                   .css('text-transform', 'capitalize');
    $('<div class="indicator right center"></div>')
        .text(count)
        .addClass(column.name)
        .appendTo(head);
    col.appendTo(colContainer);
    var list = $('<ul></ul>').appendTo(col);
    column.data.forEach(function(testCase) {
      $('<li></li>')
          .text(testCase)
          .addClass('test-case')
          .css('font-size', lineHeight - 2)
          .css('line-height', lineHeight + 'px')
          .appendTo(list);
    });
    if (count > maxLines) {
      maxLines = count;
    }
  });
  var containers = container.find('.test-case-container');
  containers.height(maxLines * lineHeight);
}

/**
 * Click handler for displaying test run details.
 * @param e The click event.
 */
function testRunClick(e) {
  var header = $(this);
  var icon = header.find('.material-icons.expand-arrow');
  var container = header.parent().find('.test-results');
  var test = header.attr('test');
  var time = header.attr('time');
  var url = '/api/test_run?test=' + test + '&timestamp=' + time;
  if (header.parent().hasClass('active')) {
    header.parent().removeClass('active');
    header.removeClass('active');
    icon.removeClass('rotate');
    header.siblings('.collapsible-body').stop(true, false).slideUp({
      duration: 100,
      easing: 'easeOutQuart',
      queue: false,
      complete: function() {
        header.css('height', '');
      }
    });
  } else {
    container.empty();
    header.parent().addClass('active');
    header.addClass('active');
    header.addClass('disabled');
    icon.addClass('rotate');
    $.get(url)
        .done(function(data) {
          displayTestDetails(container, data, 16);
          header.siblings('.collapsible-body').stop(true, false).slideDown({
            duration: 100,
            easing: 'easeOutQuart',
            queue: false,
            complete: function() {
              header.css('height', '');
            }
          });
        })
        .fail(function() {
          icon.removeClass('rotate');
        })
        .always(function() {
          header.removeClass('disabled');
        });
  }
}

/**
 * Append a clickable indicator link to the container.
 * @param container The jquery object to append the indicator to.
 * @param content The text to display in the indicator.
 * @param classes Additional space-delimited classes to add to the indicator.
 * @param click The click handler to assign to the indicator.
 * @returns The jquery object for the indicator.
 */
function createClickableIndicator(container, content, classes, click) {
  var link = $('<span></span>');
  link.addClass('indicator badge padded hoverable waves-effect');
  link.addClass(classes);
  link.css('color', 'white');
  link.css('margin-left', '1px');
  link.append(content);
  link.appendTo(container);
  link.click(click);
  return link;
}

function displayTestMetadata(container, metadataList, showTestNames = false) {
  var popout = $('<ul></ul>');
  popout.attr('data-collapsible', 'expandable');
  popout.addClass('collapsible popout test-runs');
  popout.appendTo(container);
  popout.unbind();
  metadataList.forEach(function(metadata) {
    var li = $('<li class="test-run-container"></li>');
    li.appendTo(popout);
    var div = $('<div></div>');
    var test = metadata.testRun.testName;
    var startTime = metadata.testRun.startTimestamp;
    var endTime = metadata.testRun.endTimestamp;
    div.attr('test', test);
    div.attr('time', startTime);
    div.addClass('collapsible-header test-run');
    div.appendTo(li);
    div.unbind().click(testRunClick);
    var span = $('<span></span>');
    span.addClass('test-run-metadata');
    span.appendTo(div);
    span.click(function() {
      return false;
    });
    if (showTestNames) {
      $('<span class="test-run-label"></span>').text(test).appendTo(span);
      span.append('<br>');
    }
    if (metadata.deviceInfo) {
      $('<b></b>').text(metadata.deviceInfo).appendTo(span);
      span.append('<br>');
    }
    if (metadata.abiInfo) {
      $('<b></b>').text('ABI: ').appendTo(span)
      span.append(metadata.abiInfo).append('<br>');
    }
    $('<b></b>').text('VTS Build: ').appendTo(span)
    span.append(metadata.testRun.testBuildId).append('<br>');
    $('<b></b>').text('Host: ').appendTo(span)
    span.append(metadata.testRun.hostName).append('<br>');
    var timeString =
        (moment().renderTime(startTime, false) + ' - ' +
         moment().renderTime(endTime, true) + ' (' +
         moment().renderDuration(endTime - startTime) + ')');
    span.append(timeString);
    var indicator = $('<span></span>');
    var color = metadata.testRun.failCount > 0 ? 'red' : 'green';
    indicator.addClass('indicator badge ' + color);
    indicator.css('color', 'white');
    indicator.append(
        metadata.testRun.passCount + '/' +
        (metadata.testRun.passCount + metadata.testRun.failCount));
    indicator.appendTo(div);
    if (metadata.testRun.coveredLineCount != undefined &&
        metadata.testRun.totalLineCount != undefined) {
      var url = ('/show_coverage?testName=' + test + '&startTime=' + startTime);
      var covered = metadata.testRun.coveredLineCount;
      var total = metadata.testRun.totalLineCount;
      var covPct = getRoundValue(covered / total);
      var color = getBadgeColor(covPct);
      var coverage =
          ('Coverage: ' + covered + '/' + total + ' (' + covPct + '%)');
      createClickableIndicator(div, coverage, color, function(evt) {
        window.location.href = url;
        return false;
      });
    }
    if (metadata.testRun.coveredApiCount != undefined &&
        metadata.testRun.totalApiCount != undefined) {
      var covered = metadata.testRun.coveredApiCount;
      var total = metadata.testRun.totalApiCount;
      var covPct = getRoundValue(covered / total);
      var color = getBadgeColor(covPct);
      var apiCoverage = ('API Coverage: ' + covered + '/' + total + ' (' + covPct + '%)');
      createClickableIndicator(div, apiCoverage, color, function(evt) {
        $('#apiCoverageModal')
            .data('urlSafeKeyList', metadata.testRun.apiCoverageKeyList);
        $('#apiCoverageModal').modal('open');
        return false;
      });
    }
    if (metadata.testRun.logLinks != undefined) {
      createClickableIndicator(div, 'Links', 'grey lighten-1', function() {
        showLinks(popout, metadata.testRun.logLinks);
        return false;
      });
    }
    if ($('#coverageModalGraph').length) {
      createClickableIndicator(div, 'Graph', 'grey lighten-1', function(evt) {
        $('#coverageModalGraph').data('testname', test);
        $('#coverageModalGraph').modal('open');
        $(evt.target).removeClass('grey');
        $(evt.target).addClass('blue');
        return false;
      });
    }

    var expand = $('<i></i>');
    expand.addClass('material-icons expand-arrow')
    expand.text('expand_more');
    expand.appendTo(div);
    var body = $('<div></div>')
                   .addClass('collapsible-body test-results row')
                   .appendTo(li);
    if (metadata.testDetails != undefined) {
      expand.addClass('rotate');
      li.addClass('active');
      div.addClass('active');
      displayTestDetails(body, metadata.testDetails, 16);
      div.siblings('.collapsible-body').stop(true, false).slideDown({
        duration: 0,
        queue: false,
        complete: function() {
          div.css('height', '');
        }
      });
    }
  });
}

/**
 * Display test metadata in a vertical popout.
 * @param container The jquery object in which to insert the test metadata.
 * @param metadataList The list of metadata objects to render on the display.
 * @param showTestNames True to label each entry with the test module name.
 */
$.fn.showTests = function(metadataList, showTestNames = false) {
  displayTestMetadata($(this), metadataList, showTestNames);
}
})(jQuery, moment);