/*
  -- This file is  free  software, which  comes  along  with  SmartEiffel. This
  -- software  is  distributed  in the hope that it will be useful, but WITHOUT
  -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  -- this header is kept unaltered, and a notification of the changes is added.
  -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of
  -- another product.
  --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
  --                       http://SmartEiffel.loria.fr
  --
*/

package fr.loria.smarteiffel;

import java.io.*;
import java.util.*;
import java.lang.*;

/**
 * The SmartEiffelRuntime class implements some external "SmartEiffel"
 * features. This class must be present to execute the Java byte-code
 * generated by command `compile_to_jvm'.
 * Do not forget to add this class in your CLASSPATH system
 * environment variable.
 * You can also move this class file in an appropriate directory.
 *
 * This class is completed by the "SmartEiffelBasic*" classes, each
 * implemented a basic_* section of SmartEiffel.
 */
public final class SmartEiffelRuntime {

    public static void print_run_time_stack () {
	Throwable stack = new Throwable();
	System.err.println("Printing the JVM stack:");
	stack.printStackTrace();
    }

    public static void print_all_run_time_stack () {
	Throwable stack = new Throwable();
	System.err.println("Printing the JVM stack:");
	stack.printStackTrace();
        System.err.println("*** All the stacks should have been printed, but I don't know how to do that.");
        System.err.println("*** If you have a hint, please drop a mail at SmartEiffel@loria.fr");
        System.err.println("*** Thanks!");
    }

    public static void die_with_code (int code) {
	throw( new Error( "die with code: " + code ) );
    }

    public static String NullTerminatedBytesToString (Object bytes) {
	int i = 0;
	byte b [] = ((byte[])bytes);
	while ( b[i] != 0 ) {
	    i++;
	}
	return (new String(b,0,i));
    }

    /**
     * Convert <code>string</code> as a C like null terminated
     * <code>byte[]</code> array.
     */
    public static Object StringToNullTerminatedBytes (String string) {
	byte result [] = new byte[string.length() + 1];
	int i = 0;
	for (; i < string.length() ; i++) {
	    result[i] = (byte)string.charAt(i);
	}
	result[result.length - 1] = 0;
	return result;
    }

    public static int internal_exception_number = 3;

    public static void runtime_error(int line, int column, String path, String type,
				     String message) throws Exception {
	StringBuffer s = new StringBuffer( 128 );

	s.append( "Run-time Eiffel error.\n" );
	if (message != null) {
	    s.append( message )
                .append( "\n" );
	}
	if (type != null) {
	    s.append( "Eiffel type: \"" )
                .append( type )
                .append( "\".\n" );
	}
	if (line != 0) {
	    s.append("Error occurs at line ")
                .append(line)
                .append(" column ")
                .append(column)
                .append(" in \"")
                .append(path)
                .append("\".\n");
	}
	String str = s.toString();
	Exception e = new Exception( str );
	throw( e );
    }

    public static void original_runtime_error(int line,
					      int column,
					      String path,
					      String type,
					      String message) {
	System.err.println("Run-time Eiffel error.");
	if (message != null) {
	    System.err.println(message);
	}
	if (type != null) {
	    System.err.print("Eiffel type: \"");
	    System.err.print(type);
	    System.err.println("\".");
	}
	if (line != 0) {
	    System.err.print("Error occurs at line ");
	    System.err.print(line);
	    System.err.print(" column ");
	    System.err.print(column);
	    System.err.print(" in \"");
	    System.err.print(path);
	    System.err.println("\".");
	}
	print_run_time_stack();
	System.exit(1);
    }

    public static void runtime_error_bad_target(Object target, int line, int column,
						String path, String type,
						String message) {
	if (target == null) {
	    System.err.println("Void (null) target for a call.");
	}
	else {
	    System.err.println("Bad target for a call.");
	    System.err.print("Target is \"");
	    System.err.print(target.toString());
	    System.err.println("\"");
	}
	original_runtime_error(line,column,path,type,message);
    }

    public static int runtime_error_inspect(int inspect_value, int line, int column,
					    String path) {
	System.err.print("Bad inspect value = ");
	System.err.println(inspect_value);
	original_runtime_error(line,column,path,null,
			       "Invalid inspect (nothing selected).");
	return inspect_value;
    }

    public static int runtime_check_loop_variant(int loop_counter, int prev_variant,
						 int next_variant, int line,
						 int column, String path) {
	if (next_variant < 0) {
	    bad_loop_variant(loop_counter,prev_variant,next_variant,line,column,path);
	    return 0;
	}
	else if (loop_counter == 0) {
	    return next_variant;
	}
	else if (next_variant < prev_variant) {
	    return next_variant;
	}
	else {
	    bad_loop_variant(loop_counter,prev_variant,next_variant,line,column,path);
	    return 0;
	}
    }

    private static void bad_loop_variant(int loop_counter,int prev_variant,
					 int next_variant,int line,int column,
					 String path) {
	System.err.print("Loop body counter = ");
	System.err.print(loop_counter);
	System.err.println(" (done)");
	if (loop_counter > 0) {
	    System.err.print("Previous variant = ");
	    System.err.println(prev_variant);
	}
	System.err.print("Current variant = ");
	System.err.print(next_variant);
	if (next_variant < 0) {
	    System.err.println(" (Bad Negative value)");
	}
	else {
	    System.err.println(" (must be less than previous)");
	}
	original_runtime_error(line,column,path,null,"Loop variant violation.");
    }

    public static void se_trace(Object target, int line, int column, String path) {
	se_trace_show(line,column,path);
    }

    public static void se_trace(boolean target,int line,int column,String path) {
	if (target) {
	    System.out.print("Current = true ");
	}
	else {
	    System.out.print("Current = false ");
	}
	se_trace_show(line,column,path);
    }

    public static void se_trace(byte target,int line,int column,String path) {
	System.out.print("Current = ");
	System.out.print(target);
	System.out.print(" ");
	se_trace_show(line,column,path);
    }

    public static void se_trace(int target,int line,int column,String path) {
	System.out.print("Current = ");
	System.out.print(target);
	System.out.print(" ");
	se_trace_show(line,column,path);
    }

    public static void se_trace_show(int line,int column,String path) {
	System.out.print(path);
	System.out.print(" l=");
	System.out.print(line);
	System.out.print(" c=");
	System.out.print(column);
	System.out.println();
	System.out.flush();
    }
}
