import java.awt.*;
import java.awt.event.*;
import javax.swing.*;                                       
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.Highlighter.HighlightPainter;
import javax.swing.text.BadLocationException;


/**
  *
  * Programm zur Kryptoanalyse
  * von monoalphabetischen Substitutionen
  *
  * @version 1.0 from 23.11.2016
  * @author Thomas Schaller
  */

public class BreakVigenere extends JFrame {
  // Anfang Attribute
  private JTextField[] buchstabe;
  
  private JButton jButton1 = new JButton();
  private JButton jBBuchstabe = new JButton();
  private Balkendiagramm bdText = new Balkendiagramm(); 
  private Balkendiagramm bdBruteForce = new Balkendiagramm();
  private Balkendiagramm bdDeutsch = new Balkendiagramm();
      
  private JTextArea jTAKrypto = new JTextArea("");
  private JScrollPane jTAKryptoScrollPane = new JScrollPane(jTAKrypto);
  private JTextArea jTAKlartext = new JTextArea("");
  private JScrollPane jTAKlartextScrollPane = new JScrollPane(jTAKlartext);
  private JLabel jLKryptotext = new JLabel();
  private JLabel jLKlartext = new JLabel();
  private JLabel jLCopyright = new JLabel();
  private JTextArea jTAKorrelation = new JTextArea("");
  private JScrollPane jTAKorrelationScrollPane = new JScrollPane(jTAKorrelation);
  private JSpinner jSpVerschiebung = new JSpinner();
  private SpinnerNumberModel jSpVerschiebungModel = new SpinnerNumberModel(0, 0, 99, 1);
  private JNumberField jNFAnzahlTreffer = new JNumberField();
  private JLabel lVerschiebung = new JLabel();
  private JLabel lAnzahlgleicherBuchstaben = new JLabel();
    // Ende Attribute
    
