<?php

namespace Velis\Model\File;

use Exception;
use Laminas\Http\Client;
use Velis\App;
use Velis\Filesystem\FilesystemInterface;
use Velis\Model\File;

/**
 *
 * @see http://ocrsdk.com/documentation/apireference/processImage/
 *
 * @author  Robert Jamróz <robert.jamroz@velis.pl>
 */
class Abbyy
{
    private $_appId = 'MyOcrTestApplication';
    private $_appPwd = 'bKQ2FTtRVju08ZoT/1sz6SBt';


    /**
     * @var File
     */
    private $file = null;

    /**
     *
     * Settings part
     *
     * @var array
     */
    private static $_formats = array(
        'rtf', 'txt', 'docx', 'xlsx', 'pptx', 'pdfSearchable', 'pdfTextAndImages ', 'pdfa', 'alto', 'xml'
    );

    /**
     *
     * @see http://ocrsdk.com/documentation/specifications/image-formats/
     * @var array
     */
    private static $_fileTypes = array(
        'bmp', 'dcx', 'pcx', 'png', 'jp2', 'jpc', 'jpg', 'jpeg', 'jfif', 'pdf', 'tif', 'tiff', 'gif', 'djvu', 'djv', 'jb2'
    );

    /**
     * Internal name
     * To view full list @see http://ocrsdk.com/documentation/specifications/recognition-languages/
     *
     * @var array
     */
    private static $_languages = array('Polish', 'English');


    public function __construct()
    {
        $this->_appId = App::$config->ocr->abbyy->appId;
        $this->_appPwd = App::$config->ocr->abbyy->appPwd;
    }


    /**
     * @param array $params
     * @return bool
     * @throws Exception
     */
    public function set($params)
    {
        if (!$this->file) {
            throw new Exception('File not set!', 2308001);
        }

        if (!$params['exportFormat']) {
            throw new Exception('Export format not set. Set one from: ' . implode(', ', self::$_formats), 2308001);
        }

        if (!in_array($params['language'], self::$_languages)) {
            throw new Exception('Language not allowed. Allowed one from: ' . implode(', ', self::$_languages), 2308001);
        }

        /** @var FilesystemInterface $filesystem */
        $filesystem = App::$di->get('filesystem');
        $filePath = $this->file->getStoragePath();

        if (!$filesystem->has($filePath)) {
            throw new Exception('File ' . $filePath . ' not found.', 2308001);
        }

        $out = true;

        // Recognizing with English language to rtf
        // You can use combination of languages like ?language=english,russian or
        // ?language=english,french,dutch
        // For details, see API reference for processImage method
        $url = strtolower('http://cloud.ocrsdk.com/processImage?language=' . $params['language'] . '&exportFormat=' . $params['exportFormat'] . '&profile=textExtraction');

        $client = new Client();
        $client->setUri($url);
        $client->setAuth($this->_appId, $this->_appPwd);
        $client->setMethod('POST');
        $client->setFileUpload($filePath, 'upload', $filesystem->read($filePath));
        $response = $client->send();

        $httpCode = $response->getStatusCode();

        // Parse xml response
        $xml = simplexml_load_string($response->getBody());
        if ($httpCode != 200) {
            if (property_exists($xml, "message")) {
                throw new Exception($xml->message, 2308001);
            }
            throw new Exception("unexpected response " . $response, '', 2308001);
        }

        $arr = $xml->task[0]->attributes();

        $taskStatus = $arr["status"];
        if ($taskStatus != "Queued") {
            throw new Exception("Unexpected task status " . $taskStatus, 2308001);
        }

        // Task id
        $taskid = $arr["id"];

        $this->file['is_ocr'] = 1;
        $this->file['ocr_pending'] = 1;
        $this->file['ocr_task_id'] = (string)$taskid[0];

        $this->file->save();

        return $out;
    }


    public function setFile($file)
    {
        $this->file = $file;
    }


    /**
     * @return bool
     * @throws Exception
     */
    public function check()
    {
        $url = 'http://cloud.ocrsdk.com/getTaskStatus';
        $qry_str = '?taskid=' . $this->file->ocr_task_id;

        $client = new Client();
        $client->setUri($url . $qry_str);
        $client->setAuth($this->_appId, $this->_appPwd);
        $response = $client->send();

        $httpCode = $response->getStatusCode();

        // parse xml
        $xml = simplexml_load_string($response->getBody());
        if ($httpCode != 200) {
            if (property_exists($xml, "message")) {
                throw new Exception($xml->message, 2308001);
            }
            throw new Exception("Unexpected response " . $response, 2308001);
        }

        $arr = $xml->task[0]->attributes();
        $taskStatus = $arr["status"];

        if ($taskStatus == "Queued" || $taskStatus == "InProgress") {
            $out = false;
        } elseif ($taskStatus == "Completed") {
            $out = true;
        } elseif ($taskStatus == "ProcessingFailed") {
            throw new Exception("Task processing failed: " . $arr["error"], 2308001);
        } elseif ($taskStatus == "Deleted") {
            throw new Exception("Task deleted: {$this->file->ocr_task_id}.", 2308001);
        } else {
            throw new Exception("Unexpected task status " . $taskStatus, 2308001);
        }

        if ($out) {
            $url = reset($arr["resultUrl"]);

            try {
                $client = new Client();
                $client->setUri($url);
                $client->setAdapter(Client\Adapter\Curl::class);

                $response = $client->send();
            } catch (Exception $e) {
                echo $e->getMessage();
            }


            if ($response->getStatusCode() == 200) {
                $this->file['ocr_body_txt'] = $response->getBody();
            }


            if ($arr["resultUrl2"]) {
                $response = file_get_contents(reset($arr["resultUrl2"]));

                if ($response !== false) {
                    $this->file['ocr_body_xml'] = $response;
                }
            }

            $this->file['ocr_pending'] = 0;
            $this->file->save();
        }

        return $out;
    }


    public static function checkFile($file)
    {
        $name = substr(strtolower($file), -6);
        $dotpos = strpos($name, '.');

        $out = false;

        if (in_array(substr($name, $dotpos + 1), self::$_fileTypes)) {
            $out = true;
        }

        return $out;
    }
}
