<?php

/**
 * OpenKM, Open Knowledge Management System S.L.  (http://www.openkm.com)
 * Copyright (c) 2006-2023
 *
 * No bytes were intentionally harmed during the development of this application.
 *
 * This program is commercial software; you can use it under the terms of the
 * EULA - OpenKM SDK End User License Agreement as published by OpenKM Knowledge Management System S.L.
 *
 * This program 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
 * EULA - OpenKM SDK End User License Agreement for more details:
 * http://docs.openkm.com/kcenter/view/licenses/eula-openkm-sdk-end-user-license-agreement.html
 */

namespace openkm\impl;

use Httpful\Mime;
use Httpful\Request;
use openkm\definition\BaseReport;
use openkm\util\UriHelper;
use openkm\bean\Report;
use openkm\bean\FormElementComplex;
use openkm\bean\form\Validator;
use openkm\bean\form\Option;
use openkm\util\BeanHelper;
use openkm\util\TypeException;
use openkm\util\Status;
use openkm\exception\ParseException;
use openkm\exception\AccessDeniedException;
use openkm\exception\IOException;
use openkm\exception\DatabaseException;
use openkm\exception\UnknowException;
use Httpful\Exception\ConnectionErrorException;
use openkm\exception\JRException;
use openkm\exception\EvalError;

class ReportImpl extends ClientImpl implements BaseReport {

