/***
 * Neuroph  http://neuroph.sourceforge.net
 * Copyright by Neuroph Project (C) 2008
 *
 * This file is part of Neuroph framework.
 *
 * Neuroph is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Neuroph is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Neuroph. If not, see <http://www.gnu.org/licenses/>.
 */
package org.neuroph.easyneurons.ocr.tcr;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.neuroph.contrib.ocr.OcrPlugin;
import org.neuroph.contrib.ocr.OcrUtils;
import org.neuroph.core.NeuralNetwork;


/**
 * This class is for extracting the letters from scanned image and preparing
 * them individually (croping and resizing) for recognition.
 * The recognized letter is written in JTextArea
 * @author Ivana Jovicic, Vladimir Kolarevic, Marko Ivanovic, Zoran Sevarac
 */
public class TextRecognizer {

    private int cropY1 = 0;//up locked coordinate
    private int cropY2 = 0;//down locked coordinate
    private int cropX1 = 0;//left locked coordinate
    private int cropX2 = 0;//right locked coordinate
    public static BufferedImage imageWithText = null;
    private boolean end;//end of picture
    private boolean endRow;//end of current reading row
    public static String TEMP_CHAR_DIR = "training_chars";
    public static String TEMP_CHAR_FILE = "training_chars";

    Dimension dim;
    NeuralNetwork neuralNetwork;
    OcrPlugin ocrPlugin;
    TextRecognitionFrame tcrFrame;

    public TextRecognizer(BufferedImage image, Dimension dim, TextRecognitionFrame tcrFrame) {
        this.imageWithText = image;
        this.dim = dim;
        this.tcrFrame = tcrFrame;
    }

    /**
     * This method reads the image until it reads the first black pixel
     * by height and sets (changes) y1 on that value
     * @return - return true when true when y1 value is changed and
     * false when y1 value is not changed
     */
    public boolean lockingUp() {

        for (int j = cropY2; j < imageWithText.getHeight(); j++) {
            for (int i = cropX1; i < imageWithText.getWidth(); i++) {
                if (imageWithText.getRGB(i, j) == -16777216) {
                    if (j == 0) {
                        cropY1 = j;
                        return true;
                    }
                    cropY1 = j;
                    return true;
                }
            }
        }
        end = true;//sets this value if there are no more black pixels
        return false;
    }

    /**
     * This method reads the image until it reads the first next row
     * where all pixel are white by height and sets (changes) y2 on that value
     * @return - return true when true when y2 value is changed and
     * false when y2 value is not changed
     */
    public boolean lockingDown() {

        for (int j = cropY1 + 1; j < imageWithText.getHeight(); j++) {
            //counter for number of white pixels in row
            int counterWhite = 0;
            for (int i = cropX1; i < imageWithText.getWidth(); i++) {
                if (imageWithText.getRGB(i, j) == -1) {
                    counterWhite++;
                }
            }
            if (counterWhite == imageWithText.getWidth()) {
                cropY2 = j;
                return true;
            }
            if (j == imageWithText.getHeight() - 1) {
                cropY2 = j;
                //sets this value if this method reaches the end of image
                end = true;
                return true;
            }
        }
        return false;
    }

    /**
     * This method reads the image until it reads the first black pixel
     * by width and sets (changes) x1 on that value. It also
     * writes in JTextArea " " and \n if conditions are true
     * @return - return true when true when x1 value is changed and
     * false when x1 value is not changed
     */
    public boolean lockingLeft() {
        //counter for white pixels between the letters
        int spaceCounter = 0;
        for (int i = cropX2; i < imageWithText.getWidth(); i++) {
            for (int j = cropY1 + 1; j <= cropY2; j++) {
                if (imageWithText.getRGB(i, j) == -16777216) {
                    if (i == 0) {
                        cropX1 = i;
                        return true;
                    }
                    cropX1 = i;
                    return true;
                }
            }
            spaceCounter++;
            if (spaceCounter == 3) {
                spaceCounter = 0;
            }
        }
        endRow = true;

        return false;
    }

