/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.io.Serializable;

/**
 * This class represents an element on the script execution stack.
 * @see RhinoException#getScriptStack()
 * @author Hannes Wallnoefer
 * @since 1.7R3
 */
public final class ScriptStackElement implements Serializable {

    static final long serialVersionUID = -6416688260860477449L;
    
    public final String fileName;
    public final String functionName;
    public final int lineNumber;

    public ScriptStackElement(String fileName, String functionName, int lineNumber) {
        this.fileName = fileName;
        this.functionName = functionName;
        this.lineNumber = lineNumber;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        renderMozillaStyle(sb);
        return sb.toString();
    }

    /**
     * Render stack element in Java-inspired style:
     * <code>    at fileName:lineNumber (functionName)</code>
     * @param sb the StringBuilder to append to
     */
    public void renderJavaStyle(StringBuilder sb) {
        sb.append("\tat ").append(fileName);
        if (lineNumber > -1) {
            sb.append(':').append(lineNumber);
        }
        if (functionName != null) {
            sb.append(" (").append(functionName).append(')');
        }
    }

    /**
     * Render stack element in Mozilla/Firefox style:
     * <code>functionName()@fileName:lineNumber</code>
     * @param sb the StringBuilder to append to
     */
    public void renderMozillaStyle(StringBuilder sb) {
        if (functionName != null) {
            sb.append(functionName).append("()");
        }
        sb.append('@').append(fileName);
        if (lineNumber > -1) {
            sb.append(':').append(lineNumber);
        }
    }

    /**
     * Render stack element in V8 style:
     * <code>    at functionName (fileName:lineNumber:columnNumber)</code>
     * or:
     * <code>    at fileName:lineNumber:columnNumber</code>
     * @param sb the StringBuilder to append to
     */
    public void renderV8Style(StringBuilder sb) {
        sb.append("    at ");

        if ((functionName == null) || "anonymous".equals(functionName) || "undefined".equals(functionName)) {
            // Anonymous functions in V8 don't have names in the stack trace
            appendV8Location(sb);

        } else {
            sb.append(functionName).append(" (");
            appendV8Location(sb);
            sb.append(')');
        }
    }

    private void appendV8Location(StringBuilder sb)
    {
        sb.append(fileName);
        if (lineNumber > -1) {
            sb.append(':').append(lineNumber);
        }
    }
}

@@ -555,13 +555,9 @@
 9L;%0A
-    
 %0A
+
     
@@ -1141,32 +1141,39 @@
 ionName)%3C/code%3E%0A
+     *%0A
      * @param sb
@@ -1621,32 +1621,39 @@
 neNumber%3C/code%3E%0A
+     *%0A
      * @param sb
@@ -2170,24 +2170,31 @@
 mber%3C/code%3E%0A
+     *%0A
      * @para
@@ -2403,16 +2403,29 @@
 defined%22
+%0A            
 .equals(
@@ -2750,20 +2750,16 @@
 lder sb)
-%0A   
  %7B%0A     
@@ -2772,32 +2772,44 @@
 append(fileName)
+.append(':')
 ;%0A        if (li
@@ -2794,35 +2794,41 @@
 d(':');%0A        
-if 
+sb.append
 (lineNumber %3E -1
@@ -2831,68 +2831,40 @@
 %3E -1
-) %7B%0A            sb.append(':').append(lineNumber);%0A        %7D
+ ? lineNumber : 0).append(%22:0%22);
 %0A   

Put a column number in V8 stack traces.