package com.xruby.runtime.builtin;

import java.math.BigInteger;
import java.util.Random;

import com.xruby.runtime.lang.RubyConstant;
import com.xruby.runtime.lang.RubyException;
import com.xruby.runtime.lang.RubyRuntime;
import com.xruby.runtime.lang.RubyValue;
import com.xruby.runtime.lang.annotation.RubyLevelMethod;
import com.xruby.runtime.lang.annotation.RubyLevelModule;

@RubyLevelModule(name="Kernel")
public class RubyRandom {
	private static long randomSeed;
	private static Random random = new Random();

	private static boolean first = true;
	private static RubyValue saved_seed = new RubyFixnum(0); 
 
	private static RubyValue rand_init(RubyValue vseed) {
		RubyValue seed, old;
		
		seed = vseed.toRubyInteger();
		
		if (seed instanceof RubyFixnum) {
			randomSeed = seed.toInt();
		} else if (seed instanceof RubyBignum) {
			randomSeed = ((RubyBignum)seed).longValue();
		} else {
			throw new RubyException(RubyRuntime.TypeErrorClass, "failed to convert " + vseed.getRubyClass().getName() + " into Integer");
		}
		random.setSeed(randomSeed);
		
		first = false;
		old = saved_seed;
		saved_seed = seed;
		return old;
	}

	private static RubyValue random_seed() {
		// TODO: improve the random seed
		// seeds the generator using a combination of the time, the process id, and a sequence number.
		long seed = System.nanoTime();
		return RubyBignum.bignorm(seed);
	}

    @RubyLevelMethod(name="srand")
    public static RubyValue srand(RubyValue receiver) {
        return srand(receiver, random_seed());
    }
    
    @RubyLevelMethod(name="srand")
    public static RubyValue srand(RubyValue receiver, RubyValue arg) {
        return rand_init(arg);
    }
	
	@RubyLevelMethod(name="rand")
	public static RubyValue rand(RubyValue receiver) {
		if (first) {
			rand_init(random_seed());
		}
        return new RubyFloat(random.nextDouble());
    }
	
	@RubyLevelMethod(name="rand")
	public static RubyValue rand(RubyValue receiver, RubyValue arg) {
		long val, max = 0;
		
		if (first) {
			rand_init(random_seed());
		}
		
		if (arg instanceof RubyFloat) {
			RubyFloat vmax = (RubyFloat)arg;
			if (vmax.doubleValue() <= Long.MAX_VALUE && vmax.doubleValue() >= Long.MIN_VALUE) {
				RubyValue tmp = vmax.floor();
				if (tmp instanceof RubyFixnum) {
					max = ((RubyFixnum)tmp).toInt();
				} else if (tmp instanceof RubyBignum) {
					max = ((RubyBignum)tmp).longValue();
				}
			} else {
				if (vmax.doubleValue() < 0) {
					arg = RubyBignum.bignorm((long)-vmax.doubleValue());
				} else {
					arg = RubyBignum.bignorm((long)vmax.doubleValue());
				}
			}
		} else if (arg == RubyConstant.QNIL) {
			max = 0;
		} else if (arg instanceof RubyFixnum) {
			arg = arg.toRubyInteger();
			max = arg.toInt();
		}
		
		if (arg instanceof RubyBignum) {
			byte[] bytes = new byte[((RubyBignum)arg).getInternal().toByteArray().length-1];
			random.nextBytes(bytes);
			return RubyBignum.bignorm(new BigInteger(1, bytes));
		}

		if (max == 0) {
			return new RubyFloat(random.nextDouble());
		}
		
		if (max < 0) {
			max = -max;
		}
	    val = random.nextInt((int)max);
	    if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) {
	    	return new RubyFixnum((int)val);
	    } else {
	    	return RubyBignum.bignorm(val);
	    }
    }
}
@@ -1,8 +1,98 @@
+/**%0A * Copyright 2007 Sishen%0A * Distributed under the GNU General Public License 2.0%0A */%0A%0A
 package 

add copyright for Sishen