/*---

    iGeo - http://igeo.jp

    Copyright (c) 2002-2012 Satoru Sugihara

    This file is part of iGeo.

    iGeo is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, version 3.

    iGeo 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.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with iGeo.  If not, see <http://www.gnu.org/licenses/>.

---*/


package igeo;

import java.awt.Color;
import java.util.Random;

/**
   A class to provide random number function.   

   @author Satoru Sugihara
   @version 0.7.0.0;
*/
public class IRand{
    static public final long defaultSeed=1;
    
    static protected Random random=null;
    
    static public void init(){
	init(defaultSeed);
    }
    static public void init(long seed){
	random = new Random(seed);
    }
    
    static public void initByTime(){
	random = new Random(System.currentTimeMillis());
    }
    
    static public double get(){
	if(random==null){ init(); }
	return random.nextDouble();
    }
    
    static public double getDouble(double min, double max){ return get(min,max); }
    static public double getDouble(double max){ return get(max); }
    static public double getDouble(){ return get(); }
    
    static public double get(double min, double max){
	if(random==null){ init(); }
	return random.nextDouble()*(max-min)+min;
    }
    
    static public double get(double max){
	if(random==null){ init(); }
	return random.nextDouble()*max;
    }

    static public float getf(){
	if(random==null){ init(); }
	return random.nextFloat();
    }
    static public float getf(float min, float max){
	if(random==null){ init(); }
	return random.nextFloat()*(max-min)+min;
    }
    static public float getf(float max){
	if(random==null){ init(); }
	return random.nextFloat()*max;
    }
    
    static public float getFloat(){ return getf(); }
    static public float getFloat(float min, float max){ return getf(min,max); }
    static public float getFloat(float max){ return getf(max); }
    
    
    static public int geti(int min, int max){
	int r = (int)get(min, max+1);
	if(r>max){ r=max; }
	return r;
    }
    static public int geti(int max){
	int r = (int)get(0, max+1);
	if(r>max){ r=max; }
	return r;
    }
    /** returns 0 or 1 */
    static public int geti(){
	int r = (int)get(0, 2);
	if(r>1){ r=1; }
	return r;
    }
    static public int getInt(int min, int max){ return geti(min,max); }
    static public int getInt(int max){ return geti(max); }
    static public int getInt(){ return geti(); }
    static public int getInteger(int min, int max){ return geti(min,max); }
    static public int getInteger(int max){ return geti(max); }
    static public int getInteger(){ return geti(); }
    
    
    static public IVec pt(IVec min, IVec max){
	return new IVec(get(min.x,max.x),get(min.y,max.y),get(min.z,max.z));
    }
    static public IVec point(IVec min, IVec max){ return pt(min,max); }
    static public IVec getPoint(IVec min, IVec max){ return pt(min,max); }
    
    static public IVec pt(IVec max){
	return new IVec(get(max.x),get(max.y),get(max.z));
    }
    static public IVec point(IVec max){ return pt(max); }
    static public IVec getPoint(IVec max){ return pt(max); }
    
    static public IVec pt(double minx, double miny, double minz,
			  double maxx, double maxy, double maxz){
	return new IVec(get(minx,maxx),get(miny,maxy),get(minz,maxz));
    }
    static public IVec pt(double maxx, double maxy, double maxz){
	return new IVec(get(maxx),get(maxy),get(maxz));
    }
    static public IVec pt(double min, double max){
	return new IVec(get(min,max),get(min,max),get(min,max));
    }
    static public IVec pt(double max){
	return new IVec(get(0,max),get(0,max),get(0,max));
    }
    static public IVec pt(){ return new IVec(get(),get(),get()); }
    
    static public IVec point(double minx, double miny, double minz,
			     double maxx, double maxy, double maxz){
	return pt(minx,miny,minz,maxx,maxy,maxz);
    }
    static public IVec point(double maxx, double maxy, double maxz){
	return pt(maxx,maxy,maxz);
    }
    static public IVec point(double min, double max){ return pt(min,max); }
    static public IVec point(double max){ return pt(max); }
    static public IVec point(){ return pt(); }
    