    /**
     * This method reads the image until it reads the first next row
     * where all pixel are white by width between y1 and y2. It also
     * writes in JTextArea \n if conditions are true
     * and sets (changes) x2 on that value
     * @return - return true  when x2 value is changed and
     * false when x2 value is not changed
     */
    public boolean lockingRight() {
        for (int i = cropX1 + 1; i < imageWithText.getWidth(); i++) {
            int counteWhite = 0;
            for (int j = cropY1 + 1; j <= cropY2; j++) {
                if (imageWithText.getRGB(i, j) == -1) {
                    counteWhite++;
                }
            }
            int row = cropY2 - cropY1;
            if (counteWhite == row) {
                cropX2 = i;
                return true;
            }
            if (i == imageWithText.getWidth() - 1) {
                cropX2 = i;
                endRow = true;

                return true;
            }
        }
        return false;
    }

    /**
     * This method cuts, crops, trim, resize and recognize images as characters
     * and writes them in JTextArea when all lock methods return true
     */
    public void recognizeText() {
        int i = 0;

        while (end == false) {
            endRow = false;
            boolean up = lockingUp();
            boolean down = false;
            if (up == true) {
                down = lockingDown();
                if (down == true) {
                    while (endRow == false) {
                        boolean left = false;
                        boolean right = false;
                        left = lockingLeft();
                        if (left == true) {
                            right = lockingRight();
                            if (right == true) {
                                Character character = ocrPlugin.recognizeCharacter(OcrUtils.trimImage(OcrUtils.cropImage(imageWithText, cropX1, cropY1, cropX2, cropY2)), dim);
                                tcrFrame.addCharacter(character);
                                i++;
                            }
                        }
                    }
                    cropX1 = 0;
                    cropX2 = 0;
                }
            }
        }
        cropY1 = 0;
        cropY2 = 0;
        end = false;
        tcrFrame.getjButton2().setEnabled(true);
        tcrFrame.getjLabel2().setText("Recognition done!");
    }


    /**
     * Creates HashMap with characters as keys and BufferedImages as values
     * @param Dimensions on witch images has to be resized on
     * @see Dimension
     * @param list of letters witch are names of images
     * @see List
     * @return HashMap that has images and names of images
     * @see HashMap
     * This method returns HashMap with letter images on wanted dimension, and names for all images
     */
    public HashMap<String, BufferedImage> createTrainingData(List<String> chars, Dimension dim) {
        HashMap<String, BufferedImage> data = new HashMap<String, BufferedImage>();

        int i = 0;
        while (end == false) {
            endRow = false;
            boolean up = lockingUp();
            boolean down = false;
            if (up == true) {
                down = lockingDown();
                if (down == true) {
                    while (endRow == false) {
                        boolean left = false;
                        boolean right = false;
                        left = lockingLeft();
                        if (left == true) {
                            right = lockingRight();
                            if (right == true) {
                                // crop, trim and resize character image 
                                BufferedImage charImage = OcrUtils.resizeImage(OcrUtils.trimImage(OcrUtils.cropImage(imageWithText, cropX1, cropY1, cropX2, cropY2)), dim.width, dim.height);
                                File charImageFile = new File(TEMP_CHAR_DIR + "/char" + i + ".jpg");

                                try { 
                                    ImageIO.write(charImage, "jpg", charImageFile);
                                } catch (IOException ex) {
                                    Logger.getLogger(TextRecognizer.class.getName()).log(Level.SEVERE, null, ex);
                                }

                                data.put(chars.get(i), charImage);
                                i++;

                            }
                        }
                    }
                    cropX1 = 0;
                    cropX2 = 0;
                }
            }
        }
        cropY1 = 0;
        cropY2 = 0;
        end = false;

        return data;
    }

    public void setNeuralNetwork(NeuralNetwork nn) {
        this.neuralNetwork = nn;
        this.ocrPlugin = (OcrPlugin) neuralNetwork.getPlugin(OcrPlugin.OCR_PLUGIN_NAME);
    }
}
