/*
* Copyright 2013 Skynav, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.skynav.ttv.model.value.impl;
import com.skynav.ttv.model.value.Color;
public class ColorImpl implements Color {
public static final Color CURRENT = new ColorImpl();
private double red;
private double green;
private double blue;
private double alpha;
public ColorImpl(double red, double green, double blue, double alpha) {
this.red = clamp(red);
this.green = clamp(green);
this.blue = clamp(blue);
this.alpha = clamp(alpha);
}
private ColorImpl() {
this.red = this.green = this.blue = this.alpha = Double.NaN;
}
private double clamp(double component) {
if (Double.isNaN(component))
component = 0;
else if (component <= 0)
component = 0;
else if (component >= 1)
component = 1;
return component;
}
public double getRed() {
return red;
}
public double getGreen() {
return green;
}
public double getBlue() {
return blue;
}
public double getAlpha() {
return alpha;
}
public boolean isCurrent() {
return this == CURRENT;
}
public int hashCode() {
if (isCurrent())
return -1;
else {
int r = Double.valueOf(red).hashCode();
r = rotateRight(r, 0);
int g = Double.valueOf(green).hashCode();
g = rotateRight(g, 8);
int b = Double.valueOf(blue).hashCode();
b = rotateRight(b, 16);
int a = Double.valueOf(alpha).hashCode();
a = rotateRight(a, 24);
return r ^ g ^ b ^ a;
}
}
private static int rotateRight(int bits, int n) {
n = n % Integer.SIZE;
return (bits >>> n) | (bits << (Integer.SIZE - n));
}
public boolean equals(Object o) {
if (o instanceof Color) {
Color c = (Color) o;
if (isCurrent() ^ c.isCurrent())
return false;
else if (isCurrent()) {
assert c.isCurrent();
return true;
} else if (c.getRed() != red)
return false;
else if (c.getGreen() != green)
return false;
else if (c.getBlue() != blue)
return false;
else if (c.getAlpha() != alpha)
return false;
else
return true;
} else
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer();
if (isCurrent())
sb.append("current");
else {
sb.append("rgb");
if (alpha != 1)
sb.append('a');
sb.append('(');
sb.append(getComponentAsString(red));
sb.append(',');
sb.append(getComponentAsString(green));
sb.append(',');
sb.append(getComponentAsString(blue));
if (alpha != 1) {
sb.append(',');
sb.append(getComponentAsString(alpha));
}
sb.append(')');
}
return sb.toString();
}
private static String getComponentAsString(double component) {
return Integer.toString((int) Math.floor(component * 255));
}
public static Color fromRGBHash(String hash) {
assert (hash.length() == 6) || (hash.length() == 8);
double r = fromHexColor(hash.substring(0,2));
double g = fromHexColor(hash.substring(2,4));
double b = fromHexColor(hash.substring(4,6));
double a = (hash.length() == 8) ? fromHexColor(hash.substring(6,8)) : 1;
return new ColorImpl(r,g,b,a);
}
private static double fromHexColor(String color) {
try {
return Integer.valueOf(color, 16).doubleValue() / 255.0;
} catch (NumberFormatException e) {
return 0;
}
}
}