    static public IVec getPoint(double minx, double miny, double minz,
				double maxx, double maxy, double maxz){
	return pt(minx,miny,minz,maxx,maxy,maxz);
    }
    static public IVec getPoint(double maxx, double maxy, double maxz){
	return pt(maxx,maxy,maxz);
    }
    static public IVec getPoint(double min, double max){ return pt(min,max); }
    static public IVec getPoint(double max){ return pt(max); }
    static public IVec getPoint(){ return pt(); }
    
    
    /**
       random point on XY plane
    */
    static public IVec pt2(double minx, double miny, double maxx, double maxy){
	return new IVec(get(minx,maxx),get(miny,maxy),0);
    }
    static public IVec pt2(double min, double max){
	return new IVec(get(min,max),get(min,max),0);
    }
    static public IVec pt2(double max){ return new IVec(get(0,max),get(0,max),0); }
    static public IVec pt2(){ return new IVec(get(),get(),0); }
    
    static public IVec point2(double minx, double miny, double maxx, double maxy){
	return pt2(minx,miny,maxx,maxy);
    }
    static public IVec point2(double min, double max){ return pt2(min,max); }
    static public IVec point2(double max){ return pt2(max); }
    static public IVec point2(){ return pt2(); }    
    
    static public IVec getPoint2(double minx, double miny, double maxx, double maxy){
	return pt2(minx,miny,maxx,maxy);
    }
    static public IVec getPoint2(double min, double max){ return pt2(min,max); }
    static public IVec getPoint2(double max){ return pt2(max); }
    static public IVec getPoint2(){ return pt2(); }    
    
    
    /**
       random direction in 3D
    */
    static public IVec dir(){ return dir(1.0); }
    static public IVec dir(double length){
	IVec vec = pt(-1,1);
	double l = vec.len();
	while(l < IConfig.tolerance){ vec = pt(-1,1); l = vec.len(); }
	return vec.mul(length/l);
    }
    static public IVec dir(IVecI perpendicularAxis){
	return dir(perpendicularAxis, 1.0);
    }
    static public IVec dir(IVecI perpendicularAxis, double length){
	IVec vec = null;
	if(!IVec.zaxis.isParallel(perpendicularAxis))
	    vec = IVec.zaxis.cross(perpendicularAxis);
	else vec = IVec.xaxis.cross(perpendicularAxis);
	return vec.rot(perpendicularAxis, get(Math.PI*2)).len(length);
    }
    
    static public IVec direction(){ return dir(); }
    static public IVec direction(double length){ return dir(length); }
    static public IVec direction(IVecI perpendicularAxis){
	return dir(perpendicularAxis);
    }
    static public IVec direction(IVecI perpendicularAxis, double length){
	return dir(perpendicularAxis,length);
    }
    
    static public IVec getDirection(){ return dir(); }
    static public IVec getDirection(double length){ return dir(length); }
    static public IVec getDirection(IVecI perpendicularAxis){
	return dir(perpendicularAxis);
    }
    static public IVec getDirection(IVecI perpendicularAxis, double length){
	return dir(perpendicularAxis,length);
    }
    
    
    /**
       random direction on XY plane
    */
    static public IVec dir2(){ return dir2(1.0); }
    static public IVec dir2(double length){
	double a = get(Math.PI*2);
	return new IVec(length*Math.cos(a), length*Math.sin(a), 0);
    }    
    static public IVec direction2(){ return dir2(); }
    static public IVec direction2(double length){ return dir2(length); }
    static public IVec getDirection2(){ return dir2(); }
    static public IVec getDirection2(double length){ return dir2(length); }
    
    
    static public boolean getPercent(double percent){
	return percent(percent);
    }
    static public boolean percent(double percent){
	return get()<(percent/100);
    }
    static public boolean pct(double percent){return percent(percent); }
    
    
    //static public Color color(){ return getColor(); } // PDE doesn't allow this name
    static public Color getColor(){ return clr(); }
    static public Color clr(){
	return new Color(getInt(0,255),getInt(0,255),getInt(0,255));
    }
    