    /**
     * Returns a list of reports.
     * 
     * @param bool $active The active reports
     * @return array(Report) Returns a list of reports.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws ParseException
     * @throws DatabaseException
     * @throws IOException
     * @throws UnknowException
     */
    public function getReports($active) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::REPORT_LIST);
            if ($active == 1) {
                $uri .= '?active=true';
            } else {
                $uri .= '?active=false';
            }
            $client = Request::get($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                $reports = [];
                foreach ($response->body->report as $reportXML) {
                    $reports[] = $this->phpReport($reportXML);
                }
                return $reports;
            } else {
                if ($response->code == Status::UNAUTHORIZED) {
                    throw new AccessDeniedException($response->body, $response->code);
                } else if ($response->code == Status::INTERNAL_SERVER_ERROR) {
                    $position = strpos($response->body, ':');
                    if ($position) {
                        $error = substr($response->body, 0, $position);
                        $msg = substr($response->body, $position + 1, strlen($response->body));
                        if ($error == TypeException::PARSE_EXCEPTION) {
                            throw new ParseException($error . ': ' . $msg);
                        } if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::IO_EXCEPTION) {
                            throw new IOException($error . ': ' . $msg);
                        } else {
                            throw new UnknowException($error . ': ' . $msg);
                        }
                    } else {
                        throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                    }
                } else {
                    throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                }
            }
        } catch (ConnectionErrorException $cee) {
            throw new ConnectionErrorException('ConnectionErrorException: ' . $cee->getMessage());
        }
    }

    /**
     * Returns a report.
     * 
     * @param type $rpId Is valid report id
     * @return Returns a report.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws ParseException
     * @throws DatabaseException
     * @throws IOException
     * @throws UnknowException
     */
    public function getReport($rpId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::REPORT_GET);
            $uri .= '?rpId=' . urlencode($rpId);
            $client = Request::get($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                return $this->phpReport($response->body);
            } else {
                if ($response->code == Status::UNAUTHORIZED) {
                    throw new AccessDeniedException($response->body, $response->code);
                } else if ($response->code == Status::INTERNAL_SERVER_ERROR) {
                    $position = strpos($response->body, ':');
                    if ($position) {
                        $error = substr($response->body, 0, $position);
                        $msg = substr($response->body, $position + 1, strlen($response->body));
                        if ($error == TypeException::PARSE_EXCEPTION) {
                            throw new ParseException($error . ': ' . $msg);
                        } if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::IO_EXCEPTION) {
                            throw new IOException($error . ': ' . $msg);
                        } else {
                            throw new UnknowException($error . ': ' . $msg);
                        }
                    } else {
                        throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                    }
                } else {
                    throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                }
            }
        } catch (ConnectionErrorException $cee) {
            throw new ConnectionErrorException('ConnectionErrorException: ' . $cee->getMessage());
        }
    }

    /**
     * Return a document result of executing a report.
     * 
     * @param int $rpId Is valid report id
     * @param array $params Is array with key and value
     * @param mimeType $format Avaialble formats:
                                  Report::FORMAT_CSV
                                  Report::FORMAT_DOCX
                                  Report::FORMAT_HTML
                                  Report::FORMAT_ODT
                                  Report::FORMAT_PDF
                                  Report::FORMAT_RTF
                                  Report::FORMAT_TEXT
     * @return string Return a document result of executing a report.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws ParseException
     * @throws DatabaseException
     * @throws IOException
     * @throws JRException
     * @throws EvalError
     * @throws UnknowException
     */
    public function executeReport($rpId, $params, $format) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::REPORT_EXECUTE);
            // If format is not allowed then returned format is always pdf
            if ($format != Report::FORMAT_CSV && $format != Report::FORMAT_DOCX && $format != Report::FORMAT_HTML && $format != Report::FORMAT_ODT && $format != Report::FORMAT_PDF && $format != Report::FORMAT_RTF && $format != Report::FORMAT_TEXT && $format != Report::FORMAT_TEXT) {
                $format = Report::FORMAT_PDF;
            }
            $uri .= '?format=' . $format . '&rpId=' . urlencode($rpId);
            $client = Request::post($uri);
            $mapParamsXML = new \SimpleXMLElement('<mapParams></mapParams>');
            foreach ($params as $key => $value) {
                $mapParamXML = $mapParamsXML->addChild('mapParam');
                $mapParamXML->addChild('key', $key);
                $mapParamXML->addChild('value', $value);
            }
            $client->body($mapParamsXML->asXML());
            $client->sends(Mime::XML);
            $client->addHeader('Accept', $format);
            $client->authenticateWith($this->user, $this->password);
            $response = $client->send();
            if ($response->code == Status::OK) {
                return $response->body;
            } else {
                if ($response->code == Status::UNAUTHORIZED) {
                    throw new AccessDeniedException($response->body, $response->code);
                } else if ($response->code == Status::INTERNAL_SERVER_ERROR) {
                    $position = strpos($response->body, ':');
                    if ($position) {
                        $error = substr($response->body, 0, $position);
                        $msg = substr($response->body, $position + 1, strlen($response->body));
                        if ($error == TypeException::PARSE_EXCEPTION) {
                            throw new ParseException($error . ': ' . $msg);
                        } if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::IO_EXCEPTION) {
                            throw new IOException($error . ': ' . $msg);
                        } else if ($error == TypeException::JR_EXCEPTION) {
                            throw new JRException($error . ': ' . $msg);
                        } else if ($error == TypeException::EVAL_ERROR) {
                            throw new EvalError($error . ': ' . $msg);
                        } else {
                            throw new UnknowException($error . ': ' . $msg);
                        }
                    } else {
                        throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                    }
                } else {
                    throw new UnknowException("HTTP error code " . $response->code . ": " . $response->body);
                }
            }
        } catch (ConnectionErrorException $cee) {
            throw new ConnectionErrorException('ConnectionErrorException: ' . $cee->getMessage());
        }
    }

    public function phpReport($reportXML) {
        $report = new Report();
        $report->setId((int) $reportXML->id);
        $report->setName((string) $reportXML->name);
        $report->setFileMime((string) $reportXML->fileMime);
        $report->setFileName((string) $reportXML->fileName);
        if ($reportXML->active == 'true') {
            $report->setActive(true);
        } else {
            $report->setActive(false);
        }
        $formElements = [];
        foreach ($reportXML->formElementsComplex as $formElementComplexXML) {
            $formElements[] = BeanHelper::copyToFormElement($this->phpFormElementComplex($formElementComplexXML));
        }
        $report->setFormElements($formElements);
        return $report;
    }

    public function phpFormElementComplex($formElementComplexXML) {
        $formElementComplex = new FormElementComplex();
        $formElementComplex->setObjClass((string) $formElementComplexXML->objClass);
        $formElementComplex->setLabel((string) $formElementComplexXML->label);
        $formElementComplex->setName((string) $formElementComplexXML->name);
        $formElementComplex->setWidth((string) $formElementComplexXML->width);
        $formElementComplex->setHeight((string) $formElementComplexXML->height);
        $formElementComplex->setType((string) $formElementComplexXML->type);
        $formElementComplex->setValue((string) $formElementComplexXML->value);
        if (!empty($formElementComplex->transition)) {
            $formElementComplex->setTransition((string) $formElementComplex->transition);
        }
        if ($formElementComplexXML->readonly == 'true') {
            $formElementComplex->setReadonly(true);
        } else {
            $formElementComplex->setReadonly(false);
        }
        $options = [];
        foreach ($formElementComplexXML->options as $optionXML) {
            $option = new Option();
            $option->setLabel((string) $optionXML->label);
            $option->setValue((string) $optionXML->value);
            $option->setSelected((string) $optionXML->selected);
            $options[] = $option;
        }
        $formElementComplex->setOptions($options);
        $validators = [];
        foreach ($formElementComplexXML->validators as $validatorXML) {
            $validator = new Validator();
            $validator->setType((string) $validatorXML->type);
            $validator->setParameter((string) $validatorXML->parameter);
            $validators[] = $validator;
        }
        $formElementComplex->setValidators($validators);
        return $formElementComplex;
    }

}
