/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/07/25, 11:04
!  AUTHOR(S): KOGA, Junichiro
!  File : KpointMeshPanel.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.plugins.fbz.edit;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.J3DPanel;
import ciss.phase_viewer.acviewer.fbz.FBZ;
import ciss.phase_viewer.acviewer.fbz.Kpoint;
import ciss.phase_viewer.acviewer.fbz.KpointGenerator;
import ciss.phase_viewer.acviewer.fbz.SymmetryPointBG;
import ciss.phase_viewer.acviewer.fbz.WignerSeitzAttributes;
import ciss.phase_viewer.acviewer.fbz.WignerSeitzCell;
import ciss.phase_viewer.acviewer.geom.BoundPlane;

/**
 * FBZ内にメッシュを生成 大したことはしない.
 * 
 * @author
 */
public class KpointMeshPanel extends JPanel implements KpointGenerator {
    private Logger logger = Logger.getLogger(KpointMeshPanel.class.getName());
    private FBZ fbz;
    private WignerSeitzCell wscell;

    /** Creates a new instance of KpointMeshPanel */
    public KpointMeshPanel(J3DPanel basePanel) {
        fbz = (FBZ) basePanel;
        wscell = fbz.getFBZ();
        init();
    }

    private JTextField textn1;
    private JTextField textn2;
    private JTextField textn3;

