<?php

/**
 * Run
 *
 * @package FileIndexingTool
 *
 * @author Tomasz Świenty
 * @version 5.0
 * @copyright Copyright (c) eDokumenty
 */

$options = getopt('h:');
$host = '';
if (is_array($options) AND $options) {
    $host = isset($options['h']) ? $options['h'] : '';

    if ($host) {
        $_SERVER['HTTP_HOST'] = $host.'.';
    }
}

$configFile = './conf/config'.($host ? '_'.$host : '').'.json';
if (!file_exists($configFile) OR !is_readable($configFile)) {
    trigger_error(sprintf('Missing file %s', $configFile));
    exit(sprintf('Missing file %s', $configFile));
}

$CONFIG = json_decode(file_get_contents('./conf/config'.($host ? '_'.$host : '').'.json'));

if (!is_object($CONFIG) OR !$CONFIG) {
    trigger_error(sprintf('Incorrect JSON parse %s', json_last_error_msg()));
    exit(sprintf('Incorrect JSON parse %s', json_last_error_msg()));
}

chdir(dirname(__FILE__).'/../../');

/* ------------------------------- CONFIG ------------------------------- */
// ścieżka do katalogu z tym narzędziem jeśli umieścić gdzieś głębiej niż scripts wtedy zmień tu
$TOOL_PATH = dirname(__FILE__);

$PROCESS_PID = getmypid();

$PROCESS_PID_FILE_PATH = './scripts/FileIndexingTool/pid';

$REPORT_FILE_PATH = './scripts/FileIndexingTool/reports/files_index_report_'.($host ? $host.'_' : '').uniqid().'_'.date('Y-m-d').'.txt';

// nie pozwala na uruchamianie wielu procesów chyba ze mu jawnie na to pozwolisz
$DO_NOT_LET_MANY_RUN = (isset($CONFIG->DO_NOT_LET_MANY_RUN) AND is_bool($CONFIG->DO_NOT_LET_MANY_RUN)) ? $CONFIG->DO_NOT_LET_MANY_RUN : TRUE;

// limit ile razy maksymalnie może próbować przetworzyć plik jesli jest z błedem
$INDEX_OPERATION_LIMIT = isset($CONFIG->INDEX_OPERATION_LIMIT) ? $CONFIG->INDEX_OPERATION_LIMIT : 5;

// głowny filtr na zapytanie np. fileid > 2000 AND adddat::date > 2019-01-01
$FILES_QUERY_FILTER = isset($CONFIG->FILES_QUERY_FILTER) ? $CONFIG->FILES_QUERY_FILTER : '';

// Jaki pliki ma indeksować np. po rozszerzeniach
// FILTROWANIE NASTĘPUJE PO KOLUMNIE files.filenm
// przykład $FILE_NAME_FILTER_PATTERNS = ['.pdf$', '.rtf$'];
$FILE_NAME_FILTER_PATTERNS = (isset($CONFIG->FILE_NAME_FILTER_PATTERNS) AND is_array($CONFIG->FILE_NAME_FILTER_PATTERNS)) ? $CONFIG->FILE_NAME_FILTER_PATTERNS : [];

// sortowanie czy np ma od najstarszego czy od najnowszego można wpisać cokolwiek co ma sens ;)
$FILES_QUERY_ORDER = isset($CONFIG->FILES_QUERY_ORDER) ? $CONFIG->FILES_QUERY_ORDER : '';

// raportuje tylko błędy w formie pliku testowego załączonego do dokumentu
$REPORT_INDEXING_RESULT_TO_USER = isset($CONFIG->REPORT_INDEXING_RESULT_TO_USER) ? (int)$CONFIG->REPORT_INDEXING_RESULT_TO_USER : '';

// Główna kwerenda wyciągająca pliki do zaindeksowanie
// domyślnie pobiera wszystkie
$query = 'SELECT fileid, filenm FROM files';

