// Colormap.java : Colormap class for easier manipulation of
//		   graded colors.
// by Yoonsuck Choe <yschoe@cs.utexas.edu>
//
//	 Mon Mar 30 13:24:13 CST 1998

import java.awt.*;
import java.util.*;

public class Colormap {
  
  private int max_colors;	// maximum numbers of colors available
  private String range_string;	// color range "BRYW" for Black, Yellow, etc
  private int interval_count;	// color range - how many colors?
  private int interval_size;	// how many colors per interval?
  private int interval_rgb[][];	// rgb value of each interval
  public  Color table[];	// colormap table

  // setup interval rgb table
  private void setup_interval_rgb(String spectrum_str) {
	// interval_count needs to be set up before entering
	// this function

	Hashtable color_to_int = new Hashtable();
 	interval_rgb = new int[interval_count+1][3];

	// setup rgb values for each numbered colors
	int int_to_rgb[][] = {
		{255, 	0, 	0}, 		// 0 : Red
		{0, 	255, 	0},		// 1 : Green
		{0, 	0, 	255}, 		// 2 : Blue
		{255, 	255, 	0}, 		// 3 : Yellow
		{0, 	255, 	255},		// 4 : Cyan
		{255, 	0, 	255},		// 5 : Magenta
		{0, 	0, 	0},		// 6 : Black
		{255, 	255, 	255}};		// 7 : White
		// you can add more RGB values here and 
		// set up the index below

	// setup color_to_int hashtable
	color_to_int.put(new Character('r'),new Integer(0)); 
	color_to_int.put(new Character('R'),new Integer(0));
	color_to_int.put(new Character('g'),new Integer(1)); 
	color_to_int.put(new Character('G'),new Integer(1));
	color_to_int.put(new Character('b'),new Integer(2)); 
	color_to_int.put(new Character('B'),new Integer(2));
	color_to_int.put(new Character('y'),new Integer(3)); 
	color_to_int.put(new Character('Y'),new Integer(3));
	color_to_int.put(new Character('c'),new Integer(4)); 
	color_to_int.put(new Character('C'),new Integer(4));
	color_to_int.put(new Character('m'),new Integer(5)); 
	color_to_int.put(new Character('M'),new Integer(5));
	color_to_int.put(new Character('0'),new Integer(6)); // '0' means Black
	color_to_int.put(new Character('1'),new Integer(7)); // '1' means White
	
	// fill in the rgb values for each interval
	for (int i = 0; i<interval_count+1; ++i) 
	{
		for (int j=0; j<3; ++j)
		{
			Integer idx = (Integer) color_to_int.get(
					new Character(spectrum_str.charAt(i)));
			interval_rgb[i][j] = int_to_rgb[idx.intValue()][j];
		}
	}
  }	
 
  // constructor : 
  //		spectrum_str: color spectrum
  //		 	"0ry1" for black to Red to Yellow to White.
  //		max : max color range
  public Colormap(String spectrum_str, int max) {
	// spectrum_str is a string of colors:
	//	"0RY1" - means Black to Red to Yellow to White
	int count=0;

	// set up some numbers and parameters
	max_colors=max;  
	range_string = spectrum_str;
	interval_count = range_string.length()-1; 
	interval_size = max_colors/interval_count;

	// setup rgb table for each interval
	this.setup_interval_rgb(range_string);
	
        // Allocate table[] and assign colors
	table = new Color[max_colors];
   	for (int i=0; i<interval_count; ++i)
	{
		// Get the start color in this range
		int  start_range = i*interval_size;
		int  end_range = (i==interval_count-1) 
				? max_colors
				: (i+1)*interval_size;
		int  range_size = end_range-start_range;

		// for each rgb, find start and end and step
		float rstart = interval_rgb[i][0];
		float rend   = interval_rgb[i+1][0];
		float rstep  = (rstart-rend==0)?0:-(rstart-rend)/range_size;
		float gstart = interval_rgb[i][1];
		float gend   = interval_rgb[i+1][1];
		float gstep  = (gstart-gend==0)?0:-(gstart-gend)/range_size;
		float bstart = interval_rgb[i][2];
		float bend   = interval_rgb[i+1][2];
		float bstep  = (bstart-bend==0)?0:-(bstart-bend)/range_size;

		// System.out.println(start_range+", "+end_range);
		// System.out.println("   "+rstep+","+gstep+","+bstep);
		// System.out.println("       "+rstart+" - "+rend);
		// System.out.println("       "+gstart+" - "+gend);
		// System.out.println("       "+bstart+" - "+bend);
		for (int j=start_range; j<end_range; ++j)
		{
		   //// debug
		   // if (j==start_range) {
		   //  	System.out.print("range "+i+" = "+start_range);
		   //	System.out.println(" to "+end_range);
		   // }
		   table[count++] = new Color(
					(int)(rstart+(j-start_range)*rstep),
					(int)(gstart+(j-start_range)*gstep),
					(int)(bstart+(j-start_range)*bstep));
		}
	}
  }

  // display_spectrum - in 2D plain
  public void displaySpectrum (Graphics g, int width, int height) {

	int columns = (int) Math.sqrt(max_colors);
        int xgran = width / columns - 2;
        int ygran = height / columns - 2;
	for (int k=0; k<max_colors; ++k)
	{
		g.setColor(table[k]);   // Get Color from the table.
					// Since 'table' is public, 
					// any other class can use it
					// once an instance has been generated
		g.fillRect((k%columns)*xgran,(k/columns)*ygran,xgran,ygran);
	}
  }

  // display_spectrum - in 2D plain (with configurable origin x, y)
  public void displaySpectrum(Graphics g, int x, int y, int width, int height){

	int columns = (int) Math.sqrt(max_colors);
        int xgran = width / columns - 2;
        int ygran = height / columns - 2;
	for (int k=0; k<max_colors; ++k)
	{
		g.setColor(table[k]);	// Get Color from the table.
					// Since 'table' is public, 
					// any other class can use it
					// once an instance has been generated
		g.fillRect(x+(k%columns)*xgran,y+(k/columns)*ygran,xgran,ygran);
	}
  }
}
