/**
 *  Activity Logger
 *  @author   Onur Yıldırım (onur@cutepilot.com)
 *  @license  MIT
 */
module.exports = (function () {
    'use strict';

    var path = require('path');

    var utils = {
        // windows returns 'win32' even on 64 bit but we still check for win64,
        // just in case...
        isWindows: process.platform === 'win32'
            || process.platform === 'win64'
    };

    utils.plural = function (str, count) {
        return count === 1 ? str : str + 's';
    };

    utils.repeat = function (string, times) {
        return new Array(times + 1).join(string);
    };

    utils.indent = function (str, times, indentChar) {
        indentChar = indentChar || ' ';
        var i,
            newArr = [],
            lines = (str || '').split('\n');
        for (i = 0; i < lines.length; i++) {
            newArr.push(utils.repeat(indentChar, times) + lines[i]);
        }
        return newArr.join('\n');
    };

    utils.symbol = function (name) {
        switch (name) {
            case 'dot':
                return utils.isWindows ? '.' : '∙';
            case 'info':
                return utils.isWindows ? 'i' : 'ℹ';
            case 'success':
                return utils.isWindows ? '√' : '✔'; // ✓
            case 'warning':
                return utils.isWindows ? '‼' : '⚠';
            case 'error':
                return utils.isWindows ? '×' : '✖'; // ✕
            case 'disabled':
                return utils.isWindows ? '!' : '•';
            default:
                return '';
        }
    };

    utils.reStack = function (stack, cleanLevel, style) {
        if (!stack) return stack;
        stack = String(stack).split('\n');
        // store the first line (error message)
        var first = stack[0] || '';
        // remove the first from the stack to filter
        stack = stack.slice(1);

        if (cleanLevel > 0) {
            var cleanPath = cleanLevel >= 2
                ? 'node_modules'
                : path.join('node_modules', 'jasmine-core');
            cleanPath = path.sep + cleanPath + path.sep;
            // remove stack lines with jasmine-core path.
            stack = stack.filter(function (stackLine) {
                var pathCheck = stackLine.indexOf(cleanPath) === -1,
                    sepCheck = cleanLevel >= 3
                        ? stackLine.indexOf(path.sep) > -1
                        : true;
                return (pathCheck && sepCheck);
            });
        }

        // make the file paths clickable by removing the wrapping parenths.
        stack = stack.map(function (stackLine) {
            stackLine = stackLine.replace(/\(([^\(]+?)\)/g, '$1'); // '( $1 )'
            if (style) {
                stackLine = stackLine.replace(/([^:\/\\ ]+):(\d+):(\d+)/, function (m, $1, $2, $3) {
                    return style.yellow($1) + ':' + style.white($2) + ':' + style.white($3);
                });
            }
            return stackLine;
        });
        // add back the first line and rest of stack
        if (style) first = style.red(first);
        return first + '\n' + stack.join('\n');
    };

    utils.extend = function (defaults, object) {
        object = object || {};
        var key;
        for (key in defaults) {
            if (defaults.hasOwnProperty(key)
                    && object[key] === undefined) {
                object[key] = defaults[key];
            }
        }
        return object;
    };

    // Normalizes and tries to get a numeric value. This is used for options
    // that support both Boolean and Number values.
    utils.optionBoolToNum = function (value, numTrue, numFalse) {
        if (typeof value === 'boolean') {
            return value ? numTrue : numFalse;
        }
        return typeof value === 'number' ? value : undefined;
    };

    return utils;

})();

@@ -1645,24 +1645,25 @@
  stack;%0A
+%0A
         
 stack = 
@@ -1658,42 +1658,53 @@
     
-stack = String(stack).split('%5Cn');
+// (error) message is the string until we see
 %0A   
@@ -1714,14 +1714,8 @@
   //
- store
  the
@@ -1725,117 +1725,160 @@
 rst 
-line (error message)%0A        var first = stack%5B0%5D %7C%7C '';%0A        // remove the first from the stack to filter
+%22   at ... (path:line:column)%5Cn%22%0A        var message = String(stack).split(/%5B %5Ct%5D+at %5B%5E%5Cn%5D+?:%5Cd+:%5Cd+%5C)?%5Cn/)%5B0%5D %7C%7C '';%0A        // the rest is stack lines
 %0A   
@@ -1894,21 +1894,54 @@
 k = 
+String(
 stack
+)
 .slice(
-1
+message.length).split('%5Cn'
 );%0A%0A
@@ -3088,17 +3088,20 @@
 the 
-first lin
+error messag
 e an
@@ -3135,21 +3135,23 @@
 (style) 
-first
+message
  = style
@@ -3155,21 +3155,23 @@
 yle.red(
-first
+message
 );%0A     
@@ -3184,20 +3184,15 @@
 urn 
-first + '%5Cn'
+message
  + s

revise utils.reStack() method