if ($FILES_QUERY_FILTER) {
    $query .= ' WHERE '.$FILES_QUERY_FILTER;
} else {
    $query .= ' WHERE 1=1';
}

$filter = [];
if ($FILE_NAME_FILTER_PATTERNS) {
    $FILE_NAME_FILTER_PATTERNS = array_filter($FILE_NAME_FILTER_PATTERNS);
    foreach ($FILE_NAME_FILTER_PATTERNS as $filterPattern) {
        $filter[] = 'filenm ~* E\''.$filterPattern.'\'';
    }
}

$filter = array_filter($filter);
if ($filter) {
    $query .= ' AND ('.implode(' OR ', $filter).')';
}

if ($FILES_QUERY_ORDER) {
    $query .= ' ORDER BY '.$CONFIG->FILES_QUERY_ORDER;
}

echo 'Twoje zapytanie: '.$query."\n";

if (($DO_NOT_LET_MANY_RUN === TRUE) AND file_exists($PROCESS_PID_FILE_PATH) AND ($PROCESS_PID = file_get_contents($PROCESS_PID_FILE_PATH))) {
    exit(sprintf('Nie można uruchomić więcej niż jednego procesu. Sprawdź proces o id %s lub usuń plik %s', $PROCESS_PID, $PROCESS_PID_FILE_PATH));
}

file_put_contents($PROCESS_PID_FILE_PATH, $PROCESS_PID);

/* ------------------------------- CONFIG ------------------------------- */

set_time_limit(0);
ini_set('memory_limit', -1);

require_once('ScriptRunner.php');
require_once('FileIndexLog.inc');
require_once('FileIndexStatus.inc');

$log = new FileIndexLog();
$log->write(sprintf('Odpalam FileIndexingTool::Run%s', ($host ? ' dla '.$host : '')));
$log->write(sprintf('Wykonuję zapytanie: %s', $query));

$db = new PgManager(DB_NAME);
$files = $db->query($query, FALSE, PGSQL_ASSOC);

if (!isset($files[0]['fileid'])) {
    $log->write(sprintf('Brak plików spełniających zapytanie: %s', $query));
    exit();
}

$c = count($files);

$log->write(sprintf('Znaleziono plików: %s', $c));
$log->write('Trwa indeksowania ...');

if (!is_dir('./scripts/FileIndexingTool/reports')) {
    bs_mkdir('./scripts/FileIndexingTool/reports');
}

$reportFileHandle = fopen($REPORT_FILE_PATH, 'a');

