/**
 * <b>Vigenere</b> - A Java implimentation of 
*/
public class Vigenere {
  // Alphabet
  private String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  private char[] dblALPHA;
  private int    lenALPHA;

  // Keyword used to encrypt or decrypt text.
  private String KEYWORD  = "BELLASO";
  private int[]  KEYOFFSET;
  private int    lenKEY;

  public Vigenere() { /* Default Constructor */ }

  public Vigenere(String alphabet) {
    setAlphabet( alphabet );
  }

  public Vigenere(String alphabet, String keyword) {
    setAlphabet( alphabet );
    setKeyword( keyword );
  }

  /**
   * <b>encodeVigenere</b>
   *
   * @return  
  */
  public String encodeVigenere(String plainText) throws Exception {
    return doVigenere(plainText, 'e');
  }

  public String encodeVigenere(String plainText, String keyword) throws Exception {
    setKeyword( keyword );
    return encodeVigenere( plainText );
  }

  public String encodeVigenere(String plainText, String keyword, String alphabet) throws Exception {
    setAlphabet( alphabet );
    return encodeVigenere( plainText, keyword );
  }

  /**
   * <b>decodeVigenere</b>
   *
   * @return  
  */
  public String decodeVigenere(String cipherText) throws Exception {
    return doVigenere(cipherText, 'd');
  }

  public String decodeVigenere(String cipherText, String keyword) throws Exception {
    setKeyword( keyword );
    return decodeVigenere( cipherText );
  }

  public String decodeVigenere(String cipherText, String keyword, String alphabet) throws Exception {
    setAlphabet( alphabet );
    return decodeVigenere( cipherText, keyword );
  }

  private String doVigenere(String text, char ende) throws Exception {
    initializeVigenere();

    // Create array for output.
    char[] out = new char[ text.length() ];

    // For each character to code, run Caesar.
    int i=0, j=0;
    for( char c : text.toCharArray() ) {
      out[j++] = caesar( KEYOFFSET[i++], c, ende );
      if( i >= lenKEY ) { i=0; }
    }

    // Return output as String.
    return new String(out);
  }

  private char caesar( int keyOffset, char c, char ende ) {
    // Find the current character in the ALPHABET.
    int tOffset = ALPHABET.indexOf( (int)c );

    // If it wasn't in the ALPHABET, just pass it through.
    // !  Security-wise, this is bad. However, Vigenere shouldn't  !
    // !  be used for serious security anyway.                     !
    if( tOffset == -1 ) { return c; }

    // Otherwise, encode/decode it as appropriate.
    if( ende == 'e' ) {
      return dblALPHA[tOffset + keyOffset];
    } else {
      return dblALPHA[lenALPHA + tOffset - keyOffset];
    }
  }

  private void initializeVigenere() throws Exception {
    // Store ALPHABET and KEYWORD length.
    lenALPHA = ALPHABET.length();
    lenKEY   = KEYWORD.length();

    // Create dblALPHA to make encryption/decryption easy.
    dblALPHA = (ALPHABET + ALPHABET).toCharArray();

    // Create KEYOFFSET array from KEYWORD.
    int i = 0;
    KEYOFFSET = new int[ lenKEY ];
    for( char c : KEYWORD.toCharArray() ) {
      // Find the location of each KEYWORD character in the ALPHABET.
      // Save these values for the encoding/decoding routine.
      KEYOFFSET[i++] = ALPHABET.indexOf( (int)c );

      // While we are here, see if the KEYWORD fits the ALPHABET.
      if( KEYOFFSET[i-1] == -1 ) {
        throw new Exception("KEYWORD contains character(s) that are not in ALPHABET!");
      }
    }
  }

  // Accessors.
  public String getAlphabet() { return ALPHABET; }
  public String getKeyword()  { return KEYWORD;  }

  // Mutators.
  public void setAlphabet(String alphabet) { ALPHABET = alphabet; }
  public void setKeyword(String keyword) { KEYWORD = keyword; }
}

// EOF