    static protected int limit255(int value){
	if(value<0) return 0;
	if(value>255) return 255;
	return value;
    }
    static protected float limit1(float value){
	if(value<0f) return 0f;
	if(value>1f) return 1f;
	return value;
    }
    
    //static public Color color(int alpha){ getColor(alpha); } // PDE doesn't allow this name
    static public Color getColor(int alpha){ return clr(alpha); }
    static public Color clr(int alpha){
	return new Color(getInt(0,255),getInt(0,255),getInt(0,255),limit255(alpha));
    }
    static public Color getColor(int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue,
				 int minAlpha, int maxAlpha){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,minAlpha,maxAlpha);
    }
    static public Color clr(int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue,
			    int minAlpha, int maxAlpha){
	return new Color(limit255(getInt(minRed, maxRed)),
			 limit255(getInt(minGreen, maxGreen)),
			 limit255(getInt(minBlue, maxBlue)),
			 limit255(getInt(minAlpha, maxAlpha)));
    }
    
    /** add random numbers to each component of color */
    static public Color getColor(Color c, 
				 int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue,
				 int minAlpha, int maxAlpha){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,minAlpha,maxAlpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, 
			    int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue,
			    int minAlpha, int maxAlpha){
	return new Color(limit255(c.getRed()+getInt(minRed, maxRed)),
			 limit255(c.getGreen()+getInt(minGreen, maxGreen)),
			 limit255(c.getBlue()+getInt(minBlue, maxBlue)),
			 limit255(c.getAlpha()+getInt(minAlpha, maxAlpha)));
    }
    
    static public Color getColor(int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue,
				 int alpha){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,alpha);
    }
    static public Color clr(int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue,
			    int alpha){
	return new Color(limit255(getInt(minRed, maxRed)),
			 limit255(getInt(minGreen, maxGreen)),
			 limit255(getInt(minBlue, maxBlue)),
			 limit255(alpha));
    }
    
    /** add random numbers to each component of color */
    static public Color getColor(Color c, int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue,
				 int alpha){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,alpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue,
			    int alpha){
	return new Color(limit255(c.getRed()+getInt(minRed, maxRed)),
			 limit255(c.getGreen()+getInt(minGreen, maxGreen)),
			 limit255(c.getBlue()+getInt(minBlue, maxBlue)),
			 limit255(alpha));
    }


    static public Color getColor(int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue);
    }
    static public Color clr(int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue){
	return new Color(limit255(getInt(minRed, maxRed)),
			 limit255(getInt(minGreen, maxGreen)),
			 limit255(getInt(minBlue, maxBlue)));
    }
    
    /** add random numbers to each component of color */
    static public Color getColor(Color c, int minRed, int maxRed,
				 int minGreen, int maxGreen,
				 int minBlue, int maxBlue){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, int minRed, int maxRed,
			    int minGreen, int maxGreen,
			    int minBlue, int maxBlue){
	return new Color(limit255(c.getRed()+getInt(minRed, maxRed)),
			 limit255(c.getGreen()+getInt(minGreen, maxGreen)),
			 limit255(c.getBlue()+getInt(minBlue, maxBlue)));
    }
    
    
    static public Color getColor(int maxRed, int maxGreen, int maxBlue, int alpha){
	return clr(maxRed,maxGreen,maxBlue,alpha);
    }
    static public Color clr(int maxRed, int maxGreen, int maxBlue,
			    int alpha){
	return new Color(limit255(getInt(maxRed)),limit255(getInt(maxGreen)),limit255(getInt(maxBlue)),
			 limit255(alpha));
    }

    /** add random numbers to each component of color */
    static public Color getColor(Color c, int maxRed, int maxGreen, int maxBlue, int alpha){
	return clr(c,maxRed,maxGreen,maxBlue,alpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, int maxRed, int maxGreen, int maxBlue,
			    int alpha){
	return new Color(limit255(c.getRed()+getInt(maxRed)),
			 limit255(c.getGreen()+getInt(maxGreen)),
			 limit255(c.getBlue()+getInt(maxBlue)),
			 limit255(alpha));
    }
    
    static public Color getColor(int maxRed, int maxGreen, int maxBlue){
	return clr(maxRed,maxGreen,maxBlue);
    }
    static public Color clr(int maxRed, int maxGreen, int maxBlue){
	return new Color(limit255(getInt(maxRed)),limit255(getInt(maxGreen)),limit255(getInt(maxBlue)));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, int maxRed, int maxGreen, int maxBlue){
	return clr(c,maxRed,maxGreen,maxBlue);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, int maxRed, int maxGreen, int maxBlue){
	return new Color(limit255(c.getRed()+getInt(maxRed)),
			 limit255(c.getGreen()+getInt(maxGreen)),
			 limit255(c.getBlue()+getInt(maxBlue)));
    }
    
    static public Color getColor(float alpha){ return clr(alpha); }
    static public Color clr(float alpha){
	return new Color(getFloat(),getFloat(),getFloat(),limit1(alpha));
    }
    
    
    static public Color getColor(float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue,
				 float minAlpha, float maxAlpha){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,minAlpha,maxAlpha);
    }
    static public Color clr(float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue,
			    float minAlpha, float maxAlpha){
	return new Color(limit1(getFloat(minRed, maxRed)),
			 limit1(getFloat(minGreen, maxGreen)),
			 limit1(getFloat(minBlue, maxBlue)),
			 limit1(getFloat(minAlpha, maxAlpha)));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue,
				 float minAlpha, float maxAlpha){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,minAlpha,maxAlpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue,
			    float minAlpha, float maxAlpha){
	return new Color(limit1((float)c.getRed()/255f+getFloat(minRed, maxRed)),
			 limit1((float)c.getGreen()/255f+getFloat(minGreen, maxGreen)),
			 limit1((float)c.getBlue()/255f+getFloat(minBlue, maxBlue)),
			 limit1((float)c.getAlpha()/255f+getFloat(minAlpha, maxAlpha)));
    }
    
    static public Color getColor(float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue,
				 float alpha){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,alpha);
    }
    static public Color clr(float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue,
			    float alpha){
	return new Color(limit1(getFloat(minRed, maxRed)),
			 limit1(getFloat(minGreen, maxGreen)),
			 limit1(getFloat(minBlue, maxBlue)),
			 limit1(alpha));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue,
				 float alpha){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue,alpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue,
			    float alpha){
	return new Color(limit1((float)c.getRed()/255f+getFloat(minRed, maxRed)),
			 limit1((float)c.getGreen()/255f+getFloat(minGreen, maxGreen)),
			 limit1((float)c.getBlue()/255f+getFloat(minBlue, maxBlue)),
			 limit1(alpha));
    }
    
    static public Color getColor(float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue){
	return clr(minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue);
    }
    static public Color clr(float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue){
	return new Color(limit1(getFloat(minRed, maxRed)),
			 limit1(getFloat(minGreen, maxGreen)),
			 limit1(getFloat(minBlue, maxBlue)));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, float minRed, float maxRed,
				 float minGreen, float maxGreen,
				 float minBlue, float maxBlue){
	return clr(c,minRed,maxRed,minGreen,maxGreen,minBlue,maxBlue);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, float minRed, float maxRed,
			    float minGreen, float maxGreen,
			    float minBlue, float maxBlue){
	return new Color(limit1((float)c.getRed()/255f+getFloat(minRed, maxRed)),
			 limit1((float)c.getGreen()/255f+getFloat(minGreen, maxGreen)),
			 limit1((float)c.getBlue()/255f+getFloat(minBlue, maxBlue)));
    }
    
    static public Color getColor(float maxRed,float maxGreen,float maxBlue,float alpha){
	return clr(maxRed,maxGreen,maxBlue,alpha);
    }
    static public Color clr(float maxRed, float maxGreen, float maxBlue,
			    float alpha){
	return new Color(limit1(getFloat(maxRed)),limit1(getFloat(maxGreen)),limit1(getFloat(maxBlue)),
			 limit1(alpha));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, float maxRed,float maxGreen,float maxBlue,float alpha){
	return clr(c,maxRed,maxGreen,maxBlue,alpha);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, float maxRed, float maxGreen, float maxBlue,
			    float alpha){
	return new Color(limit1((float)c.getRed()/255f+getFloat(maxRed)),
			 limit1((float)c.getGreen()/255f+getFloat(maxGreen)),
			 limit1((float)c.getBlue()/255f+getFloat(maxBlue)),
			 limit1(alpha));
    }
    
    static public Color getColor(float maxRed,float maxGreen,float maxBlue){
	return clr(maxRed,maxGreen,maxBlue);
    }
    static public Color clr(float maxRed, float maxGreen, float maxBlue){
	return new Color(limit1(getFloat(maxRed)),limit1(getFloat(maxGreen)),limit1(getFloat(maxBlue)));
    }
    /** add random numbers to each component of color */
    static public Color getColor(Color c, float maxRed,float maxGreen,float maxBlue){
	return clr(c,maxRed,maxGreen,maxBlue);
    }
    /** add random numbers to each component of color */
    static public Color clr(Color c, float maxRed, float maxGreen, float maxBlue){
	return new Color(limit1((float)c.getRed()/255f+getFloat(maxRed)),
			 limit1((float)c.getGreen()/255f+getFloat(maxGreen)),
			 limit1((float)c.getBlue()/255f+getFloat(maxBlue)));
    }
    
    
    //static public Color gray(){ return getGray(); }
    static public Color getGrayColor(){ return gray(); }
    static public Color getGray(){ return gray(); }
    static public Color gray(){
	int gray = getInt(0,255);
	return new Color(gray,gray,gray);
    }
    //static public Color gray(int alpha){ return getGray(alpha); }
    static public Color getGrayColor(int alpha){ return gray(alpha); }
    static public Color getGray(int alpha){ return gray(alpha); }
    static public Color gray(int alpha){
	int gray = getInt(0,255);
	return new Color(gray,gray,gray,limit255(alpha));
    }
    static public Color getGrayColor(float alpha){ return gray(alpha); }
    static public Color getGray(float alpha){ return gray(alpha); }
    static public Color gray(float alpha){
	float gray = getFloat();
	return new Color(gray,gray,gray,limit1(alpha));
    }

    static public Color getGrayColor(float minGray, float maxGray, float minAlpha, float maxAlpha){
	return gray(minGray,maxGray,minAlpha,maxAlpha);
    }
    static public Color getGray(float minGray, float maxGray, float minAlpha, float maxAlpha){
	return gray(minGray,maxGray,minAlpha,maxAlpha);
    }
    static public Color gray(float minGray, float maxGray, float minAlpha, float maxAlpha){
	float gray = limit1(getFloat(minGray,maxGray));
	return new Color(gray,gray,gray,limit1(getFloat(minAlpha,maxAlpha)));
    }
    
    static public Color getGrayColor(float minGray, float maxGray, float alpha){
	return gray(minGray,maxGray,alpha);
    }
    static public Color getGray(float minGray, float maxGray, float alpha){
	return gray(minGray,maxGray,alpha);
    }
    static public Color gray(float minGray, float maxGray, float alpha){
	float gray = limit1(getFloat(minGray,maxGray));
	return new Color(gray,gray,gray,limit1(alpha));
    }
    
    
    static public Color getGrayColor(float minGray, float maxGray){
	return gray(minGray,maxGray);
    }
    static public Color getGray(float minGray, float maxGray){
	return gray(minGray,maxGray);
    }
    static public Color gray(float minGray, float maxGray){
	float gray = limit1(getFloat(minGray,maxGray));
	return new Color(gray,gray,gray);
    }
    
    
}



