var View = require('./view')
var ScrollableTextPanel = require('./scrollable_text_panel')
var log = require('winston')
var tabs = require('./constants')
var StyledString = require('styled_string')
var Chars = require('../chars')
var indent = require('../strutils').indent


function failureDisplay(item){
    var extra = ''
    var stacktrace = item.stacktrace
    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 = stacktrace
    }else{
        if (item.file)
            extra += item.file
        if (item.line)
            extra += ' ' + item.line
    }

    if (item.expected) {
        extra += ' expected ' + item.expected + '\n'
    }

    if (item.actual) {
        extra += ' actual ' + item.actual
    }

    return Chars.cross + ' ' + (item.message || 'failed') +
        (extra ? '\n' + indent(extra) : '')
}


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'))
}

var SplitLogPanel = module.exports = View.extend({
    defaults: {
        visible: false
        , focus: 'top'
    }
    , initialize: function(attrs){
        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 topPanel = this.topPanel = new ScrollableTextPanel({
            line: tabs.TabStartLine + tabs.TabHeight - 1
            , col: 0
            , visible: visible
        })
        var bottomPanel = this.bottomPanel = new ScrollableTextPanel({
            col: 0
            , visible: visible
        })
        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 appview = this.get('appview')
        var runner = this.get('runner')
        var idx = appview.get('currentTab')
        var results = runner.get('results')
        var topLevelError = results ? results.get('topLevelError') : null
        var tests = null
        var out = ''

        if (topLevelError){
            out += "Top Level:\n" + indent(topLevelError) + '\n\n'
        }

        if (results && (tests = results.get('tests'))){
            var total = results.get('total')
            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){
                        out += Chars.success + ' ' + total + ' tests complete.'
                    }else{
                        out += 'Looking good...'
                    }
                }
            }
        }

        return StyledString(out, {foreground: 'cyan'})
    }
    , 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 = message.get('color') || ( type === 'error' ? 'red' : 'yellow' )
            retval = retval.concat(StyledString(text, {foreground: color}))
        })
        return retval
    }
})
