import java.lang.Math;
import java.util.ArrayList;
import java.util.List;


public class Vector {
	// Constants for color models
	public static final int RGB=1;
	public static final int YCBCR=2;
	public static final int HSV=3;
	public static final int HMMD=4;
	public static final int MONOCHROMATIC=5;
	// Constants for HSV model
	public static final int H=0;
	public static final int S=1;
	public static final int V=2;
	
	// Class variables 
	protected ArrayList<Double> v = new ArrayList<Double>(); // protected means, that nobody from outside can work with this v
	protected int colorModel=1;
		
	public double distance (Vector vDistance) { // v of method has higher importance then v of class
		assert vDistance.getLength() == this.v.size();
		ArrayList<Double> distanceList = new ArrayList<Double>(); // 5 is because of HMMD model (five dimension model)
		double distance;
		for (int i=0;i<vDistance.getLength();i++) { // generate 0 to distanceList
			distanceList.add(0.0);
		}
		for (int i=0;i<vDistance.getLength();i++) {
			distanceList.set(i, Math.abs(this.v.get(i)-vDistance.get(i)));
		}
		distance = Math.sqrt(Math.pow(distanceList.get(0), 2)+
					  		 Math.pow(distanceList.get(1), 2)+
					  		 Math.pow(distanceList.get(2), 2)
					 		);
		return distance;
	}
	
	public int getLength () {
		return v.size();
	}
	
	public void setRandomHSV() {
		v.set(H, (double) Math.round(Math.random()*360));
		v.set(S, (double) Math.round(Math.random()*100));
		v.set(V, (double) Math.round(Math.random()*100));
	}
	
	public void generate(int size) { // preparing for vector (set is possible only after generating vector)
		for (int i=v.size(); i<size; i++) {
			v.add(0.0);
		}
	}
	
	public void set(double first, double second, double third) {
		v.set(0, first);
		v.set(1, second);
		v.set(2, third);
	}
	
	public void set (double value, int i) {
		v.set(i, value);
	}
	
	public void convertTo(int cm) {
		double red=v.get(0);
		double green=v.get(1);
		double blue=v.get(2);
		if (cm==HSV) {
			double hue,sat,val=0;
	
			red=red/255; 		// normalize r,g,b, [0,1]
	        green=green/255; 
	        blue=blue/255; 
	        double max = Math.max(red,Math.max(green,blue)); // find max and min values
	        double min = Math.min(red,Math.min(green,blue));
	        double delta = max-min; // delta max and min
			//Value extraction
	        val=max;
	        // Saturation extraction
	        if (max==0)   
				sat = 0;
			else 
				sat=delta/max;
			// Hue extraction
	        if (max==min) 
			hue=-1; // hue is undefined. (achromatic color) 
			else 
			{ 
			if ( red==max && green>blue ) 
			hue = 60*(green-blue)/delta; 
			else if (red==max && green>blue ) 
			hue = 360+60*(green-blue)/delta; 
			else if (green==max ) 
			hue = 60*(2.0 + (blue-red)/delta); 
			else 
			hue=60*(4.0+(red-green)/delta); 
			}
			
			hue = Math.round(hue); // rounding
			sat = Math.round(sat*100); //rounding and normalize range to 100
			val = Math.round(val*100); // rounding and normalize range to 100
			v.set(0, hue);
			v.set(1, sat);
			v.set(2, val);
		}
		else if (cm==YCBCR) {
			double y, cb, cr;
			y=0.299*red+0.587*green+0.114*blue;
			cb=-0.169*red-0.331*green+0.5*blue;
			cr=0.5*red-0.419*green-0.881*blue;
			v.set(0, y);
			v.set(1, cb);
			v.set(2, cr);
		}
		else if (cm==HMMD) {	
			double hue;
			red=red/255; 		// normalize r,g,b, [0,1]
	        green=green/255; 
	        blue=blue/255;
	        // Max extraction
	        double max = Math.max(red,Math.max(green,blue)); // find max and min values
	        // Min extraction
	        double min = Math.min(red,Math.min(green,blue));
	        double delta = max-min; // delta max and min
			//Diff extraction
	        double diff=delta;
	        //Sum extraction
	        double sum = (max+min)/2;
			// Hue extraction
	        if (max==min) 
			hue=-1; // hue is undefined. (achromatic color) 
			else 
			{ 
			if ( red==max && green==min ) 
			hue = 60*(green-blue)/delta; 
			else if (red==max && green==min ) 
			hue = 360+60*(green-blue)/delta; 
			else if (green==max ) 
			hue = 60*(2.0 + (blue-red)/delta); 
			else 
			hue=60*(4.0+(red-green)/delta); 
			}
			
			hue = Math.round(hue); // rounding
			v.set(0, hue);
			v.set(1, max);
			v.set(2, min);
			v.set(3, diff);
			v.set(4, sum);
		}
		
		else if (cm==MONOCHROMATIC) {
			double y;
			y=0.299*red+0.587*green+0.114*blue;
			v.set(0, y);
		}	
	}
	
	public double get(int i) {
		return v.get(i);
	}
	
	public void plus (Vector plusv) {
		this.generate(3);
		this.v.set(0, this.v.get(0)+plusv.get(0)); // v is ArrayList, not vector!
		this.v.set(1, this.v.get(1)+plusv.get(1));
		this.v.set(2, this.v.get(2)+plusv.get(2));
	}
	
	public void div (double divD) {
		this.v.set(0, this.v.get(0)/divD); // v is ArrayList, not vector!
		this.v.set(1, this.v.get(1)/divD);
		this.v.set(2, this.v.get(2)/divD);
	}
	
	public void copy (Vector vector) {
		this.generate(vector.getLength());
		for (int i=0;i<vector.getLength();i++) {
			this.v.set(i, vector.get(i));
		}
	}

}

	

