text: 'use strict';
  
  var View = require('./view');
  var ScrollableTextPanel = require('./scrollable_text_panel');
  var tabs = require('./constants');
  var styledString = require('styled_string');
  var Chars = require('../../chars');
  var indent = require('../../strutils').indent;
  var Screen = require('./screen');
  
  function failureDisplay(item) {
    var extra = [];
    var stacktrace = item.stack;
    if (stacktrace) {
      var stacklines = stacktrace.split('\n');
      if (stacklines[0] === item.message) {
        stacktrace = stacklines.slice(1).map(function(line) {
          return line.trim();
        }).join('\n');
      }
      extra.push(stacktrace);
    } else {
      if (item.file) {
        extra.push(item.file);
      }
      if (item.line) {
        extra.push(' ' + item.line);
      }
    }
  
    if (item.expected) {
      extra.push(' expected ' + (item.negative ? 'NOT ' : '') + item.expected);
    }
  
    if (item.actual) {
      extra.push(' actual ' + item.actual);
    }
  
    if (item.at) {
      extra.push(' at ' + item.at);
    }
  
    return Chars.cross + ' ' + (item.message || 'failed') +
      (extra ? '\n' + indent(extra.join('\n')) : '');
  }
  
  function failedTestDisplay(test) {
    var failedItems = (test.get('items') || []).filter(function(item) {
      return !item.passed;
    });
    return test.get('name') + '\n' +
      indent(failedItems.map(failureDisplay).join('\n'));
  }
  
  module.exports = View.extend({
    defaults: {
      visible: false,
      focus: 'top'
    },
    initialize: function() {
      if (!this.get('screen')) {
        this.set('screen', new Screen());
      }
      var runner = this.get('runner');
      var results = runner.get('results');
      var messages = runner.get('messages');
      var appview = this.get('appview');
      var visible = this.get('visible');
      var self = this;
      var screen = this.get('screen');
      var topPanel = this.topPanel = new ScrollableTextPanel({
        line: tabs.TabStartLine + tabs.TabHeight - 1,
        col: 0,
        visible: visible,
        screen: screen
      });
      var bottomPanel = this.bottomPanel = new ScrollableTextPanel({
        col: 0,
        visible: visible,
        screen: screen
      });
      this.observe(appview, 'change:cols change:lines', function() {
        self.syncDimensions();
        self.render();
      });
      if (results) {
        this.observe(results, 'change', function() {
          self.syncDimensions();
          self.syncResultsDisplay();
        });
      }
      this.observe(messages, 'reset add remove', function() {
        self.syncDimensions();
        self.syncMessages();
      });
      this.observe(this, 'change:visible', function() {
        var visible = self.get('visible');
        topPanel.set('visible', visible, {silent: true});
        bottomPanel.set('visible', visible, {silent: true});
        self.syncDimensions({silent: true});
        self.render();
      });
      this.syncDimensions({silent: true});
      this.syncResultsDisplay({silent: true});
      this.syncMessages({silent: true});
      this.render();
    },
    toggleFocus: function() {
      var focus = this.get('focus');
      this.set('focus', focus === 'top' ? 'bottom' : 'top');
    },
    resetScrollPositions: function() {
      this.topPanel.set('scrollOffset', 0);
      this.bottomPanel.set('scrollOffset', 0);
    },
    targetPanel: function() {
      var runner = this.get('runner');
      var bottomPanel = this.bottomPanel;
      var topPanel = this.topPanel;
      if (runner.hasMessages() && runner.hasResults()) {
        return (this.get('focus') === 'top') ? topPanel : bottomPanel;
      } else if (runner.hasMessages()) {
        return bottomPanel;
      } else if (runner.hasResults()) {
        return topPanel;
      } else {
        return topPanel;
      }
    },
    scrollUp: function() {
      this.targetPanel().scrollUp();
    },
    scrollDown: function() {
      this.targetPanel().scrollDown();
    },
    pageUp: function() {
      this.targetPanel().pageUp();
    },
    pageDown: function() {
      this.targetPanel().pageDown();
    },
    halfPageUp: function() {
      this.targetPanel().halfPageUp();
    },
    halfPageDown: function() {
      this.targetPanel().halfPageDown();
    },
    syncMessages: function(options) {
      this.bottomPanel.set('text', this.getMessagesText(), options);
    },
    syncResultsDisplay: function(options) {
      this.topPanel.set('text', this.getResultsDisplayText(), options);
    },
    syncDimensions: function(options) {
      var appview = this.get('appview');
      var termCols = appview.get('cols');
      var termLines = appview.get('lines');
      var runner = this.get('runner');
      if (runner.hasMessages() && runner.hasResults()) {
        var midLine = Math.floor((termLines - tabs.LogPanelUnusedLines) / 2);
  
        this.topPanel.set({
          height: midLine,
          width: termCols
        }, options);
        var line = midLine + tabs.TabStartLine + tabs.TabHeight - 1;
        var bottomPanelAttrs = {
          line: line,
          height: termLines - line - 1,
          width: termCols
        };
        this.bottomPanel.set(bottomPanelAttrs, options);
      } else if (runner.hasMessages()) { // only has messages
        this.topPanel.set({
          height: 0,
          width: termCols
        }, options);
        var height = termLines - tabs.LogPanelUnusedLines;
        this.bottomPanel.set({
          line: tabs.TabStartLine + tabs.TabHeight - 1,
          height: height,
          width: termCols
        }, options);
      } else { // only has results
  
        // Hide the bottom panel if there are no messages
        // to be displayed
        var topPanelHeight = termLines - tabs.LogPanelUnusedLines;
        this.topPanel.set({
          height: topPanelHeight,
          width: termCols
        }, options);
        this.bottomPanel.set({
          line: tabs.TabStartLine + tabs.TabHeight + topPanelHeight,
          height: 0,
          width: termCols
        }, options);
      }
    },
    render: function() {
      this.topPanel.render();
      this.bottomPanel.render();
    },
    getResultsDisplayText: function() {
      var runner = this.get('runner');
      var results = runner.get('results');
      var topLevelError = results ? results.get('topLevelError') : null;
      var tests = null;
      var out = '';
      var pendingOut = '';
  
      if (topLevelError) {
        out += 'Top Level:\n' + indent(topLevelError) + '\n\n';
      }
  
      if (results && (tests = results.get('tests'))) {
        var total = results.get('total');
        var pending = results.get('pending');
        var allDone = results.get('all');
        if (!total) {
          out = allDone ? 'No tests were run :(' : 'Please be patient :)';
        } else {
          var failedTests = tests.filter(function(test) {
            return test.get('failed') > 0;
          });
          if (failedTests.length > 0) {
            out += failedTests.map(failedTestDisplay).join('\n');
          } else { // All passed
            if (allDone) {
              var pendingTests = tests.filter(function(test) {
                return test.get('pending') > 0;
              });
              out += Chars.success + ' ' + total + ' tests complete';
              if (pending > 0) {
                out += ' (' + pending + ' pending)';
              }
              out += '.';
              if (pending) {
                pendingOut += '\n\n';
                pendingOut += pendingTests.map(function(test) {
                  return '[PENDING] ' + test.get('name');
                }).join('\n');
              }
            } else {
              out += 'Looking good...';
            }
          }
        }
      }
  
      return styledString(out, {foreground: 'cyan'})
        .append(styledString(pendingOut, {foreground: 'yellow'}));
    },
    getMessagesText: function() {
      var messages = this.get('runner').get('messages');
      var retval = styledString('');
  
      messages.forEach(function(message) {
        var type = message.get('type');
        var text = message.get('text');
  
        var color = 'yellow';
  
        switch (type) {
          case 'warn':
            color = 'cyan';
            break;
          case 'info':
            color = 'green';
            break;
          case 'error':
            color = 'red';
            break;
        }
  
        retval = retval.concat(styledString(text, {foreground: color}));
      });
      return retval;
    }
  });
  