// © copyright 2019 
// free for educational and development uses
//package com.thebibleinthebible
// It takes about 15 minutes the first time it is run because it is 
// downloading the entire Human DNA off the internet,
// but skips this part once it sees the created files.
// The arguments at the end of your call are the words to search.
// For example to search for the string "God made the heaven and the earth."
// java verify God made the heaven and the earth
// Files halves.htm and words.htm are created.
import java.io.*;
import java.util.*;
import java.net.*;
import java.util.zip.*;
//_____________________________________________________________
public class verify
{ 
   StringBuffer bufall = new StringBuffer();
   StringBuffer bufout = new StringBuffer();
   int count = 0;
   int[] conv = new int[256];
   int[] conv2 = new int[256];
   byte[][] file21 = new byte[26][];
   byte[] file;
   int max = 1000;
//_____________________________________________________________
public static final void main(String[] args) throws Exception
{
   verify bnk = new verify();
   bnk.start(args);
}
//_____________________________________________________________
verify() throws Exception 
{
}
//___________________________________________________________________________
void start(String[] args) throws Exception
{
   long t1 = System.nanoTime();
   makedir("gz");
   makedir("file");
   makedir("txt");
   makedir("ltr");
   for (int i = 1; i <= 25; i++)
   {
      System.out.print(i + " ");
      String name = Integer.toString(i);
      if (i == 23) name = "X";
      else if (i == 24) name = "Y";
      else if (i == 25) name = "MT";
      doall(name);
   }
   appendall();
   file = getBytes("ltr/chr.ltr");
   for (int i = 1; i <= 25; i++)
   {
      String str = Integer.toString(i);
      if (i == 23) str = "X";
      if (i == 24) str = "Y";
      if (i == 25) str = "MT";
      file21[i] = getBytes("ltr/chr" + str + ".ltr");
   } 
  String wd = "BRAJYO BRA ALHYM AO HJMYM VAO HARE";
  if (args.length > 0)
  {
      wd = "";
      for (int i = 0; i < args.length; i++)
      {
         if (i > 0) wd += " ";
         wd += args[i];
      }
   }
   wd = wd.toUpperCase();
   System.out.println("");
   halves(wd);
   System.out.println("");
   find(wd);
   long t2 = System.nanoTime();
   System.out.println("seconds = " + ((t2-t1)/1e9));
}
//___________________________________________________________________________
void doall(String name) throws Exception
{
   getit(name);
   gunzipit(name);
   tofile(name);
   amino(name);
}
//___________________________________________________________________________
void getit(String name) throws Exception
{
   if (fileexists("gz/chr" + name + ".gz")) return;
   String name2 = name;
   byte[] bb = name.getBytes();
   if (name.length() == 1)
   {
      if ((bb[0] >= '1') & (bb[0] <= '9')) name2 = "0" + name;
   }
   String namein = "ftp://ftp.ncbi.nih.gov/genomes/Homo_sapiens/CHR_" + name2 + "/hs_ref_GRCh38.p12_chr" + name + ".fa.gz";
   byte[] bb2 = getUrlBytes(namein);
   saveBytes("gz/chr" + name + ".gz",bb2);
}
//___________________________________________________________________________
byte[] getUrlBytes(String name) throws Exception
{
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   InputStream is = null;
   URL url = new URL(name);
   is = url.openStream ();
   byte[] byteChunk = new byte[4096]; 
   int n;
   while ( (n = is.read(byteChunk)) > 0 ) 
   {
      baos.write(byteChunk, 0, n);
   }
   is.close(); 
   byte[] bb = baos.toByteArray();
   return(bb);
}
//___________________________________________________________
public void gunzipit(String name)
{
   if (fileexists("txt/chr" + name + ".txt")) return;
   byte[] buffer = new byte[1024];
   try
   {
      GZIPInputStream gzis = new GZIPInputStream(new FileInputStream("gz/chr" + name + ".gz"));
      FileOutputStream out =  new FileOutputStream("txt/chr" + name + ".txt");
       int len;
      while ((len = gzis.read(buffer)) > 0) 
      {
         out.write(buffer, 0, len);
      }
      gzis.close();
      out.close();
   }
   catch(IOException ex)
   {
      ex.printStackTrace();   
   }
} 
//___________________________________________________________________________
void tofile(String name)
{
   if (fileexists("file/chr" + name + ".file")) return;
   StringBuffer buf = new StringBuffer();
   String full = "txt/chr" + name + ".txt";
   int[] count = new int[256];
   String[] file = getFile(full).split("\r\n");
   int count2 = 0;
   for (int i = 0; i < file.length; i++)
   {
      if (file[i].indexOf("ref") >= 0)
      {
         if (isdiv(count2+1,3))
         {
            buf.append("N");
         }
         else if (isdiv(count2+2,3))
         {
            buf.append("NN");
         }
         count2 = 0;
      }
      else
      {
         byte[] bb = file[i].getBytes();
         count2 += bb.length;
         boolean ok = true;
         int j = 0;
         int m = 0;
         StringBuffer buf2 = new StringBuffer();
         for (j = 0; j < bb.length; j++)
         {
            if ((bb[j] == 'A') 
              | (bb[j] == 'C') 
              | (bb[j] == 'G') 
              | (bb[j] == 'N') 
              | (bb[j] == 'T'))
            { 
               buf2.append((char)bb[j]);
            }
            else 
            {
               buf2.append('N');
               ok = false; 
               m = j; 
            }
         }
         String str2 = buf2.toString();
         buf.append(str2 + "");
         bb = str2.getBytes();
         for (j = 0; j < bb.length; j++)
         {
            int bc = bb[j];
            if (bc < 0) bc += 256;
            count[bc]++;
         }
      }
   }
   if (isdiv(count2+1,3))
   {
      buf.append("N");
   }
   else if (isdiv(count2+2,3))
   {
      buf.append("NN");
   }
   saveFile("file/chr" + name + ".file",buf.toString(),false);
}
//___________________________________________________________________________
void amino(String name)
{
   if (fileexists("ltr/chr" + name + ".ltr")) return;
   long t1 = System.nanoTime();
   StringBuffer buf = new StringBuffer();
   String full = "file/chr" + name + ".file";
   int[] count = new int[256];
   byte[] bb = getBytes(full);
   for (int i = 0; i < bb.length; i += 3)
   {
      StringBuffer buf2 = new StringBuffer();
      buf2.append((char)bb[i]);
      if (bb.length > (i+1)) buf2.append((char)bb[i+1]);
      if (bb.length > (i+2)) buf2.append((char)bb[i+2]);
      String look = buf2.toString();
      String s = lookup(look);
      buf.append(s);
   }
   saveFile("ltr/chr" + name + ".ltr", buf.toString(), false);
   long t2 = System.nanoTime();
}
//___________________________________________________________________________
String lookup(String s)
{
   String t = "Z";
   if (s.equals("TTT")) t = "F";
   else if (s.equals("TTC")) t = "F";
   else if (s.equals("TTA")) t = "L";
   else if (s.equals("TTG")) t = "L";
   else if (s.equals("CTT")) t = "L";
   else if (s.equals("CTC")) t = "L";
   else if (s.equals("CTA")) t = "L";
   else if (s.equals("CTG")) t = "L";
   else if (s.equals("ATT")) t = "I";
   else if (s.equals("ATC")) t = "I";
   else if (s.equals("ATA")) t = "I";
   else if (s.equals("ATG")) t = "M";
   else if (s.equals("GTT")) t = "V";
   else if (s.equals("GTC")) t = "V";
   else if (s.equals("GTA")) t = "V";
   else if (s.equals("GTG")) t = "V";
   else if (s.equals("TCT")) t = "S";
   else if (s.equals("TCC")) t = "S";
   else if (s.equals("TCA")) t = "S";
   else if (s.equals("TCG")) t = "S";
   else if (s.equals("CCT")) t = "P";
   else if (s.equals("CCC")) t = "P";
   else if (s.equals("CCA")) t = "P";
   else if (s.equals("CCG")) t = "P";
   else if (s.equals("ACT")) t = "T";
   else if (s.equals("ACC")) t = "T";
   else if (s.equals("ACA")) t = "T";
   else if (s.equals("ACG")) t = "T";
   else if (s.equals("GCT")) t = "A";
   else if (s.equals("GCC")) t = "A";
   else if (s.equals("GCA")) t = "A";
   else if (s.equals("GCG")) t = "A";
   else if (s.equals("TAT")) t = "Y";
   else if (s.equals("TAC")) t = "Y";
   else if (s.equals("TAA")) t = "X";
   else if (s.equals("TAG")) t = "X";
   else if (s.equals("CAT")) t = "H";
   else if (s.equals("CAC")) t = "H";
   else if (s.equals("CAA")) t = "Q";
   else if (s.equals("CAG")) t = "Q";
   else if (s.equals("AAT")) t = "N";
   else if (s.equals("AAC")) t = "N";
   else if (s.equals("AAA")) t = "K";
   else if (s.equals("AAG")) t = "K";
   else if (s.equals("GAT")) t = "D";
   else if (s.equals("GAC")) t = "D";
   else if (s.equals("GAA")) t = "E";
   else if (s.equals("GAG")) t = "E";
   else if (s.equals("TGT")) t = "C";
   else if (s.equals("TGC")) t = "C";
   else if (s.equals("TGA")) t = "X";
   else if (s.equals("TGG")) t = "W";
   else if (s.equals("CGT")) t = "R";
   else if (s.equals("CGC")) t = "R";
   else if (s.equals("CGA")) t = "R";
   else if (s.equals("CGG")) t = "R";
   else if (s.equals("AGT")) t = "S";
   else if (s.equals("AGC")) t = "S";
   else if (s.equals("AGA")) t = "R";
   else if (s.equals("AGG")) t = "R";
   else if (s.equals("GGT")) t = "G";
   else if (s.equals("GGC")) t = "G";
   else if (s.equals("GGA")) t = "G";
   else if (s.equals("GGG")) t = "G";
   return(t);
}
//___________________________________________________________________________
void appendall()
{
   if (fileexists("ltr/chr.ltr")) return;
   System.out.println("\r\ncombine \t");
   for (int i = 1; i <= 22; i++)
   {
      startit(Integer.toString(i));
   }
   startit("X");
   startit("Y");
   startit("MT");
   saveFile("ltr/chr.ltr",bufall.toString(),false);
}
//___________________________________________________________________________
void startit(String name)
{
   System.out.print(name + " ");
   String full = "ltr/chr" + name + ".ltr";
   String file = getFile2(full);
   bufall.append(file);
}
//___________________________________________________________________________
boolean fileexists(String name)
{
   File f = new File(name);
   if(f.exists() && !f.isDirectory()) return(true);
   else return(false);
} 
//___________________________________________________________________________
void makedir(String name) throws Exception
{
   File theDir = new File(name);
   if (!theDir.exists())
   {
      theDir.mkdir();
   }
}   
//___________________________________________________________________________
void halves(String wd)
{   
   wd = wd.replace(" ","");
   int mid = (int)(wd.length() / 2);
   bufout.append("<table border='1'>\r\n");
   bufout.append("<tr><th>number</th><th>letters</th>");
   bufout.append("<th>chromosome</th><th>position</th><th>key</th></tr>\r\n");
   count = 0;
   startit(wd,1,mid);
   count = 0;
   startit(wd,mid+1,wd.length());
   bufout.append("</table>\r\n");
   saveFile("halves.htm",bufout.toString(),false);
}
//___________________________________________________________________________
void startit(String word, int val1, int val2)
{
   for (int i = 1; i <= 25; i++)
   {
      String name = Integer.toString(i);
      if (i == 23) name = "X";
      else if (i == 24) name = "Y";
      else if (i == 25) name = "MT";
      startall(name,word.substring(val1-1,val2));
   }
   System.out.print(count + " ");
}
//___________________________________________________________________________
void startall(String name, String word)
{
   int cnt = 0;
   String full = "ltr/chr" + name + ".ltr";
   byte[] gg = word.getBytes(); 
   byte[] bb = getBytes(full);
   for (int ii = 0; ii < bb.length - gg.length; ii++)
   {
      int i = ii;
      if ((i + gg.length) > bb.length) break;
      boolean ok = true;
      for (int j = 0; j < gg.length; j++)
      {
         
         for (int k = j+1; k < gg.length; k++)
         {
            if (gg[j] == ' ')
            {
            }
            else if (gg[j] == gg[k])
            {
               if (bb[i + j] == bb[i + k])
               {
                  
               }
               else
               {
                  ok = false;
                  break;
               }
            }
            else
            {
               if (bb[i+j] == bb[i+k])
               {
                  ok = false;
                  break;
               }
               else
               {
               }
            }
         }
         if (!ok) break;
      }
      if (ok)
      {
         StringBuffer buf = new StringBuffer();
         for (int m = 0; m < gg.length; m++)
         {
            buf.append((char)bb[i+m]);
         }
         count++;
         bufout.append("<tr><td>" + count + "</td><td>" + convert(word) + "</td>");
         bufout.append("<td>" + name + "</td><td>" + i + "</td>");
         bufout.append("<td>" + buf.toString() + "</td></tr>\r\n");
         String s = name + " ";
         s += buf.toString() + "\r\n";
         saveFile("all.txt",s,true);
         if (cnt++ > 100) break;
      }
   }
}
//___________________________________________________________________________
void find(String wd)
{
   System.out.println(getkey(wd));
}
//___________________________________________________________________________
String getkey(String wd2)
{
   int max = 0;
   int maxnum = 0;
   for (int i = 1; i <= 25; i++)
   {
      String out = check(file21[i], wd2, false);
      String[] out2 = out.split(",");
      int val = Integer.parseInt(out2[0]);
      if (val > max)
      {
         max = val;
         maxnum = i;
      }
      for (int j = 0; j < conv.length; j++)
      {
         conv[j] = 0;
         conv2[j] = 0;
      }
   }
   check(file21[maxnum], wd2, false);
   return(check(file, wd2, true));
}
//___________________________________________________________________________
String check(byte[] file, String wd2, boolean showit)
{
   int itrn = 0;
   StringBuffer buf2 = new StringBuffer();
   buf2.append("<table border='1'>\r\n");
   buf2.append("<tr><th>position</th><th>offset</th><th>amino acids</th><th>Hebrew</th></tr>\r\n");
   String[] words = wd2.split(" ");
   int pos = 0;
   int jold = 0;
   int itr = 0;
   int count = 0;
   int cnt = -1;
   int cnt2 = 1;
   for (int i = 0; i < words.length * max; i++)
   {
      if (cnt++ >= words.length - 1)
      {
         buf2.append("<tr><th colspan='4'>" + cnt2 + "</th></tr>\r\n");
         cnt2++;
         cnt = 0;
      }
      byte[] bb = words[i % words.length].getBytes();
      boolean found = true;
      boolean found2 = false;
      for (int j = pos; j < file.length - bb.length; j++)
      {
         found = true;
         found2 = false;
         for (int k = 0; k < bb.length; k++)
         {
            if (file[j+k] == 'X') found = false;
            if (file[j+k] == 'N') found = false;
            found2 = false;
            if (conv2[bb[k]]!= 0)
            {
               if (conv[file[j+k]] != bb[k]) 
               {
                  found = false;
                  break;
               }
               else
               {
               }
               found2 = true;
            }
            else
            {
               if (conv2[conv[file[j+k]]] > 0)
               {
                  found = false;
                  found2 = false;
                  break;
               }
            }
            if (!found2)
            {
               for (int m = k+1; m < bb.length; m++)
               {
                  if (bb[k] != bb[m])
                  {
                     if (file[j+k] == file[j+m])
                     {
                        found = false;
                        break;
                     }
                   }
                   else
                   {
                      if (file[j+k] != file[j+m])
                      {
                         found = false;
                         break;
                      }
                   }              
               }
            }
            if (!found) break;
         }
         if (found)
         {
            boolean ok2 = true;
            if (!showit)
            {
               if (itr++ < itrn)
               {
                  ok2 = false;   
               }
            }
            if (ok2)
            {
               count++;
               StringBuffer buf = new StringBuffer();
               for (int k = 0; k < bb.length; k++)
               {
                  buf.append((char)file[j + k]);
                  conv[file[j+k]] = bb[k];
                  conv2[bb[k]]++;
               }
               buf2.append("<tr><td>" + j + "</td><td>" + (j - jold) + "</td><td>" + buf.toString() + "</td><td>" + convert(words[i % words.length]) + "</td></tr>\r\n");
               pos = j + bb.length;
               jold = j;
               break;
            }
         }
      }
      if (!found) break;
   }
   buf2.append("</table>\r\n");
   StringBuffer buf3 = new StringBuffer();
   buf3.append("<table border='1'>\r\n");
   buf3.append("<tr><th>letter</th><th>amino acid</th></tr>\r\n");
   for (int i = 0; i < conv.length; i++)
   {
      if (conv[i] > 0)
      {
         buf3.append("<tr><td>" + (char)conv[i] + "</td><td>" + (char)i + "</td></tr>\r\n");
      }
   }
   String key = thekey(conv);
   buf3.append("</table>\r\n");
   saveFile("words.htm",buf3.toString() + buf2.toString(),false);
   return(Integer.toString(cnt2) + "," + key);
}
//___________________________________________________________________________
String thekey(int[] conv)
{
   StringBuffer buf = new StringBuffer();
   for (int i = 'A'; i <= 'Z'; i++)
   {
      if (conv[i] > 0)
      {
         buf.append((char)conv[i]);
      }
      else
      {
         if (i == 'B') buf.append("+");
         else if (i == 'J') buf.append("+");
         else if (i == 'O') buf.append("+");
         else if (i == 'U') buf.append("+");
         else if (i == 'X') buf.append("+");
         else if (i == 'Z') buf.append("+");
         else buf.append(".");
      }
   }
   return(buf.toString());
}
//___________________________________________________________________________
void saveFile(String file, String str, boolean append) 
{
  try
  {
   BufferedWriter out = new BufferedWriter(new FileWriter(file, append));
   out.write(str);
   out.close();
  }
  catch (Exception e)
  {
   System.out.println(e);
  }
}
//___________________________________________________________________________
void saveBytes(String file, byte[] str) 
{

   try (FileOutputStream fos = new FileOutputStream(file)) 
   {
      fos.write(str);
      fos.close(); 
   }
  catch (Exception e)
  {
   System.out.println(e);
  }
}
//___________________________________________________________________________
String getFile(String file) 
{
   StringBuffer buf=new StringBuffer();String str;
  try
  {
   BufferedReader in = new BufferedReader (new FileReader (file));
   while((str=in.readLine())!=null)
   {
      buf.append(str+"\r\n");
   }
   in.close();
  }
  catch (Exception e)
  {
   System.out.println(e);
  }
   return (buf.toString());
}
//___________________________________________________________________________
String getFile2(String file) 
{
   StringBuffer buf=new StringBuffer();String str;
  try
  {
   BufferedReader in = new BufferedReader (new FileReader (file));
   while((str=in.readLine())!=null)
   {
      buf.append(str);
   }
   in.close();
  }
  catch (Exception e)
  {
   System.out.println(e);
  }
   return (buf.toString());
}
//___________________________________________________________________________
byte[] getBytes(String name) 
{
   byte[] b = new byte[0];
  try
  {
   File file = new File(name);
   b = new byte[(int) file.length()];
   FileInputStream fileInputStream = new FileInputStream(file);
   fileInputStream.read(b);
  }
  catch (Exception e)
  {
   System.out.println(e);
  }
   return(b);
}
//__________________________________________________
boolean isdiv(int val, int div)
{
   if (val == 0) return(false);
   double val2 = (double)val / (double)div;
   int val3 = (int)val2;
   if (val2 == val3) 
   {
      //number++;
      return(true);
   }
   return(false);
}
//_____________________________________________________
String convert(String tr)
{
   String out = "";
   byte[] bb = tr.getBytes();
   for (int i = 0; i < bb.length; i++)
   {
      int val = bb[i];
      if (val < 0) val += 256;
      if (val == 65) out += "&#x05d0";
      else if (val == 66) out += "&#x05d1";
      else if (val == 71) out += "&#x05d2";
      else if (val == 68) out += "&#x05d3";
      else if (val == 72) out += "&#x05d4";
      else if (val == 86) out += "&#x05d5";
      else if (val == 90) out += "&#x05d6";
      else if (val == 67) out += "&#x05d7";
      else if (val == 84) out += "&#x05d8";
      else if (val == 89) out += "&#x05d9";
      else if (val == 75) out += "&#x05da";
      else if (val == 75) out += "&#x05db";
      else if (val == 76) out += "&#x05dc";
      else if (val == 77) out += "&#x05dd";
      else if (val == 77) out += "&#x05de";
      else if (val == 78) out += "&#x05df";
      else if (val == 78) out += "&#x05e0";
      else if (val == 83) out += "&#x05e1";
      else if (val == 73) out += "&#x05e2";
      else if (val == 70) out += "&#x05e3";
      else if (val == 70) out += "&#x05e4";
      else if (val == 69) out += "&#x05e5";
      else if (val == 69) out += "&#x05e6";
      else if (val == 81) out += "&#x05e7";
      else if (val == 82) out += "&#x05e8";
      else if (val == 74) out += "&#x05e9";
      else if (val == 79) out += "&#x05ea";
      else out += (char)val;
   }
   return(out);
}
}//__________________________________________________________________________
