package org.hschott.camdroid.processor;

import java.io.File;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hschott.camdroid.ConfigurationFragment;
import org.hschott.camdroid.OnCameraPreviewListener;
import org.hschott.camdroid.R;
import org.hschott.camdroid.util.StorageUtils;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.photo.Photo;

import android.app.Fragment;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;

import com.googlecode.tesseract.android.ResultIterator;
import com.googlecode.tesseract.android.TessBaseAPI;
import com.googlecode.tesseract.android.TessBaseAPI.PageIteratorLevel;
import com.googlecode.tesseract.android.TessBaseAPI.PageSegMode;

public class OCRProcessor extends AbstractOpenCVFrameProcessor {

    static final String LOG = OCRProcessor.class.getSimpleName();

    private static int min = 16;
    private static int max = 255;
    private static int blocksize = 21;
    private static int reduction = 32;


    public OCRProcessor(OnCameraPreviewListener.FrameDrawer drawer) {
        super(drawer);
    }

    @Override
    public Fragment getConfigUiFragment(Context context) {
        return Fragment.instantiate(context, OCRUIFragment.class.getName());
    }

    public static class OCRUIFragment extends
            ConfigurationFragment {

        @Override
        public int getLayoutId() {
            return R.layout.ocr_ui;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View v = super
                    .onCreateView(inflater, container, savedInstanceState);

            SeekBar minSeekBar = (SeekBar) v.findViewById(R.id.min);
            minSeekBar.setMax(255);
            minSeekBar.setProgress(min);

            minSeekBar
                    .setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                        @Override
                        public void onProgressChanged(SeekBar seekBar,
                                                      int progress, boolean fromUser) {
                            if (fromUser) {
                                min = progress;
                                OCRUIFragment.this
                                        .showValue(min);
                            }
                        }

                        @Override
                        public void onStartTrackingTouch(SeekBar seekBar) {
                        }

                        @Override
                        public void onStopTrackingTouch(SeekBar seekBar) {
                        }
                    });

            SeekBar maxSeekBar = (SeekBar) v.findViewById(R.id.max);
            maxSeekBar.setMax(255);
            maxSeekBar.setProgress(max);

            maxSeekBar
                    .setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                        @Override
                        public void onProgressChanged(SeekBar seekBar,
                                                      int progress, boolean fromUser) {
                            if (fromUser) {
                                max = progress;
                                OCRUIFragment.this
                                        .showValue(max);
                            }
                        }

                        @Override
                        public void onStartTrackingTouch(SeekBar seekBar) {
                        }

                        @Override
                        public void onStopTrackingTouch(SeekBar seekBar) {
                        }
                    });

            SeekBar blocksizeSeekBar = (SeekBar) v.findViewById(R.id.blocksize);
            blocksizeSeekBar.setMax(32);
            blocksizeSeekBar.setProgress(blocksize);

            blocksizeSeekBar
                    .setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                        @Override
                        public void onProgressChanged(SeekBar seekBar,
                                                      int progress, boolean fromUser) {
                            if (fromUser) {
                                if (progress % 2 == 0) {
                                    blocksize = progress + 3;
                                } else {
                                    blocksize = progress + 2;
                                }
                                OCRUIFragment.this
                                        .showValue(blocksize + "px");
                            }
                        }

                        @Override
                        public void onStartTrackingTouch(SeekBar seekBar) {
                        }

                        @Override
                        public void onStopTrackingTouch(SeekBar seekBar) {
                        }
                    });

            SeekBar reductionSeekBar = (SeekBar) v.findViewById(R.id.reduction);
            reductionSeekBar.setMax(64);
            reductionSeekBar.setProgress(reduction + 1);

            reductionSeekBar
                    .setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                        @Override
                        public void onProgressChanged(SeekBar seekBar,
                                                      int progress, boolean fromUser) {
                            if (fromUser) {
                                reduction = progress - 1;
                                OCRUIFragment.this
                                        .showValue(reduction);
                            }
                        }

                        @Override
                        public void onStartTrackingTouch(SeekBar seekBar) {
                        }

                        @Override
                        public void onStopTrackingTouch(SeekBar seekBar) {
                        }
                    });

            return v;
        }
    }

    @Override
    public FrameWorker createFrameWorker() {
        return new OCRFrameWorker(drawer);
    }

    public static class OCRFrameWorker extends AbstractOpenCVFrameWorker {

        private static final int SIMPLETEXT_MIN_SCORE = 60;

        private TessBaseAPI tessBaseAPI;

        private Paint paint;
        private Rect bounds;
        int lines;
        private String simpleText = new String();

        public OCRFrameWorker(OnCameraPreviewListener.FrameDrawer drawer) {
            super(drawer);

            this.tessBaseAPI = new TessBaseAPI();
            this.tessBaseAPI.setPageSegMode(PageSegMode.PSM_AUTO_OSD);

            this.tessBaseAPI.setVariable(TessBaseAPI.VAR_ACCURACYVSPEED,
                    String.valueOf(50));
            this.tessBaseAPI.init(Environment.getExternalStorageDirectory().getPath(), "eng");

            paint = new Paint();
            paint.setColor(Color.RED);
            int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    (float) 11.0, drawer.getDisplayMetrics());
            paint.setTextSize(size);

            bounds = new Rect();
            paint.getTextBounds("Q", 0, 1, bounds);

            lines = drawer.getDisplayMetrics().heightPixels / bounds.height();

        }

        @Override
        protected void draw() {
            Utils.matToBitmap(out, this.bmp);
            Canvas canvas = new Canvas(this.bmp);

            int y = bounds.height();
            int c = 1;
            for (String line : simpleText.split("\n")) {
                canvas.drawText(line, bounds.width(), y, paint);
                y = y + bounds.height();
                if (c >= lines)
                    break;;
            }

            this.drawer.drawBitmap(this.bmp);

        }

        protected void execute() {
            out = gray();

            Imgproc.equalizeHist(out, out);
            Core.normalize(out, out, min, max, Core.NORM_MINMAX);

            Imgproc.adaptiveThreshold(out, out, 255, Imgproc.THRESH_BINARY,
                    Imgproc.ADAPTIVE_THRESH_MEAN_C, blocksize, reduction);

            byte[] data = new byte[(int) out.total()];
            out.get(0, 0, data);

            this.tessBaseAPI.setImage(data, out.width(), out.height(),
                    out.channels(), (int) out.step1());

            String utf8Text = this.tessBaseAPI.getUTF8Text();
            int score = this.tessBaseAPI.meanConfidence();
            this.tessBaseAPI.clear();


            if (score >= SIMPLETEXT_MIN_SCORE && utf8Text.length() > 0) {
                simpleText = utf8Text;
            } else {
                simpleText = new String();
            }
        }

    }

}