  public BreakVigenere (String title) {
    super (title);
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    int frameWidth = 702; 
    int frameHeight = 651;
    setSize(frameWidth, frameHeight);
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    Container cp = getContentPane();
    cp.setLayout(null);
    // Anfang Komponenten
    
    jTAKryptoScrollPane.setBounds(16, 24, 665, 105);
    jTAKrypto.setLineWrap(true);
    jTAKrypto.setFont(new Font("Courier New", Font.BOLD, 16));
    jTAKrypto.setText("JMLQMFNSKIOQNXGYZOQEBJLUKXHFCXGVLGBMREAJZCAEKVIFOWJLMFGJLPQZJIYHQQHYJLAFGFLRLQYESTPMHIAWQZFIPPMZMIZGPDOIIIVGTHIIQVKHLVHQOPLNMIKMSWCYKMUIVBREADEQOXLVVMILSMVWYZLVAONSIIVIKVKIVPOIZIEGXHLHCDILKIVPKYAWKTKRIIVQJMRXQZKVHFBVULHRVQYXYMBTKQPYAUSNHLZUSJUJBQTFHRLEKMUIAUTPHXMUTMZGPQXWWVIONINIAONVPIJQTIUWMONWIRLUMIUAMDQIZTWXEKYEXTOELPQNXMZIFEKGOWJONIYDCDVSSCODGTOMMMTKLKMNKRPRLQSRHGPEKMUIUFUHLZMDLJLRBXOGOXMZHYJLAONPBKMDBSYRIONNLHMYKMUDMXTIUOTMXXLBBNAGOWBMHIUDCYTGOWBQTESTPMHIAMVEKMUIZFGFBPINKVGYOQNIUYVPYSHPTQBIYJONGVLRIXVLHFMFKEBWHGTYADMZJETMBQXJHRLQXHPIXDUKYIAEOZLTWXEESTPMHIAMAONIJLQRLVPIZGTKHFMDKWDEZZUGOIQZLIZXMEBIYJITXIUSPZKWJLTEYISHQQYIYACDJIPQRMNVCSUUZESMMZOWJLMZQVFTBARSNIVSOSCEVNGXAMAFGFLPTMYSJEQZLSYQMUTIZZWYBIYWKTRWZPMDLVLMHGCLSIVPKRRIVZCSYXAAJIYIQZKWRIVZYEADMEBSYKMEILSEOQTKLVVQARKOZKVXVKZMVLPWKTYGOAIONHHPMUILADCQXVHXMZCYYHMZJETETEREAIQZOWJLMEORUWXDILLFMZAXGXEUKFLMABOISWEQOWLZQDZZAMWYTMHTIDKRAETXKWNIPAXGOXLQXXJLBUMOLMBPOIIYKTYXHFMZJIZOMZTWHXHQYFLWBUSQLRLUKVLMPQTJVPOQORKIZPOICIZEILPILQTIUETBNEIIBQGYZHMDZEIYTMGYZKMINPAA\nMDJIUQAEKRZMVPGPSIDQXFYECONXHPAAKMUQIXHIUYBLZAVVLQTLPIZZGGOOTMXXLBBNAGOWBMHIUWWNKKPRVFSEUAQQJIYZWZBSYRMENEUHMXZWPGPEUQPXCYKMUIXQXMVHQEILLTWXEESTPMHIAMAONIZYJEZMAYBUURTMBUSFLMABOISIQZKVWIZUUHLZWZCLYIVPZVPXPQSMBWAUILHYNHKVZGPAHIUIAFGRKEZPGPWLINKXLFMEILYRSFKESWWPOINIEANRAIIXVLHFMFOWJLMDKMOIVRUPNILQXFBGPEZEIIVHKVDIVPKXLFMXREZSJQXIPXAHKVDVNQRXLETBNEIIBQJMLIZMRPLVLUTKZMVHUPBXWDOWJLETRXLFMUJIUQWZUESTPMHIAMAONIUWCNYXPXCFOSUWUQZLVHMZCEYHQQYWJLWZYIPXTMTKLQJXOGOKZGTHZXHXOGOLIFZIKMMEHIYIQFYMTNITXESWWXGRNIDAXXYMBTKQPYAGTHIITXGWVHMDOXHPQQTMZGPQMISIPDZISIWZHEAXQEZEHPJQXXPIUBLSOPMZKVZGPXAKCSZPOIHPXTGFLXMZGGONMIKMSWLDKMVHMDBMLVEDZIYRHGCIJLAQRRHPAYKGOEVUYGOIATOPMWUUZXLPPMZXLIZTOIYDCPOIUEKTOLTFMZGRUXMMRFLVBUYGOIQNKIYJCZJIUIQZKGOMNRXMLVAONIPFMNKWAIPQTHGYUQOWAECEFALMZGTHLRUQZESPAONIPFMZJMLECRKMUIZSKQLMVEGQLRIONWLWQFFIUYVPYSCIZNARKIVEORKHIEYWPGPPOIRPMUTIYIIGLHLVODKVLRLDKLLRSMTRUEPQFYLMVVGLYLCZJIYXABZIYMUVGLYZMDGPSKMYKMUIZFKHLVVQGTVPQFGRPWKTKKLPMTXXLKQABEURQNGXAMAFGHLPTMVSYXIMRFLVBUYZLVEDLISXMMRTOEJQZIBRLNKPSEAAYOLRVIUVAYVPYGOYNPOI\nWSTKGPWLINKXPWKTKGOMNRXMLVCZMQPXDQXAYJMXZITETBNEIIBGTHZGPXYWLPPUKVGYEGXHLETNKVAMAEILLMJQHIUYBLZHPIVMILQILQSFBGPEZEIIVLAHYIPQTAHVQYPEOVODOJMHMDLVHRHAYIIPIUYIKIDUMIUVMBUVAEAUJILECRARKWKTRYNZWDYXHXBPKVHPJQXXPWKTKMIILUKXHFCXGVLGBMJIZXZUZLLQQGYDBZMDCIUHMZJEIIQMHIYEVPKVZETEOQVVQSORHPDQXAYJMXZIHPXTGFLXMQORGYBDGKLRLUKWLVSDETASODGTOMAONWAEZWKZVVAONPHKDUMIUVMEMIYMMFORKIVRUPNIVPKRQEPDNYUHMDZIUMVHKVNIAEKROIQFARKHQQAVZTZZMPPGPHURAVQFNITMCEBSYKMEILSEOQTITIBTUHLACDJIBRBQXHLQVMSIUZQSKRYIKTOJMVMNKOHRVF");
    jTAKrypto.addKeyListener(new KeyAdapter() { 
    public void keyTyped(KeyEvent evt) { 
    jTAKrypto_KeyTyped(evt);
    }
    });
    cp.add(jTAKryptoScrollPane);
       
    jTAKlartextScrollPane.setBounds(16, 480, 665, 105);
    jTAKlartext.setLineWrap(true);
    jTAKlartext.setFont(new Font("Courier New", Font.BOLD, 16));
    cp.add(jTAKlartextScrollPane);
    jLKryptotext.setText("Kryptotext");
    jLKryptotext.setBounds(16, 3, 110, 20);
    cp.add(jLKryptotext);
    jLKlartext.setText("Klartext");
    jLKlartext.setBounds(16, 456, 110, 20);
    cp.add(jLKlartext);
    jLCopyright.setText("(cc) Schaller (ZPG Informatik) - V1.0 (2017)");
    jLCopyright.setBounds(128, 584, 419, 33);
    jLCopyright.setHorizontalAlignment(SwingConstants.CENTER);
    jLCopyright.setFont(new Font("Dialog", Font.PLAIN, 12));
    cp.add(jLCopyright);

    // -------------------------------- Tab 1 ---------------------------------------------
    JPanel tab1 = new JPanel();
    tab1.setLayout(null);
    
    jSpVerschiebung.setBounds(192, 40, 41, 25);
    jSpVerschiebung.setValue(1);
    jSpVerschiebung.setModel(jSpVerschiebungModel);
    jSpVerschiebung.addChangeListener(new ChangeListener() { 
    public void stateChanged(ChangeEvent evt) { 
        jSpVerschiebung_StateChanged(evt);
    }
    });
    tab1.add(jSpVerschiebung);
    
    lVerschiebung.setBounds(16, 10, 310, 20);
    lVerschiebung.setText("Angriff auf die Schlüssellänge mit Brute Force");
    tab1.add(lVerschiebung);
    JLabel l = new JLabel();
    l.setBounds(14, 80, 320, 100);
    l.setText("<html>Die meisten Schlüsselwörter sind nicht länger als 10 bis maximal 15 Buchstaben. Probiere daher systematisch die Schlüssellänge durch und schaue, ob die Häufigkeitsverteilungen des ersten Teiltextes in etwa dem deutschen Alphabet entspricht. Eine Verschiebung ist dabei erlaubt.</html>");
    tab1.add(l);
    l = new JLabel();
    l.setBounds(16, 40, 162, 20);
    l.setText("Vermutete Schlüssellänge:");
    tab1.add(l);
    
    double[] h2 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    bdBruteForce.setBounds(380,10,300,120);
    bdBruteForce.setHaeufigkeit(h2);
    bdBruteForce.setZeigeDeutsch(false);
    tab1.add(bdBruteForce);
    
    double[] h3 = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    bdDeutsch.setBounds(380,140,300,120);
    bdDeutsch.setHaeufigkeit(h3);
    tab1.add(bdDeutsch);
    
    
    
    // ---------------------------------- Tab 2 -------------------------------
    JPanel tab2 = new JPanel();
    tab2.setLayout(null);
    
    l = new JLabel();
    l.setBounds(16, 10, 310, 20);
    l.setText("Angriff auf die Teiltexte mit Häufigkeitsanalyse");
    tab2.add(l);

    l = new JLabel();
    l.setBounds(380, 10, 300, 25);
    l.setText("Buchstabenhäufigkeit Deutsch");
    tab2.add(l);

    l = new JLabel();
    l.setBounds(16, 40, 300, 25);
    l.setText("Schlüssel");
    tab2.add(l);

    l = new JLabel();
    l.setBounds(16, 100, 300, 100);
    l.setText("<html>Versuche den Schlüssel zu knacken, indem du in jedem Teiltext die Häufigkeitsverteilung der Buchstaben mit der üblichen Häufigkeitsverteilung in deutschen Texten in Einklang bringst.</html>");
    tab2.add(l);

    double[] h = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    bdText.setBounds(380,40,300,180);
    bdText.setHaeufigkeit(h);
    tab2.add(bdText);

    jButton1.setBounds(16, 210, 193, 25);
    jButton1.setText("Entschlüsselung versuchen");
    jButton1.setMargin(new Insets(2, 2, 2, 2));
    jButton1.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent evt) { 
    jButton1_ActionPerformed(evt);
    }
    });
    tab2.add(jButton1);


    
    // Ende Komponenten
    buchstabe = new JTextField[26];
    for (int i = 0; i<26 ;i++ ) {
      buchstabe[i] = new JTextField();
      buchstabe[i].setBounds(16+i*25, 65, 25, 25);
      buchstabe[i].setText("A");
      buchstabe[i].setHorizontalAlignment(SwingConstants.CENTER);
      buchstabe[i].setVisible(false);
      buchstabe[i].addFocusListener(new FocusAdapter() { 
      public void focusGained(FocusEvent evt) { 
      highlightKryptotext(evt);
      }
      });
      buchstabe[i].addKeyListener(new KeyAdapter() {
      public void keyReleased(KeyEvent e) {
      e.consume();
      }
      
      public void keyTyped(KeyEvent e) {
      e.consume();
      }
      
      public void keyPressed(KeyEvent e) {
      JTextField textField = (JTextField) e.getSource();
      String text = textField.getText();
      if ((e.getKeyChar()>='a' && e.getKeyChar()<='z') ||(e.getKeyChar()>='A' && e.getKeyChar()<='Z')) {
      text = ""+e.getKeyChar();
      }
      if (e.getKeyChar()==' ' || e.getKeyChar() == KeyEvent.VK_BACK_SPACE || e.getKeyChar() == KeyEvent.VK_DELETE) {
      text = "";
      
      } // end of if
      textField.setText(text.toUpperCase());
      e.consume();
      if (textField.getText().length()>0) {
        bdText.setVerschiebung((int) textField.getText().charAt(0)-65);
        
      } else {
        bdText.setVerschiebung(0);      
      } // end of if-else
      bdText.repaint();
            
      } // end of if
      
      });
      
      tab2.add(buchstabe[i]);    
    } // end of for
    
    JTabbedPane tabpane = new JTabbedPane
            (JTabbedPane.TOP,JTabbedPane.SCROLL_TAB_LAYOUT );
    tabpane.setBounds(10,140,672,290);
    
    tabpane.addTab("Schritt 1", tab1);
    tabpane.addTab("Schritt 2", tab2);
    cp.add(tabpane);
     
    setResizable(false);
    setVisible(true);
  }
    
    
   
    // Anfang Methoden
  public void jButton1_ActionPerformed(ActionEvent evt) {
    String krypttext = jTAKrypto.getText().toUpperCase();
    String klartext="";
    int c = 0;
    int diff = (Integer) jSpVerschiebung.getValue();
    for (int i=0;i<krypttext.length() ;i++ ) {
      int asc = krypttext.charAt(i);
      if (asc != 10) {
        String z = buchstabe[c%diff].getText().toUpperCase();
        if (z.equals("")) {
          klartext += "*";
        } else {
          int v = (int) z.charAt(0)-65;
          asc = (asc-65-v+26)%26+65;  
          klartext += (char) asc;
        } // end of if
        c++;
      } 
      
    } // end of for
    jTAKlartext.setText(klartext);
  } // end of jButton1_ActionPerformed
    

    
      
  public void highlightKryptotext(FocusEvent evt) {
    int start, diff;
    for (start = 0; start < 26 ; start++) {
      if (buchstabe[start] == evt.getSource()) {
        break;
      } // end of if-else
    } // end of for       
        jBBuchstabe.setText("Buchstabenhäufigkeit Deutsch");

    diff = (Integer) jSpVerschiebung.getValue();
    Highlighter h1 = jTAKrypto.getHighlighter();
    h1.removeAllHighlights();
    int c = 0;
    String krypto = jTAKrypto.getText().toUpperCase();
    double[] h = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    try{
      for (int i=0;i<krypto.length() ;i++) {
        int asc = (int)krypto.charAt(i);
        if (asc!=10) {
          
          if (c%diff == start) {
            h1.addHighlight(i, i+1,
            new DefaultHighlighter.DefaultHighlightPainter(new Color(100,100,255)));    
            if (asc>=65 && asc<=90) {
              h[asc-65]++;
            } 
          } // end of if
          c++;
        } // end of if
      }
      bdText.setHaeufigkeit(h);
      if (buchstabe[start].getText().length()>0) {
        bdText.setVerschiebung((int) buchstabe[start].getText().charAt(0)-65);
        
      } else {
        bdText.setVerschiebung(0);      
      } // end of if-else
      bdText.repaint();
    }   catch(BadLocationException e) {}   
  }
    
      
  public void jSpVerschiebung_StateChanged(ChangeEvent evt) {
    String krypto = jTAKrypto.getText().toUpperCase();
    String krypto2="";
    int diff = (Integer) jSpVerschiebung.getValue();
    Highlighter h1 = jTAKrypto.getHighlighter();
    h1.removeAllHighlights();
    int c = 0; 
    double[] h = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    try{
      for (int i=0;i<krypto.length() ;i++) {
        int asc = (int)krypto.charAt(i);
        if (asc!=10) {
          
          if (c%diff == 0) {
            h1.addHighlight(i, i+1,
            new DefaultHighlighter.DefaultHighlightPainter(new Color(100,100,255)));    
            if (asc>=65 && asc<=90) {
              h[asc-65]++;
            } 
          } // end of if
          c++;
        } // end of if
      }
      bdBruteForce.setHaeufigkeit(h);
         bdBruteForce.repaint();
    }   catch(BadLocationException e) {}   
    
    for (int i=0; i<buchstabe.length ;i++ ) {
      if (i<diff) {
        buchstabe[i].setVisible(true);
      } else {
        buchstabe[i].setVisible(false);
        
      } // end of if-else
    } // end of for
    
  } // end of jSpVerschiebung_StateChanged

  public void jTAKrypto_KeyTyped(KeyEvent evt) {
    //jSpVerschiebung_StateChanged(null);
    
  } // end of jTAKrypto_KeyTyped

  public void jTAKrypto_InputMethodTextChanged(InputMethodEvent evt) {
    jSpVerschiebung_StateChanged(null);
    
  } // end of jTAKrypto_InputMethodTextChanged

  public void jTAKrypto_FocusGained(FocusEvent evt) {
    // TODO hier Quelltext einfügen
    
  } // end of jTAKrypto_FocusGained

      // Ende Methoden
      
  public static void main(String[] args) {
    new BreakVigenere("BreakVigenere");
  }
}
