/*
PROGRAM NAME:   Program #1 - 2D Arrays
PROGRAMMER:     Daniel Yim
CLASS:          CSC 202.002
INSTRUCTOR:     Dr. Strader
DATE DEVELOPED: January 28, 2008
DATE COMPLETED: January 29, 2008
REFERENCES:     Computer Science - 
                    Introduction to Java Programming
                    Y. Daniel Liang

STATEMENT:
    To determine patterns in pictures, a data file with a table of multiple light intensities
    of a certain image will be provided, and this program will compute matches of intensities
    according to a key that is provided.
    
    The data provided will be:
    
        10
        8  4  7  3  8  6  3  4  3  8
        2  7  6  3  5  2  9  8  6  5
        1  2  3  8  6  4  4  5  4  8
        3  2  8  8  8  5  1  2  3  5
        4  3  2  1  3  8  6  4  3  8
        8  9  6  7  5  5  4  3  4  5
        9  8  7  4  2  8  6  5  9  7
        1  5  4  6  5  3  3  8  6  5
        4  3  2  1  2  3  4  5  6  5
        9  8  7  6  5  6  5  4  3  8
    
    Using the key (not provided in the data file):
                
                5
            3   8   6
                5   
    
    The output will produce the original data and will list the coordinates of full or partial
    matches that were found during the computation. For example:
        
        8  4  7  3  8  6  3  4  3  8
        2  7  6  3  5  2  9  8  6  5
        1  2  3  8  6  4  4  5  4  8
        3  2  8  8  8  5  1  2  3  5
        4  3  2  1  3  8  6  4  3  8
        8  9  6  7  5  5  4  3  4  5
        9  8  7  4  2  8  6  5  9  7
        1  5  4  6  5  3  3  8  6  5
        4  3  2  1  2  3  4  5  6  5
        9  8  7  6  5  6  5  4  3  8
        
        MATCHES:  (0,0), (3,5), (6,2)

METHODS USED: 
    findMatches(int row, int col, int[][] 2D array, ArrayList<String> MatchCoords, int[][] 
        KeyArray, int HeaderValue)
                Given a single coordinate, findMatches computes each surrounding neightbor
                to the key provided and adds it to the list if it is a partial or a full
                match.
    printArray(int[][] 2DArray, int HeaderValue)
                The method outputs the 2D array provided in the data file as it is.
    printMatches(int[][] 2DArray, ArrayList<String> MatchCoords, int HeaderValue)
                Reads the stored values of coordinates which contain matches with the given key
                against the given data set.
DICTIONARY OF VARIABLES:
    public class Program1
        boolean debug
            A switch to output every action to aid the development process
    public static main void
        final int SIZE
            A constant that reflects the header value read from the data file
        int[][] key
            A 2D array containing the key to match the "image" with
        ArrayList<String> coords
            A list of coordinates found to contain partial or full matches
    public static void findMatches
        boolean topFound, leftFound, rightFound, botFound
            Indicator if a match is found on the top, left, right, or bottom (respectively) of the
            coordinate given
        int inCorner
            A count of how many times accessing a neighbor went out of bounds, used to calculate
            if a match is partial (inCorner > 1) or full (inCorner == 0)
            
--------------------------------------------------------------------------------
*/

import java.util.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
    
public class Program1
{
    static boolean debug = false;
    
// ============================= method main ===================================

