using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BallotTemplates;
using CognitiveToolkit;
using CognitiveToolkit.OpenCvSharp;
using InterpreterLibrary.Interpreters;
using InterpreterLibrary.Models;
using InterpreterLibrary.Processing;
using Tesseract;
using Valg.EVA.Skanning.Scan.ReadSoftEmulation.ScannerAccess;

namespace Valg.EVA.Skanning.Scan.ReadSoftEmulation.BallotInterpretation
{
    class BallotInterpreter
    {
        private readonly TesseractEngine _ocr;
        private readonly WriteInInterpreter _writeInInterpreter;
        private readonly CheckboxClassifier _checkBoxInterpreter;
        private readonly NumberInterpreter _numberInterpreter;
        private bool _aborted;

        internal BallotInterpreter()
        {
            _ocr = new TesseractEngine(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tessdata"), "nor"); 
            _numberInterpreter = new NumberInterpreter(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "Models", "MNISTConvolution.model"));
            _writeInInterpreter = new WriteInInterpreter(new SingleModelCharacterClassifier(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "Models", "ConvNet_Vdir_39.dnn")));
            _checkBoxInterpreter = new CheckboxClassifier(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "Models", "ConvNet_checkbox_3state_Vdir.dnn"));
        }

        internal void Start(
            BlockingCollection<(int order, byte[] frontBytes, byte[] backBytes, bool areDeskewed)> inputQueue,
            BlockingCollection<object> outputQueue,
            BallotTemplate[] templates)
        {
            _aborted = false;
            while (!inputQueue.IsCompleted && !_aborted)
            {
                if (!inputQueue.TryTake(out var tuple))
                {
                    Thread.Sleep(100);
                    continue;
                }

                try
                {
                    
                    
                    
                    

                    
                    
                    
                    
                    
                    using (var preprocessor = new BallotPreprocessor(tuple.frontBytes, tuple.backBytes,
                        _ocr,
                        new BallotPreprocessorOptions() { AreDeskewed = tuple.areDeskewed, MinimumTypeIdConfidence = 0.7f },
                        templates))
                    {
                        if (preprocessor.Output.Template != null)
                        {
                            var ballot = new ScannedBallotPaper(preprocessor.Output, _ocr, _numberInterpreter, _writeInInterpreter, _checkBoxInterpreter);
                            try
                            {
                                ballot.Interpret();
                                outputQueue.Add(new Tuple<int, ScannedBallotPaper, BallotPreprocessorOutput, byte[], byte[]>(
                                    tuple.order,ballot, preprocessor.Output, tuple.frontBytes, tuple.backBytes));
                            }
                            catch (Exception e)
                            {
                                outputQueue.Add(e);
                            }
                        }
                        else
                        {
                            outputQueue.Add(new Tuple<int,BallotPreprocessorOutput, byte[], byte[]>(tuple.order,preprocessor.Output, tuple.frontBytes, tuple.backBytes));
                        }
                    }
                }
                catch (Exception e)
                {
                    outputQueue.Add(e);
                }
            }
        }

        internal void Abort()
        {
            _aborted = true;
        }
    }
}