    private void init() {
        JPanel panel = new JPanel();
        panel.setBorder(new TitledBorder("mesh"));
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));

        textn1 = new JTextField(8);
        textn2 = new JTextField(8);
        textn3 = new JTextField(8);
        textn1.setText("20");
        textn2.setText("20");
        textn3.setText("20");

        JPanel xpanel = new JPanel();
        xpanel.setBorder(new TitledBorder("n1"));
        xpanel.add(textn1);

        JPanel ypanel = new JPanel();
        ypanel.setBorder(new TitledBorder("n2"));
        ypanel.add(textn2);

        JPanel zpanel = new JPanel();
        zpanel.setBorder(new TitledBorder("n3"));
        zpanel.add(textn3);

        panel.add(xpanel);
        panel.add(ypanel);
        panel.add(zpanel);

        this.add(panel);
    }

    public void saveInput(Kpoint[] kpoints, double deltak) {
    }

    public void generateKpoints(Kpoint[] kpoints, double dk) {
        int n1 = 0;
        int n2 = 0;
        int n3 = 0;
        try {
            n1 = Integer.parseInt(textn1.getText().trim());
            n2 = Integer.parseInt(textn2.getText().trim());
            n3 = Integer.parseInt(textn3.getText().trim());
        } catch (Exception exc) {
            logger.error("invalid values");
            return;
        }

        float[][] recvec = fbz.getReciprocalLatticeVector();
        Point3f[] lat = new Point3f[3];
        lat[0] = new Point3f(recvec[0]);
        lat[1] = new Point3f(recvec[1]);
        lat[2] = new Point3f(recvec[2]);

        int n1h = n1;
        int n2h = n2;
        int n3h = n3;

        float delta1 = 1f / ((float) n1h);
        float delta2 = 1f / ((float) n2h);
        float delta3 = 1f / ((float) n3h);
        float de1 = recvec[0][0] * delta1 + recvec[1][0] * delta2
                + recvec[2][0] * delta3;
        float de2 = recvec[0][1] * delta1 + recvec[1][1] * delta2
                + recvec[2][1] * delta3;
        float de3 = recvec[0][2] * delta1 + recvec[1][2] * delta2
                + recvec[2][2] * delta3;
        float ratio1 = de1
                / ((float) Math.sqrt((double) (recvec[0][0] * recvec[0][0]
                        + recvec[1][0] * recvec[1][0] + recvec[2][0]
                        * recvec[2][0])));
        float ratio2 = de2
                / ((float) Math.sqrt((double) (recvec[0][1] * recvec[0][1]
                        + recvec[1][1] * recvec[1][1] + recvec[2][1]
                        * recvec[2][1])));
        float ratio3 = de3
                / ((float) Math.sqrt((double) (recvec[0][2] * recvec[0][2]
                        + recvec[1][2] * recvec[1][2] + recvec[2][2]
                        * recvec[2][2])));
        float rat = ratio1;
        if (ratio2 > rat) {
            rat = ratio2;
        }
        if (ratio3 > rat) {
            rat = ratio3;
        }

        BoundPlane[] planes = wscell.getPlanes();
        if (planes == null) {
            logger.error("invalid planes!!!");
            return;
        }
        BoundPlane[] biggerPlane = new BoundPlane[planes.length];
        Point3f orig = new Point3f();
        // float bigger = 1f+rat*5f;
        float bigger = 1.1f;
        logger.debug("plane enlargement factor: " + bigger);
        for (int i = 0; i < biggerPlane.length; i++) {
            float d = planes[i].getDistanceFrom(orig);
            biggerPlane[i] = new BoundPlane();
            biggerPlane[i].setVertices(planes[i].getVertices());
            biggerPlane[i].setNormalVector(planes[i].getNormalVector());
            Point3f origorig = planes[i].getOrigin();
            Point3f neworig = new Point3f();
            neworig.x = origorig.x * bigger;
            neworig.y = origorig.y * bigger;
            neworig.z = origorig.z * bigger;
            biggerPlane[i].setOrigin(neworig);
        }
        // for ( int i=0 ; i<planes.length ; i++ ) {
        // planes[i].sortVertices();
        // planes[i].generateNormal();
        // planes[i].generateOrigin();
        // }

        // int n1h = n1/2;
        // int n2h = n2/2;
        // int n3h = n3/2;

        WignerSeitzAttributes wsattrs = new WignerSeitzAttributes();
        Vector points = new Vector();
        Vector inbz = new Vector();
        for (int i = -n3h; i <= n3h; i++) {
            for (int j = -n2h; j <= n2h; j++) {
                for (int k = -n1h; k <= n1h; k++) {
                    Point3f point = new Point3f();
                    point.x = recvec[0][0] * delta1 * i + recvec[1][0] * delta2
                            * j + recvec[2][0] * delta3 * k;
                    point.y = recvec[0][1] * delta1 * i + recvec[1][1] * delta2
                            * j + recvec[2][1] * delta3 * k;
                    point.z = recvec[0][2] * delta1 * i + recvec[1][2] * delta2
                            * j + recvec[2][2] * delta3 * k;
                    int inplane = 0;
                    for (int l = 0; l < biggerPlane.length; l++) {
                        if (biggerPlane[l].getVertices().length <= 2) {
                            logger.error("invalid plane....");
                            continue;
                        }
                        float d1 = biggerPlane[l].getDistanceFrom(point);
                        float d2 = biggerPlane[l].getDistanceFrom(orig);
                        if (d1 <= 0 && d2 <= 0 || d1 >= 0 && d2 >= 0) {
                            inplane++;
                        }
                    }
                    if (inplane == biggerPlane.length) {
                        points.addElement((new Kpoint(new SymmetryPointBG(
                                new Vector3f(point), lat, wsattrs)))
                                .toString_bandkptpl());
                        // SymmetryPointBG p = new SymmetryPointBG(new
                        // Vector3f(point),lat,wsattrs);
                        // points.addElement(p);
                        inbz.addElement(new Boolean(true));
                    } else {
                        inbz.addElement(new Boolean(false));
                    }
                    // SymmetryPointBG p = new SymmetryPointBG(new
                    // Vector3f(point),lat,wsattrs);
                    // points.addElement(p);
                    // inbz.addElement(new Boolean(true));
                }
            }
        }

        String kpointfile = fbz.getParentDirectory()
                + System.getProperty("file.separator") + "kpoint.data";
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(new BufferedWriter(new FileWriter(
                    kpointfile)));
            writer.println(String.valueOf(points.size()) + " "
                    + String.valueOf(points.size()));
            for (int i = 0; i < points.size(); i++) {
                // logger.debug(points.get(i)+" is within FBZ.");
                // SymmetryPointBG p = (SymmetryPointBG) points.get(i);
                // wscell.addChild(p);
                // Kpoint kp = new Kpoint(p);
                // String str = kp.toString_bandkptpl();
                String str = (String) points.get(i);
                str += " 1";
                writer.println(str);
                // System.out.println(i+" "+str);
            }
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
            writer.flush();
            try {
                writer.close();
            } catch (Exception exc) {
            }
        }

        String fsfile = fbz.getParentDirectory()
                + System.getProperty("file.separator") + "fs.data";
        float dlat1x = lat[0].x / ((float) n1h);
        float dlat1y = lat[0].y / ((float) n1h);
        float dlat1z = lat[0].z / ((float) n1h);
        float dlat2x = lat[1].x / ((float) n2h);
        float dlat2y = lat[1].y / ((float) n2h);
        float dlat2z = lat[1].z / ((float) n2h);
        float dlat3x = lat[2].x / ((float) n3h);
        float dlat3y = lat[2].y / ((float) n3h);
        float dlat3z = lat[2].z / ((float) n3h);
        try {
            writer = new PrintWriter(new BufferedWriter(new FileWriter(fsfile)));
            writer.println(String.valueOf(2 * n1h + 1) + " " + dlat1x + " "
                    + dlat1y + " " + dlat1z);
            writer.println(String.valueOf(2 * n2h + 1) + " " + dlat2x + " "
                    + dlat2y + " " + dlat2z);
            writer.println(String.valueOf(2 * n3h + 1) + " " + dlat3x + " "
                    + dlat3y + " " + dlat3z);
            int count = 0;
            for (int i = -n3h; i <= n3h; i++) {
                for (int j = -n2h; j <= n2h; j++) {
                    for (int k = -n1h; k <= n1h; k++) {
                        writer.println(i + " " + j + " " + k + " "
                                + inbz.get(count));
                        count++;
                    }
                }
            }
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
            writer.flush();
            try {
                writer.close();
            } catch (Exception exc) {
            }
        }

    }

    /**
     * ここでは使わない
     */
    public Kpoint[] getKpointsFrom(String file) {
        return null;
    }

}