    public static void main (String[] args)
    {
        try
        {
            
            FileInputStream dataFile 
                = new FileInputStream("prog1.dat"); // Initialize the file
            Scanner in = new Scanner(dataFile);     // Initialize the scanner
            final int SIZE = in.nextInt();      // Read in the header value & set constant
            
            int[][] arr = new int[SIZE][SIZE];      // Initialize the 2D Array
            int[][] key = new int[3][3];            // Initialize the key to search for
            key[0][1] = 5;        //     KEY
            key[1][0] = 3;        // r  c 0 1 2
            key[1][1] = 8;        // 0   [0,5,0]
            key[1][2] = 6;        // 1   [3,8,6]
            key[2][1] = 5;        // 2   [0,5,0]


            ArrayList<String> coords = new ArrayList<String>();    // Initialize the array to store
                                                                   // coordinates with matches
            
                    // Reads the individual values from the file to an array
            for(int r = 0; r < SIZE; r++)
                for(int c = 0; c < SIZE; c++)
                    arr[r][c] = in.nextInt();
            
                    // Cycles through each value in the array to find matching neighbors
            for(int r = 0; r < SIZE; r++)
                for(int c = 0; c < SIZE; c++)
                    findMatches(r, c, arr, coords, key, SIZE);
            
            
            printArray(arr, SIZE);                // Print the original array
            printMatches(arr, coords, SIZE);      // Print the coords of matches
            
            in.close();                           // Close the file
        }
        catch(FileNotFoundException e)
        {
                    // Display an error if the data file cannot be found
            System.out.println("/////////// ERROR! ///////////");
            System.out.println("The data file cannot be found!");
        }

                // Add lines to the end of the program.
        System.out.println ("\n\n");
                // Returns to the OS
        return;
    }   // End of public static void main
    
    
// ============================= method findMatch ===================================
/*
METHOD DESCRIPTION:
    Given a single coordinate, findMatches computes each surrounding neightbor
    to the key provided and adds it to the list if it is a partial or a full
    match.
*/
    public static void findMatches(int r, int c, int[][] arr, ArrayList<String> coords, int[][] key, int size)
    {
        boolean topFound = false;
        boolean botFound = false;
        boolean leftFound = false;
        boolean rightFound = false;
        int inCorner = 0;
        
        if(debug) System.out.println("CHECKING (" + r + ", " + c + ")");
        
            // Center check
        if(arr[r][c] == key[1][1])
        {
            if(debug) System.out.println("CENTER WAS FOUND @ (" + r + ", " + c + ")");
            
                // Top check
            if(r-1 >= 0)   // Checks bounds
            {
                if(arr[r-1][c] == key[0][1]){   // Checks the top key value
                    if(debug) System.out.println("TOP WAS FOUND @ (" + r + ", " + c + ")");
                    topFound = true;}
            }
            else inCorner++;    // Add to variable if out of bounds
    
                // Bottom check
            if(r+1 <= size-1)   // Checks bounds
            {
                if(arr[r+1][c] == key[2][1]){   // Checks the bottom key value
                    if(debug) System.out.println("BOTTOM WAS FOUND @ (" + r + ", " + c + ")");
                    botFound = true;}
            }
            else inCorner++;    // Add to variable if out of bounds
            
                // Left check
            if(c-1 >= 0)   // Checks bounds
            {
                if(arr[r][c-1] == key[1][0]){   // Checks the left key value
                    if(debug) System.out.println("LEFT WAS FOUND @ (" + r + ", " + c + ")");
                    leftFound = true;}
            }
            else inCorner++;    // Add to variable if out of bounds
    
                // Right check
            if(c+1 <= size-1)   // Checks bounds
            {
                if(arr[r][c+1] == key[1][2]){   // Checks the right key value
                    if(debug) System.out.println("RIGHT WAS FOUND @ (" + r + ", " + c + ")");
                    rightFound = true;}
            }
            else inCorner++;    // Add to variable if out of bounds
            
            if(debug)
            {
                System.out.println("topFound: " + topFound);
                System.out.println("rightFound: " + rightFound);
                System.out.println("leftFound: " + leftFound);
                System.out.println("botFound: " + botFound);
                System.out.println("inCorner val: " + inCorner);
            }
                    // Checks for partial matches (matches in a corner or edge)
            if(inCorner > 0 && ((rightFound&&(topFound||botFound)) || (leftFound&&(topFound||botFound))))
            {
                if(debug) System.out.println("DEBUG: PARTIAL MATCH ADDED (" + r + ", " + c + ")\n");
                coords.add("(" + r + ", " + c + ")");   // Adds a partial match
            }
                    // Checks for full matches
            else if(rightFound && topFound && leftFound && botFound)
            {
                if(debug) System.out.println("DEBUG: FULL MATCH ADDED (" + r + ", " + c + ")\n");
                coords.add("(" + r + ", " + c + ")");   // Adds a full match
            }
            else
                if(debug) System.out.println("NOTHING FOUND. NEXT.\n");
        }
        
    }           // End of public static void findMatches


// ============================= method printArray =============================
/*
METHOD DESCRIPTION:
    The method outputs the 2D array provided in the data file as it is
*/     
    public static void printArray(int[][] arr, int s)
    {
                // Reads from the array and prints according to the size given
        for(int r = 0; r < s; r++)
        {
            for(int c = 0; c < s; c++)
            {
                System.out.print("  " + arr[r][c]);
            }
            System.out.println();
        }
            
        System.out.println("\n\n");                                    
    }       // End of public static void printArray
    
    
// ============================= method printMatches =============================
/*
METHOD DESCRIPTION:
    Reads the stored values of coordinates which contain matches with the given key
    against the given data set.
*/     
    public static void printMatches(int[][] arr, ArrayList<String> coords, int s)
    {
        System.out.print("MATCHES:  ");
        for(int k = 0; k < coords.size(); k++)
            System.out.print(coords.get(k) + ", ");
    }       // End of public static void printMatches

}   // End of public class Program1


