import java.io.*;
public class NearestNeighbor {
  public static void main(String argv[]){

    int i, j, natom;
    int sum_neighbor;

    FileInputStream fis;
    FileOutputStream Table_out, DataOut_ordered, Jmol_out;

    PrintStream prn_table, prn_jmol; 

    String atom_name;
    double [][] all_atoms;
    int [][] table_neighbor;
    int [] table_amount;
    double lowest_distance = 1.0e+20;
    double distance;
    double [] tempo;


    tempo = new double [3];

    try {    
      fis = new FileInputStream("quantumdot.dat");

      Table_out = new FileOutputStream("NNtable.list");
      Jmol_out = new FileOutputStream("ordered.xyz");
      DataOut_ordered = new FileOutputStream("ordered.dat");

      DataInputStream dis = new DataInputStream(fis);
      prn_table = new PrintStream( Table_out );
      prn_jmol = new PrintStream( Jmol_out );

      DataOutputStream Data_out = new DataOutputStream( DataOut_ordered );
      natom = dis.readInt();
      System.out.println(natom);

      all_atoms = new double [natom][3];
      table_amount   = new int [natom];
      table_neighbor = new int [natom][4];

      for( i=0; i < natom; i++) {
          atom_name = dis.readUTF();
          all_atoms[i][0] = dis.readDouble();
          all_atoms[i][1] = dis.readDouble();
          all_atoms[i][2] = dis.readDouble();
      }

      // find lowest distance
      for( i=0; i < natom; i++) {

        tempo[0] = all_atoms[i][0];
        tempo[1] = all_atoms[i][1];
        tempo[2] = all_atoms[i][2];

        for( j=0; j < natom; j++) {
          if (j != i) {
            distance = Math.pow(Math.abs(tempo[0]-all_atoms[j][0]), 2.0) +
                       Math.pow(Math.abs(tempo[1]-all_atoms[j][1]), 2.0) +
                       Math.pow(Math.abs(tempo[2]-all_atoms[j][2]), 2.0);
            distance = Math.sqrt(distance);
            if (distance < lowest_distance) lowest_distance = distance;

          }
        }
      }
      System.out.printf( "lowest distance = %2.6f \n", lowest_distance );
      if (lowest_distance < 1.0e-4) 
        System.out.printf( "WARNING: The structure has at least 2 atoms that coincide\n");
    
      // Nearest neighbor table
      prn_table.printf("Nearest Neighbor list of neighbors:\n");
      prn_table.printf("atom #    neighbor \n");
      prn_table.printf("------    -------- \n");
      for( i=0; i < natom; i++) {
  
        tempo[0] = all_atoms[i][0];
        tempo[1] = all_atoms[i][1];
        tempo[2] = all_atoms[i][2];
      
        sum_neighbor = 0;
        for( j=0; j < natom; j++) {
          if (j != i) {
            distance = Math.pow(Math.abs(tempo[0]-all_atoms[j][0]), 2.0) +
                       Math.pow(Math.abs(tempo[1]-all_atoms[j][1]), 2.0) +
                       Math.pow(Math.abs(tempo[2]-all_atoms[j][2]), 2.0);
            distance = Math.sqrt(distance);
            if (distance < lowest_distance*(1.1)) {
               table_neighbor[i][sum_neighbor] = j;
               sum_neighbor += 1;
               prn_table.printf("%4d  %4d   (%2.6f)\n", i+1, j+1, distance);
            }
          }
        }
        table_amount[i] = sum_neighbor;
        prn_table.printf("\n");
      }

      prn_jmol.printf ("%4d\n\n", natom);
      Data_out.writeInt(natom);
      for( i=0; i < natom; i++) {
        if (table_amount[i] == 4) {
          prn_table.printf("%4d  %4d: %4d   %4d   %4d   %4d\n", table_amount[i], i+1, table_neighbor[i][0]+1, table_neighbor[i][1]+1, table_neighbor[i][2]+1, table_neighbor[i][3]+1);
          prn_jmol.printf ("C   %.4f  %.4f  %.4f\n",
                     all_atoms[i][0], all_atoms[i][1],all_atoms[i][2]);
          Data_out.writeUTF("C ");
          Data_out.writeDouble(all_atoms[i][0]);
          Data_out.writeDouble(all_atoms[i][1]);
          Data_out.writeDouble(all_atoms[i][2]);
        }
      }
      for( i=0; i < natom; i++) {
        if (table_amount[i] == 3) {
          prn_table.printf("%4d  %4d: %4d   %4d   %4d\n", table_amount[i], i+1, table_neighbor[i][0]+1, table_neighbor[i][1]+1, table_neighbor[i][2]+1);
          prn_jmol.printf ("C   %.4f  %.4f  %.4f\n",
                     all_atoms[i][0], all_atoms[i][1],all_atoms[i][2]);
          Data_out.writeUTF("C ");
          Data_out.writeDouble(all_atoms[i][0]);
          Data_out.writeDouble(all_atoms[i][1]);
          Data_out.writeDouble(all_atoms[i][2]);
        }
      }
      for( i=0; i < natom; i++) {
        if (table_amount[i] == 2) {
          prn_table.printf("%4d  %4d: %4d   %4d\n", table_amount[i], i+1, table_neighbor[i][0]+1, table_neighbor[i][1]+1);
          prn_jmol.printf ("C   %.4f  %.4f  %.4f\n",
                     all_atoms[i][0], all_atoms[i][1],all_atoms[i][2]);
          Data_out.writeUTF("C ");
          Data_out.writeDouble(all_atoms[i][0]);
          Data_out.writeDouble(all_atoms[i][1]);
          Data_out.writeDouble(all_atoms[i][2]);
        }
      }
      for( i=0; i < natom; i++) {
        if (table_amount[i] == 1) {
          prn_table.printf("%4d  %4d: %4d\n", table_amount[i], i+1, table_neighbor[i][0]+1);
          prn_jmol.printf ("C   %.4f  %.4f  %.4f\n",
                     all_atoms[i][0], all_atoms[i][1],all_atoms[i][2]);
          Data_out.writeUTF("C ");
          Data_out.writeDouble(all_atoms[i][0]);
          Data_out.writeDouble(all_atoms[i][1]);
          Data_out.writeDouble(all_atoms[i][2]);
        }
      }

      prn_table.close();
      Data_out.close();

    }
    catch(IOException e){
      System.out.println("Error reading input file");
    }
  }
}
