import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.awt.image.*;
import com.cnn.io.*;


public class Isotopenlijst
  extends JPanel
  implements ActionListener{
  static JFrame frame;
  JPanel pnl1;
  JMenu menuFile;
  JMenu menuView;
  Vector vElements= new Vector();
  static int FIRSTMASSINDEX= 0;
  Image img;
  //----------------------------------------------------------------------------

  Isotopenlijst(){
    loadTable();
    frame= new JFrame("Isotopenlijst");
    createMenu();
    frame.getContentPane().setLayout(new BorderLayout());
    frame.addWindowListener(new WindowAdapter(){
      /** Als je het window sluit, wil je dat het programma stopt. */
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
    });
    addVisibleElements();
    frame.getContentPane().add(this, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
    draw(pnl1);
    frame.pack();
  }
  //----------------------------------------------------------------------------

  void loadTable(){
    //Vector vLines= new Vector();
    //vLines.add("0.n(neutron) 1");
    //vLines.add("1.H(Waterstof) 1,2,3(B-)");
    //vLines.add("2.He(Helium) 3,4,6(B-)");
    //vLines.add("3.Li(Lithium) 6,7,8(B-)");
    //vLines.add("4.Be(Beryllium) 7(K),8(A),9,10(B-)");
    //vLines.add("5.B(Boor) 8(B+),10,11,12(B-/G)");
    //vLines.add("6.C(Koolstof) 10(B+),12,13,14(B-)");
    //String[] asEl= (String[]) vLines.toArray(new String[0])*/;
    String[] asEl= null;
    String sFile= this.getClass().getName() + ".txt";
    try{
      int nBytes= (int) new File(sFile).length();
      char[] aBuf= new char[nBytes];
      new FileReader(sFile).read(aBuf);
      StringTokenizer stLines= new StringTokenizer(new String(aBuf), "\n");
      asEl= new String[stLines.countTokens()];
      for (int i= 0; i < asEl.length; i++){
        asEl[i]= stLines.nextToken();
      }
    } catch(Exception e){
      System.err.println("Storing bij het verwerken van " + sFile);
      System.exit(1);
    }
    for (int iEl= 0; iEl < asEl.length; iEl++){
      String sEl= asEl[iEl];
      int i1= sEl.indexOf(".");
      int i2= sEl.indexOf("(");
      int i3= sEl.indexOf(")");
      Element e= new Element(
          Integer.parseInt(sEl.substring(0, i1)),
          sEl.substring(i1 + 1, i2),
          sEl.substring(i2 + 1, i3));
      vElements.add(e);
      StringTokenizer stI= new StringTokenizer(sEl.substring(i3 + 1), ",");
      while (stI.hasMoreTokens()){
        String sI= stI.nextToken().trim();
        if (sI.equals("")){
          continue;
        }
        int iMass;
        String sDecay;
        if (sI.indexOf("(") >= 0){
          iMass= Integer.parseInt(sI.substring(0, sI.indexOf("(")));
          sDecay= sI.substring(sI.indexOf("("), sI.length());
        } else{
          iMass= Integer.parseInt(sI);
          sDecay= null;
        }
        e.addIsotope(iMass).setDecay(sDecay);
      }
    }
  }

  //----------------------------------------------------------------------------
  void createMenu(){
    JMenuBar bar= new JMenuBar();
    menuFile= new JMenu("Bestand");
    menuFile.setMnemonic(java.awt.event.KeyEvent.VK_B);
    addMenuItem(menuFile, "Herladen");
    menuFile.addSeparator();
    addMenuItem(menuFile, "Opslaan");
    menuFile.addSeparator();
    addMenuItem(menuFile, "Sluiten");
    menuView= new JMenu("Beeld", true);
    menuView.setMnemonic(java.awt.event.KeyEvent.VK_D);
    //for (int i= 0; i < vElements.size(); i+=5){
    //  addMenuItem(menuView, ((Element) vElements.get(i)).toString());
    //}
    addMenuItem(menuView, "Wit");
    addMenuItem(menuView, "Lichtgrijs");
    addMenuItem(menuView, "Donkergrijs");
    addMenuItem(menuView, "Zwart");
    bar.add(menuFile);
    bar.add(menuView);
    frame.setJMenuBar(bar);
  }
  //----------------------------------------------------------------------------

  void addMenuItem(JMenu menu, String sItem){
    JMenuItem item= new JMenuItem(sItem);
    //item.setMnemonic(java.awt.event.KeyEvent.VK_);
    item.addActionListener(this);
    menu.add(item);
  }
  //----------------------------------------------------------------------------

  /**
   *  Hier maken we alle zichtbare elementen op dit frame.
   */
  void addVisibleElements(){
    setLayout(new BorderLayout());
    pnl1= new JPanel();
    pnl1.setPreferredSize(new Dimension(500,500));
    pnl1.setLayout(new BorderLayout());
    add(pnl1, BorderLayout.CENTER);
  }
  //----------------------------------------------------------------------------

  public void actionPerformed(ActionEvent e){
    Object o= e.getSource();
    if (o instanceof JMenuItem){
      String sCmd= ((JMenuItem) o).getText();
      if (sCmd.equals("Sluiten")){
        System.exit(0);
      } else if (sCmd.equals("Herladen")){
        loadTable();
        draw(pnl1);
      } else if (sCmd.equals("Opslaan")){
        savePng();
      } else if (sCmd.equals("Lichtgrijs")){
        Isotope.GRAY_MIN= Color.GRAY.getRed();
        draw(pnl1);
      } else if (sCmd.equals("Donkergrijs")){
        Isotope.GRAY_MIN= 64;
        draw(pnl1);
      } else if (sCmd.equals("Zwart")){
        Isotope.GRAY_MIN= 0;
        draw(pnl1);
      } else if (sCmd.equals("Wit")){
        Isotope.GRAY_MIN= 255;
        draw(pnl1);
      }
      //} else if (sCmd.indexOf(". ") > 0){
      //  int iMass= Integer.parseInt(sCmd.substring(0, sCmd.indexOf(".")));
      //  Element el= (Element) vElements.get(iMass);
      //  FIRSTMASSINDEX= el.getFirstMassIndex() - 1;
      //  draw(pnl1);
      //}
    }
  }
  //----------------------------------------------------------------------------

  public static void main(String[] asArg){
    Isotopenlijst lijst= new Isotopenlijst();
  }
  //----------------------------------------------------------------------------

  void savePng(){
    try{
      FileOutputStream fosPng= new FileOutputStream("Isotopenlijst.png");
      BufferedImage BufImg= toBufferedImage(img);
      PngEncoderB pngEnc= new PngEncoderB(BufImg, PngEncoder.NO_ALPHA, PngEncoder.FILTER_NONE, 9);
      byte[] abBytes= pngEnc.pngEncode(false);
      fosPng.write(abBytes);
      fosPng.flush();
      fosPng.close();
    } catch(Exception e){
      e.printStackTrace();
    }
  }
  //----------------------------------------------------------------------------
  BufferedImage toBufferedImage(Image image){
    BufferedImage bufferedImage = new BufferedImage(
        image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
    // Copy image to buffered image.
    Graphics g = bufferedImage.createGraphics();
    // Clear background and paint the image.
    g.setColor(Color.white);
    g.fillRect(0, 0, image.getWidth(null), image.getHeight(null));
    g.drawImage(image, 0, 0, null);
    g.dispose();
    return bufferedImage;
  }
  //----------------------------------------------------------------------------

  /**
   *  Teken alles op het gegeven paneel
   */
  void draw(JPanel p){
    int iImgHeight= Element.MARGIN_TOP + 145*(Isotope.MARGIN + Isotope.HEIGHT);
    int iImgWidth= Element.MARGIN_LEFT + 34 *(Isotope.MARGIN + Isotope.WIDTH);
    if (img==null){
      img= this.createImage(iImgWidth, iImgHeight);
      JLabel lbl= new JLabel();
      ImageIcon icon= new ImageIcon(img);
      lbl.setIcon(icon);
      //p.add(lbl, BorderLayout.CENTER);
      p.add(new JScrollPane(lbl), BorderLayout.CENTER);
    }
    Graphics g= img.getGraphics();
    g.setColor(new Color(Isotope.GRAY_MIN, Isotope.GRAY_MIN, Isotope.GRAY_MIN));
    g.fillRect(0, Element.MARGIN_TOP,
        Element.MARGIN_LEFT - 1, 10000 - Element.MARGIN_TOP);
    g.fillRect(Element.MARGIN_LEFT, Element.MARGIN_TOP,
        1600 - Element.MARGIN_LEFT, 10000 - Element.MARGIN_TOP);

    int iTextColor= Isotope.GRAY_MIN < 255 
        ? Isotope.GRAY_MIN + (255 - Isotope.GRAY_MIN) / 2 
        : 128;
    Color clrText= new Color(iTextColor, iTextColor, iTextColor);
    for (int i= 1; i < 300; i++){
      g.setColor(clrText);
      int y= Element.MARGIN_TOP + (Isotope.HEIGHT/2 + Isotope.MARGIN/2) * i;
      String sTitle= "" + i;
      g.drawString(sTitle, Element.MARGIN_LEFT/2 - (9*sTitle.length())/2,
          y + 6);
      if (i%5==0){
        g.setColor(clrText);
        g.drawLine(Element.MARGIN_LEFT, y, iImgWidth, y);
        for(int n= 10; n < 100; n+=10){
          String sMass= "" + i;
          int x= Element.MARGIN_LEFT + (Isotope.WIDTH/2 + Isotope.MARGIN/2) * n;
          g.drawString(sMass, x + 1 - (9*sMass.length())/2, y - 1);
        }
      }
    }
    for (int i= 0; i < vElements.size(); i++){
        ((Element) vElements.get(i)).draw(g);
    }
    p.repaint();
  }
  //----------------------------------------------------------------------------

} // class Isotopenlijst
//------------------------------------------------------------------------------

class Element{
  static int MARGIN_TOP= 0;
  static int MARGIN_LEFT= 200;
  static int FONTSIZE= 12;
  int nProtons;
  String sShortName;
  String sName;
  Vector vIsotopes= new Vector();
  //--------------------------------------------------------------------------

  Element(int nProtons, String sShortName, String sName){
    this.nProtons= nProtons;
    this.sShortName= sShortName;
    this.sName= sName;
  }
  //--------------------------------------------------------------------------
  Isotope addIsotope(int iMass){
    Isotope i= new Isotope(this, iMass);
    vIsotopes.add(i);
    return i;
  }
  //--------------------------------------------------------------------------
  int getFirstMassIndex(){
    return ((Isotope) vIsotopes.get(0)).iMass;
  }
  //--------------------------------------------------------------------------
  void draw(Graphics g){
    for (int i= 0; i < vIsotopes.size(); i++){
      ((Isotope) vIsotopes.get(i)).draw(g);
    }
  }
  //--------------------------------------------------------------------------
  public String toString(){
    return "" + nProtons + ". " + sName;
  }
  //--------------------------------------------------------------------------
} // class Element
//----------------------------------------------------------------------------

class Isotope{
  static int WIDTH= 32;
  static int HEIGHT= 32;
  static int FONTSIZE= 12;
  static int MARGIN= 6;
  static int GRAY_MIN= Color.GRAY.getRed();
  Element e;
  int iMass;
  String sDecay;
  //--------------------------------------------------------------------------
  Isotope(Element e, int iMass){
    this.e= e;
    this.iMass= iMass;
  }
  //--------------------------------------------------------------------------
  void setDecay(String sType){
    this.sDecay= sType;
  }
  //--------------------------------------------------------------------------
  void draw(Graphics g){
    if (iMass <= Isotopenlijst.FIRSTMASSINDEX){
      return;
    }
    /* bereken het neutronensurplus, voor de horizontale coordinaat */
    int nXn= iMass - 2 * e.nProtons;
    int x= Element.MARGIN_LEFT + (WIDTH/2 + MARGIN/2) * nXn;
    int y= Element.MARGIN_TOP + (HEIGHT/2 + MARGIN/2) * iMass;
    //g.setClip(Element.MARGIN_LEFT + MARGIN + WIDTH, 0, 1600, 10000);
    if (sDecay==null){
      if (Isotope.GRAY_MIN==255){
        g.setColor(Color.BLACK);
      } else{
        g.setColor(Color.WHITE);
      }
    } else{
      if (sDecay.indexOf("/") >= 0){
        sDecay= sDecay.substring(0, sDecay.indexOf("/"));
        // laat (andere) isomere toestanden buiten beschouwing
      }
      if (sDecay.endsWith("(")){ // eerste toestand stabiel
        if (Isotope.GRAY_MIN==255){
          g.setColor(Color.BLACK);
        } else{
          g.setColor(Color.WHITE);
        }
      } else{ // standaard
        if (Isotope.GRAY_MIN==255){
          g.setColor(Color.WHITE); 
        } else{
          g.setColor(new Color(GRAY_MIN, GRAY_MIN, GRAY_MIN));
        }
      }
      if (sDecay.indexOf(":") >= 0){
        String s1= sDecay;
        if (s1.endsWith(")")){
          s1= s1.substring(0, s1.length() - 1);
        }
        s1= s1.substring(s1.indexOf(":") + 1);
        // halfwaardetijd gegeven in ps, ns, us, ms, s, m, h, d, y
        double fT= 0; // halfwaardetijd in seconden
        String[] asUnit= {"ps","ns","us","ms","s","m","h","d","y"};
        double[] afUnit= {1E-12, 1E-9, 1E-6, 1E-3, 1, 60, 3.6E3, 8.64E4, 3.1536E7};
        for (int i= 0; i < asUnit.length; i++){
          if (s1.endsWith(asUnit[i])){
            String sTime= s1.substring(0, s1.length() - asUnit[i].length()).trim();
            fT= afUnit[i] * Double.parseDouble(sTime);
            break;
          }
        }
        if (fT==0){
          System.err.println("Onbegrijpelijke halfwaardetijd: '" + s1 + "'");
        }
        //int iGray= (int) (6.7 * Math.log(fT));
        double fScale= 6.7 * (255-Color.GRAY.getRed())/255.0;
        int iGray= GRAY_MIN + Math.max(0, (int) (fScale * Math.log(fT)));
        if (GRAY_MIN==255){
          iGray= Math.max(0, 255 - (int) (6.7 * Math.log(fT)));
        }
        if (iGray > 255){
          iGray= 255;
        }
        g.setColor(new Color(iGray, iGray, iGray));
      }
    }
    int[] ax= {x - WIDTH/2, x         , x+WIDTH/2, x         };
    int[] ay= {y          , y-HEIGHT/2, y        , y+HEIGHT/2};
    g.fillPolygon(ax, ay, 4);
    g.setColor(Color.BLACK);
    g.drawPolygon(ax, ay, 4);
    //if ((sDecay+"").indexOf("G")>=0){ // niet goed ingevuld
    //  int[] ax2= {x - WIDTH/2 - 1, x         , x+WIDTH/2+1, x         };
    //  int[] ay2= {y           , y-HEIGHT/2-1, y        , y+HEIGHT/2+1};
    //  g.setColor(new Color(255,255,192));
    //  g.drawPolygon(ax2, ay2, 4);
    //}
    if ((sDecay+"").indexOf("2A")>=0){
      int[] ax2= {x              , x + WIDTH/3 , x - WIDTH/3};
      int[] ay2= {y - HEIGHT/2   , y - HEIGHT/4+HEIGHT/12, y - HEIGHT/4+HEIGHT/12};
      g.setColor(new Color(191,255,255));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("A")>=0){
      int[] ax2= {x              , x + WIDTH/4 , x - WIDTH/4};
      int[] ay2= {y - HEIGHT/2   , y - HEIGHT/4, y - HEIGHT/4};
      g.setColor(new Color(191,255,255));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("2B-")>=0){
      int[] ax2= {x - WIDTH/2, x - WIDTH/2 + WIDTH/6 +2, x - WIDTH/2 + WIDTH/6 +2};
      int[] ay2= {y          , y - HEIGHT/6 -2, y + HEIGHT/6 +2};
      g.setColor(new Color(255,191,191));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("B-")>=0){
      int[] ax2= {x - WIDTH/2, x - WIDTH/2 + WIDTH/6 , x - WIDTH/2 + WIDTH/6};
      int[] ay2= {y          , y - HEIGHT/6, y + HEIGHT/6};
      g.setColor(new Color(255,191,191));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("B+")>=0){ // gaat altijd gepaard met K hieronder...
      int[] ax2= {x + WIDTH/2, x + WIDTH/2 - WIDTH/6 - 1, x + WIDTH/2 - WIDTH/6 - 1};
      int[] ay2= {y          , y - HEIGHT/6 - 1, y + HEIGHT/6 + 1};
      g.setColor(new Color(191,255,191));
      g.fillPolygon(ax2, ay2, 3);
      //g.setColor(Color.BLACK);
      //g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("K")>=0){
      int[] ax2= {x + WIDTH/2, x + WIDTH/2 - WIDTH/6, x + WIDTH/2 - WIDTH/6};
      int[] ay2= {y          , y - HEIGHT/6, y + HEIGHT/6};
      g.setColor(new Color(191,255,191));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("P")>=0){ // proton-emissie
      int[] ax2= {x + WIDTH/4,  x + WIDTH/4, x};
      int[] ay2= {y - HEIGHT/4, y, y - HEIGHT/4};
      g.setColor(new Color(191,255,223));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("N")>=0){ // neutron-emissie
      int[] ax2= {x - WIDTH/4, x - WIDTH/12, x - WIDTH/4};
      int[] ay2= {y - HEIGHT/4, y - HEIGHT/4, y-HEIGHT/12};
      g.setColor(new Color(191,191,255));
      g.fillPolygon(ax2, ay2, 3);
      g.setColor(Color.BLACK);
      g.drawPolygon(ax2, ay2, 3);
    }
    if ((sDecay+"").indexOf("S")>=0){ // Spontanious Fission (spontane kernsplijting)
      g.setColor(Color.RED);
      g.drawLine(x-WIDTH/4, y-HEIGHT/4, x+WIDTH/4, y+HEIGHT/4);
      g.drawLine(x-WIDTH/4, y+HEIGHT/4, x+WIDTH/4, y-HEIGHT/4);
    }
    if (GRAY_MIN==255){
      g.setColor(Color.WHITE);
    } else{
      g.setColor(Color.BLACK);
    }
    String sTitle= "" + e.sShortName;
    g.drawString(sTitle, x + 1 - (9*sTitle.length())/2, y + 6);
    g.setClip(null);
  }
  //--------------------------------------------------------------------------
} // class Isotope
//----------------------------------------------------------------------------

