/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/07/21, 17:32
!  AUTHOR(S): KOGA, Junichiro
!  File : Kpoint.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.fbz;

import javax.vecmath.Point3f;

import org.apache.log4j.Logger;

/**
 * 「k点」構造体.
 * 
 * @author
 */
public class Kpoint {
    private Logger logger = Logger.getLogger(Kpoint.class.getName());

    private int[] numerators;

    private int[] denomenator;

    private int weight = 1;

    private String symbol = "";

    public Kpoint(int[] numerators, int[] denomenator) {
        this.numerators = numerators;
        this.denomenator = denomenator;
    }

    private int commonDenom = 1;

    private int[] scale;

    public Kpoint(int[][] kpts) {
        this.numerators = new int[3];
        this.denomenator = new int[3];
        for (int i = 0; i < 3; i++) {
            numerators[i] = kpts[i][0];
            denomenator[i] = kpts[i][1];
        }
        commonDenom = getCommonDenomenator(denomenator[0], denomenator[1],
                denomenator[2]);
        scale = new int[3];
        for (int i = 0; i < 3; i++) {
            scale[i] = commonDenom / denomenator[i];
        }
    }

    public Kpoint(float[] kps) {
        this.numerators = new int[3];
        this.denomenator = new int[3];
        for (int i = 0; i < kps.length; i++) {
            int[] buns = FBZUtils.getBunsu(kps[i]);
            numerators[i] = buns[1];
            denomenator[i] = buns[2];
        }
        commonDenom = getCommonDenomenator(denomenator[0], denomenator[1],
                denomenator[2]);
        scale = new int[3];
        for (int i = 0; i < 3; i++) {
            scale[i] = commonDenom / denomenator[i];
        }
    }

    public Kpoint(SymmetryPointBG bg) {
        int[][] kpts = bg.getBunsuCoords();
        this.numerators = new int[3];
        this.denomenator = new int[3];
        for (int i = 0; i < 3; i++) {
            numerators[i] = kpts[i][0];
            denomenator[i] = kpts[i][1];
        }
        commonDenom = getCommonDenomenator(denomenator[0], denomenator[1],
                denomenator[2]);
        scale = new int[3];
        for (int i = 0; i < 3; i++) {
            scale[i] = commonDenom / denomenator[i];
        }
        setSymbol(bg.getSymbol());
    }

    private void init() {

    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public String getSymbol() {
        return symbol;
    }

    public int[][] getBunsuCoords() {
        return new int[][] { numerators, denomenator };
    }

    public static int getCommonDenomenator(int denom1, int denom2, int denom3) {
        int lcm1 = FBZUtils.lcm(denom1, denom2);
        return FBZUtils.lcm(lcm1, denom3);
    }

    public double[] getDouble() {
        double[] ret = new double[3];
        for (int i = 0; i < 3; i++)
            try {
                ret[i] = ((double) numerators[i]) / ((double) denomenator[i]);
            } catch (RuntimeException e) {
                logger.error("invalid denomenator");
                return null;
            }
        return ret;
    }

    public Point3f getPoint3f() {
        double[] d = getDouble();
        float[] f = new float[3];
        for (int i = 0; i < 3; i++)
            f[i] = (float) d[i];
        Point3f ret = new Point3f(f);
        return ret;
    }

    /**
     * band_kpoint.pl用の書き出しを行う.
     * 
     * @return band_kpoint.plのk点入力形式
     */
    public String toString_bandkptpl() {
        if (scale == null) {
            return toString();
        }
        String ret = String.valueOf(numerators[0] * scale[0]) + " "
                + String.valueOf(numerators[1] * scale[1]) + " "
                + String.valueOf(numerators[2] * scale[2]) + " "
                + String.valueOf(commonDenom);
        if (symbol != null && symbol.trim().length() != 0) {
            ret += " # " + symbol;
        }
        return ret;
    }

    /**
     * 自分自身と引数のk点からの"距離"を返す
     * 
     * @param from
     *            比較するk点
     * @return fromからの距離
     */
    public double getDistanceFrom(Kpoint from) {
        double[] dfrom = from.getDouble();
        double[] d = getDouble();
        return Math.sqrt(Math.pow(dfrom[0] - d[0], 2)
                + Math.pow(dfrom[1] - d[1], 2) + Math.pow(dfrom[2] - d[2], 2));
    }

    public String toString() {
        String ret = String.valueOf(numerators[0]) + "/"
                + String.valueOf(denomenator[0]) + " "
                + String.valueOf(numerators[1]) + "/"
                + String.valueOf(denomenator[1]) + " "
                + String.valueOf(numerators[2]) + "/"
                + String.valueOf(denomenator[2]);
        if (symbol != null && symbol.trim().length() != 0) {
            ret += " # " + symbol;
        }
        return ret;
    }

    public boolean equals(Object obj) {
        double eps = 0.00001d;
        if (!(obj instanceof Kpoint))
            return false;
        double[] comp = ((Kpoint) obj).getDouble();
        double[] dk = getDouble();
        for (int i = 0; i < dk.length; i++)
            if (Math.abs(comp[i] - dk[i]) > eps)
                return false;
        return true;
    }

}
