/******************************* MAIN HEADER **********************************
    Title:       Palindromes
    File:        Palindromes.java
    
    Author:      James D. Skrentny, skrentny@cs.wisc.edu
                 copyright 2000 all rights reserved
    Course:      CS 302: Lectures 1 & 2
    
    Compiler:    CodeWarrior IDE 4.0 (JDK 1.2)
    Platform:    Windows NT 4.0
 **************************** 80 columns wide *********************************/

/**
 * This program determines if a string reads the same forwards and
 * backwards.  Two algorithms are shown and two implementations are
 * done for each algorithm.
 *
 * Bugs: none known
 **/

public class Palindromes {

    public static void main(String args[]) {
    
        // Type 1 examples
        //String s = "mom";
        //String s = "noon";
        //String s = "radar";
        //String s = "rats live on no evil star";
        
        // Type 2 examples (must handle differences in case)
        //String s = "Bob";
        //String s = "Kayak";
        //String s = "Dennis sinned";
        //String s = "Amaryllis sillyrama";
        //String s = "Able was I ere I saw Elba";  // attributed to Napolean B.
        
        // Type 3 examples (must handle case, spacing, and punctuation)
        String s = "A man, a plan, a canal, Panama!"; 
        //String s = "Campus motto: Bottoms up, Mac";
        //String s = "Do geese see God?";
        //String s = "Is it I? It is I!";
        //String s = "Ma is as selfless as I am.";
        //String s = "Was it a car or a cat I saw?";
        //String s = "Cigar? Toss it in the can. It is so tragic.";
        
        // Type 3
        // Clean up punctuation and spacing. 
        s = clean(s);
        // Type 2 and 3
        // Case can be handled by converting to all UPPER or all lowercase.
        // Could also use equalsIgnoreCase() instead of equals() in palindrome
        // testing methods below. 
        s = s.toLowerCase();
        
        // change to desired palindrome tester
        if (palindrome1(s))
            System.out.println(s + " is a palindrome");
        else
            System.out.println(s + " isn\'t a palindrome");

    }
    
    
    // Palindrome testing algorithm 1:
    //     1. create a reversed copy of the original string
    //     2. test if reversed equals original

    /**         
    * This implements algorithm 1 using String objects.
    * @param original the string being tested
    **/
    public static boolean palindrome1 (String original) {
    
        // create the reversed copy
        String reversed = "";
        for (int i = original.length()-1; i >= 0; i--)
            reversed = reversed + original.charAt(i);
            
        // test if reverse equals the original
        return original.equals(reversed);
    }
    
    /**         
    * This implements algorithm 1 using a StringBuffer object.
    * @param original the string being tested
    **/
    public static boolean palindrome2 (String original) {
    
        // create the reversed copy
        StringBuffer reversed = new StringBuffer(original);
        reversed.reverse();
        
        // test if reverse equals the original
        return original.equals(reversed.toString());
    }
    
    // Palindrome testing algorithm 2:
    //     1. check if first and last character are the same
    //     2. and check if the remainder is a palindrome

    /**         
    * This implements algorithm 2 using loops.
    * @param original the string being tested
    **/
    public static boolean palindrome3 (String s) {
        for (int i = s.length()-1, j = 0; i >= j; i--, j++)
            // if first and last don't match then it's not a palindrome
            // otherwise repeat and check if the rest is a palindrome
            if (s.charAt(i) != s.charAt(j)) return false;
            
        // if loop ends the string must be a palindrome
        return true;
    }
    
    /**         
    * This implements algorithm 2 using recursion.
    * @param original the string being tested
    **/
    public static boolean palindrome4 (String s) {
        // calls the recursive method
        return recursivePalindrome(s, 0, s.length()-1);

    }
    
    public static boolean recursivePalindrome (String s, int n, int m) {
        if (n >= m)
             // base case: empty word is a palindrome
            return true;
        else
            // recursive case: check first == last and if rest is a palindrome
            return (s.charAt(n) == s.charAt(m) &&
                                         recursivePalindrome(s, n+1, m-1));
    }

    /**         
    * Cleans up a string allowing only A-Z and a-z to remain.
    * @param original the string being cleaned
    **/
    public static String clean (String s) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')
                sb.append(c);
        }
        return sb.toString();
    }
    
}
