/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/06/29, 14:54
!  AUTHOR(S): KOGA, Junichiro
!  File : BaseColorMap.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.acviewer.colormap;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;

import javax.media.j3d.BranchGroup;
import javax.vecmath.Color3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.main.PluginLoader;

/**
 * 具体的なカラーマップの, これがベースクラス.
 * 
 * @author
 */
public abstract class BaseColorMap implements ColorMap {
    private static Logger logger = Logger.getLogger(BaseColorMap.class
            .getName());
    protected String name;

    public BaseColorMap() {
    }

    public javax.vecmath.Color3f getColor3f(float value) {
        Color color = getColor(value);
        Color3f c3f = new Color3f(color.getRed() / 255.f,
                color.getGreen() / 255.f, color.getBlue() / 255.f);
        return c3f;
    }

    public Color3f getColor3f(float value, boolean invert) {
        Color3f c3f = getColor3f(value);
        if (!invert) {
            return c3f;
        }
        return getColor3f(1 - value);
        // return new Color3f(1.f-c3f.x,1.f-c3f.y,1.f-c3f.z);
    }

    public Color getColor(float value, boolean invert) {
        Color c = getColor(value);
        if (!invert) {
            return c;
        }
        // return new Color(255-c.getRed(),255-c.getGreen(),255-c.getBlue());
        return getColor(1 - value);
    }

    public javax.media.j3d.BranchGroup getColorBar() {
        BranchGroup bg = new BranchGroup();

        return bg;
    }

    public String getName() {
        return name;
    }

    public String toString() {
        return getName();
    }

    /**
     * 線形スケールによって0から1の間の値に収めるメソッド
     * 
     * @param min
     *            最小値
     * @param max
     *            最大値
     * @param value
     *            スケールしたい値
     * @return スケールされた値; 0から1の値になっている
     */
    public static double getLinearScaledValue(double min, double max,
            double value) {
        double minmax = max - min;
        return (value - min) / minmax;
    }

    /**
     * 対数ベースである値を0から1の間に収める. 基本的には正の値を想定している; 負の値の場合差し当たり とても小さな数に置き換わる.
     * 
     * @param min
     *            最小値
     * @param max
     *            最大値
     * @param value
     *            スケールしたい値
     * @return スケールされた値; 0から1の間の値をとる.
     */
    public static double getLogScaledValue(double min, double max, double value) {
        if (min > max) {
            logger.debug("the specified minimum is larger than the specified maximum... replacing minimum and maximum.");
            double tmptmp = min;
            min = max;
            max = tmptmp;
        }
        if (min == max) {
            max = min + 1.0d - 10;
        }
        double tmpval = (double) value;
        if (min <= 0.0) {
            min = 1.0e-10;
        }
        if (max <= 0.0) {
            max = 2.0e-10;
        }
        if (tmpval <= 0.0) {
            tmpval = 1.0e-10;
        }
        double lmin = Math.log((double) min) + 100.d;
        double lmax = Math.log((double) max) + 100.d;
        double lval = Math.log((double) tmpval) + 100.d;

        double tmp1 = 1.0 / (lmax - lmin);
        double tmp2 = lval - lmin;
        double foo = (tmp1 * tmp2);

        return foo;
    }

    /**
     * 線形に0から1にスケールされた値から元の値をゲットする.
     * 
     * @param min
     *            最小値
     * @param max
     *            最大値
     * @param scaledValue
     *            線形にスケールされた値
     * @return 元の値
     */
    public static double getValueFromLinearScaledValue(double min, double max,
            double scaledValue) {
        return min + (max - min) * scaledValue;
    }

    /**
     * 対数で0から1にスケールされた値から元の値をゲットする.
     * 
     * @param min
     *            最小値
     * @param max
     *            最大値
     * @param scaledValue
     *            対数でスケールされた値
     * @return 元の値
     */
    public static double getValueFromLogScaledValue(double min, double max,
            double scaledValue) {
        if (scaledValue >= 1) {
            return max;
        }
        if (scaledValue <= 0) {
            return min;
        }

        if (min > max) {
            logger.warn("the specified minimum is larger than the specified maximum... replacing minimum and maximum.");
            double tmptmp = min;
            min = max;
            max = tmptmp;
        }
        if (min == max) {
            max = min + 1.0d - 10;
        }
        if (min <= 0.0) {
            min = 1.0e-10;
        }
        if (max <= 0.0) {
            max = 2.0e-10;
        }
        double lmin = Math.log((double) min) + 100.d;
        double lmax = Math.log((double) max) + 100.d;
        double foo = (lmax - lmin) * scaledValue + lmin - 100.d;
        double ret = Math.exp(foo);
        return ret;
    }

    private static ColorMap[] cmaps = null;

    public static ColorMap[] getSupportedColorMaps() {
        if (cmaps == null) {
            Vector objs = new Vector();
            try {
                InputStream is = BaseColorMap.class
                        .getResourceAsStream("/ciss/phase_viewer/acviewer/colormap/supported.properties");
                BufferedReader breader = new BufferedReader(
                        new InputStreamReader(is));
                String line = "";
                while ((line = breader.readLine()) != null) {
                    line = line.trim();
                    if (line.startsWith("#")) {
                        continue;
                    }
                    String[] foo = line.split("=");
                    if (foo == null || foo.length < 2) {
                        continue;
                    }
                    String na = foo[0];
                    String path = foo[1];
                    Object obj = PluginLoader.instantiate(path, null);
                    ((BaseColorMap) obj).name = na.replaceAll("_", " ");
                    objs.addElement(obj);
                }
                breader.close();
                is.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }

            cmaps = new ColorMap[objs.size()];
            objs.copyInto(cmaps);
        }
        return cmaps;
    }

}