foreach ($files as $i => $fileItem) {
    $cc = ++$i;

    $fileIndexStatus = new FileIndexStatus($fileItem['fileid']);
    $fileIndexStatusCounter = $fileIndexStatus->geti('idxcnt');
    $fileIndexStatusHash = $fileIndexStatus->get('hash__');

    if ($fileIndexStatusCounter === (int)$INDEX_OPERATION_LIMIT) {
        $log->write(sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s niemożliwe. Przekroczony limit błędnych indeksacji', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm']));
        fwrite($reportFileHandle, sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s niemożliwe. Przekroczony limit błędnych indeksacji', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm'])."\n");
        continue;
    }

    $file = new File($fileItem['fileid']);
    $fileHash = $file->getHash();
    if (!$fileHash) {
        $log->write(sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s niemożliwe. Brak skrótu dla treści', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm']));
        fwrite($reportFileHandle, sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s niemożliwe. Brak skrótu dla treści', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm'])."\n");
        continue;
    }

    $fileHash = base64_encode($fileHash);

    // to nie jest błąd
    if ($fileIndexStatusHash AND $file->getMetaText() AND ($fileIndexStatusHash === $fileHash)) {
        $log->write(sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s niepotrzebne. Brak zmiany hasha treści pliku w stosunku do zapamiętanego w files_index_status.hash__', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm']));
        continue;
    }

    $log->write(sprintf('Indeksowanie pliku (%s/%s): %s', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm']));

    $start = METime::begin();
    passthru(escapeshellarg(PHP_BINARY).' '.$TOOL_PATH.'/FileIndex.inc '.$fileItem['fileid'].' '.$host);

    $end = METime::finish(TRUE, $start);

    $log->write(sprintf('Koniec indeksowania pliku (%s/%s): %s. Czas: %s', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm'], (round($end, 4)).' sek'));

    // musi być bo w FileIndex.inc nastepuje zapisanie beana !
    $fileIndexStatus->reload();

    // jesli skrypt FileIndex.inc zwiekszyl liczbe indeksacji z bledem to jest powod aby dodac wpis
    if ($fileIndexStatusCounter < $fileIndexStatus->geti('idxcnt')) {
        fwrite($reportFileHandle, sprintf(date('Y-m-d H:i:s').' Indeksowanie pliku (%s/%s): %s z błędem. %s', $cc, $c, $fileItem['fileid'].'_'.$fileItem['filenm'], $fileIndexStatus->get('lasmsg'))."\n");
    }

    $fileIndexStatus->set('ittook', (round($end, 4) * 1000));
    $fileIndexStatus->set('hash__', $fileHash);
    $fileIndexStatus->save();
}

fclose($reportFileHandle);
clearstatcache();

if (filesize($REPORT_FILE_PATH) AND (filter_var($REPORT_INDEXING_RESULT_TO_USER, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]) !== FALSE)) {
    require_once('./classes/Notifications/NotificationSettings.inc');

    UserRights::disable();
    SysContext::$usr_info['orunid'][0] = SysContext::NOTIFY_SERVICE_ID;
    SysContext::$usr_info['firnam'] = 'Usługa';
    SysContext::$usr_info['lasnam'] = 'Indeksowanie plików';
    SysContext::$usr_info['entity'] = 'UIP';
    SysContext::$usr_info['initls'] = 'UIP';

    $targetOut = $db->query('SELECT orunid FROM orgtree_view WHERE usr_id = '.$REPORT_INDEXING_RESULT_TO_USER, FALSE, PGSQL_ASSOC);
    if (isset($targetOut[0]['orunid'])) {
        $documentData = [];
        $documentData['dscrpt'] = sprintf(Translator::translate('Raport indeksacji załączników z dnia %s'), date('Y-m-d'));
        $documentData['dctptp'] = 'Other';
        $documentData['target'] = $targetOut[0]['orunid'];
        $documentData['crtdat'] = date('Y-m-d');

        $api = new EDokApi();
        $doc_id = $api->createDocument($documentData);
        if ($doc_id) {
            $zip = new \PHPZip\Zip\File\Zip();
            $zip->addFile(file_get_contents($REPORT_FILE_PATH), basename($REPORT_FILE_PATH), 0, NULL, FALSE);
            $zip->finalize();

            $api->addAttachmentToDocument($zip->getZipData(), basename($REPORT_FILE_PATH, '.txt').'.zip', $doc_id, 'binary');
        }

        if (!NotificationSettings::get(NotificationSettings::NOTIFY_SETTING_DOCUMENT_DECREE, NotificationSettings::NOTIFY_TYPE_STREAM, $REPORT_INDEXING_RESULT_TO_USER)) {
            $notifyData = [];
            $notifyData['usr_id'] = $REPORT_INDEXING_RESULT_TO_USER;
            $notifyData['msgtxt'] = $documentData['dscrpt'];
            $notifyData['metaData'] = ['nscls_' => 'DOCUMENT', 'nskey_' => $doc_id, 'nstxt_' => $documentData['dscrpt']];

            $api->notifyUser($notifyData);
        }

        bs_unlink($REPORT_FILE_PATH);
    }
}

bs_unlink($PROCESS_PID_FILE_PATH);

$db->commit();
$db->disconnect();