<?php

class floraBK implements sigb
{

    const version = "1.1.7";
    const nameClass = "flora";

    const XML_HEADER = '<?xml version="1.0" encoding="utf-8"?>';

    public $hostData;
    public $portData;
    public $userData;
    public $passData;
    public $ext_path;

    public $hostApi;
    public $portApi;
    public $keyApi;

    public $idClient = 'Identifiant client Decalog';
    public $institutionId = 1;
    public $wsPath = '/floratest';

    private $oJSON;
    private $bStandalone;


    function __construct($sExtPath = './')
    {
        $this->ext_path = $sExtPath;
        $this->bStandalone = false;
    }

    private function connect($sHost, $iPort, $sUser, $sPass) {
        require_once ($this->ext_path . "sigb_class/JsonHttpClient.class.php");
        if ($iPort == 443 || strpos($sHost, 'https://') >= 0) {
            $this->oJSON = new JsonHttpClientSsl($sHost, $iPort);
        } else {
            $this->oJSON = new JsonHttpClient($sHost, $iPort);
        }
        $this->oJSON->setHeader('apikey', $this->buildFloraApiKey($this->institutionId), false);
        $this->oJSON->setDebug(false);
    }

    private function buildFloraApiKey($institution_id) {
        $key = 'OpacAPIDecalog'.date('Y-m-d');
        $encryptApiKey = hash_hmac('sha1', $institution_id, $key);
        return $encryptApiKey;
    }

    private function buildPath($path) {
        return $this->hostData . $this->wsPath . '/rest/decalog-api/' . $this->institutionId . $path;
    }

    public function getVersion($serialize=true){
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->get($this->buildPath("/version.json"));
        $jsonresponseDetails = $this->decodeResponse($this->oJSON);
        if ($serialize === true){
            $jsonresponseDetails = serialize($jsonresponseDetails);
        }
        return $jsonresponseDetails;
    }

    public function getVersionAgent() {
        return self::XML_HEADER . '<root><res>' . self::version . '</res></root>';
    }

    private function decodeResponse($client) {
        if ($client->getStatus() != 200) {
            if (!empty($client->getContent())) {
                $error = json_decode($client->getContent())->message;
            } else {
                $error = 'Backend call error';
            }
            return (object) array(
                'success'    => false,
                'status'     => $client->getStatus(),
                'error'      => $error,
                'stacktrace' => array()
            );
        }
        return json_decode($client->getContent());
    }

    private function formatResultLogin($userInfos, $username)
    {
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $login = $res->addChild('login');
        $login->addChild('sigb', self::nameClass);
        if(!empty($userInfos->error)) {
            $res->addChild('error', $userInfos->error);
            return $res->asXML();
        }
        $login->addChild('client_id', $this->idClient);
        $login->addChild('id', $userInfos->data->id);
        $login->addChild('code', $userInfos->data->barcode);
        $login->addChild('user', $username);
        $login->addChild('fullname', $userInfos->data->lastname . ', ' . $userInfos->data->firstname);
        $login->addChild('email', $userInfos->data->email);
        $login->addChild('birthdate', $userInfos->data->birthdate);
        $login->addChild('phoneNumber', $userInfos->data->phoneNumber);
        $login->addChild('mobileNumber', $userInfos->data->mobileNumber);
        $login->addChild('error', 0);

        return $res->asXML();
    }

    private function formatResultUpdateAccount($accountInfos, $newLoginInfos)
    {
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $resUpdate = $res->addChild('updateAccount');
        $resUpdate->addChild('sigb', self::nameClass);
        if($newLoginInfos['errorCode'] != 0 || $newLoginInfos['errorCode'] != '0') {
            $resUpdate->addChild('error', $newLoginInfos['errorCode']);
            return $res->asXML();
        }
        $resUpdate->addChild('user', $newLoginInfos['username']);
        $resUpdate->addChild('error', 0);
        $resUpdate->addChild('code', 0);

        return $res->asXML();
    }

    private function formatResultProlongLoan($loanInfos)
    {
        $message = '';
        if ($loanInfos->error != '') {
            $message = $loanInfos->error;
        }
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $resProlong = $res->addChild('prolongation');
        $resProlong->addChild('sigb', self::nameClass);
        $res->addChild('error', (!empty($message) ? $message : ''));
        $res->addChild('code', 0); // TODO : utilité ?

        return $res->asXML();
    }

    private function formatResultReserveInfo($reserveInfos, $userNoticeInfos)
    {
        $message = '';
        if ($reserveInfos->error != '') {
            $message = $reserveInfos->error;
        }
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $resInfo = $res->addChild('reservationInfo');
        $resInfo->addChild('sigb', self::nameClass);
        $resInfo->addChild('user', $userNoticeInfos['userInt']);
        $resInfo->addChild('nn', $userNoticeInfos['idNotice']);
        if ($reserveInfos->data->networkType){
            $resInfo->addChild('networkType', $reserveInfos->data->networkType);
        }
        if (!empty($reserveInfos->data->sites)){
            foreach ($reserveInfos->data->sites as $site) {
                $resInfoSite = $resInfo->addChild('site', $site->name);
                $resInfoSite->addAttribute('id', $site->id);
                $resInfoSite->addAttribute('nbItems', $site->nbItems);
                $resInfoSite->addAttribute('nbBookings', $site->nbBookings);
            }
        }

        if (!empty($message)) {
            $resInfo->addChild('error', $message);
        }
        $resInfo->addChild('code', 0);

        return $res->asXML();
    }

    private function formatResultReserveDocument($reserveDocInfos, $userInt)
    {
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $resDoc = $res->addChild('reservationDoc');
        $resDoc->addChild('sigb', self::nameClass);
        $resDoc->addChild('user', $userInt);

        if (!empty($reserveDocInfos->data->isNotBookableReason)) {
            $resDoc->addChild('isNotBookableReason', $reserveDocInfos->data->isNotBookableReason);
            $resDoc->addChild('error', 0);
            $resDoc->addChild('code', $reserveDocInfos->data->isNotBookableReason);
        } elseif ($reserveDocInfos->error != '') {
            $resDoc->addChild('error', 0);
            $resDoc->addChild('code', $reserveDocInfos->error);
        } else {
            $resDoc->addChild('infosres', 'OK');
            $resDoc->addChild('error', 1);
            $resDoc->addChild('code', 1);
        }

        return $res->asXML();
    }

    private function formatResultCopyDetails($copyDetailsInfos)
    {
        $message = '';
        if (!empty($copyDetailsInfos->error)) {
            $message = $copyDetailsInfos->error;
        }
        if ($copyDetailsInfos->data->items) {
            $xmlItem = '';
            foreach ($copyDetailsInfos->data->items as $item) {
                $xmlItem .=
                    '<item>' .
                    '<library>' .
                    '<name>'.$item->libraryName.'</name>' .
                    '</library>' .
                    '<code>' . $item->barCode . '</code>' .
                    '<id>' . $item->id . '</id>' .
                    '<cote>' . $item->cote . '</cote>' .
                    '<targetAudience>' .
                    '<name>' . $item->targetAudience . '</name>' .
                    '</targetAudience>' .
                    '<note>' . $item->note . '</note>' .
                    '<price>' . $item->price . '</price>' .
                    '<inventoryDate>'.$item->inventoryDate .'</inventoryDate>' .
                    '<localization>' .
                    '<name>' . htmlspecialchars($item->localization) . '</name>' .
                    '</localization>' .
                    '<sublocalization>' .
                    '<name>' . htmlspecialchars($item->sublocalization) . '</name>' .
                    '</sublocalization>' .
                    '<support>' .
                    '<name>' . $item->support . '</name>' .
                    '</support>' .
                    '<loan>'. $item->availabilityStatus .'</loan>' .
                    '</item>';
            }
        }

        if (empty($message)) {
            $res = simplexml_load_string(
                self::XML_HEADER . '<root>' .
                '<items>' . $xmlItem . '</items>' .
                '</root>'
            );
        } else {
            $res = simplexml_load_string(
                self::XML_HEADER . '<root>' .
                '<error>' . $message . '</error>' .
                '</root>'
            );
        }

        return $res->asXML();
    }

    private function formatResultReserveCancel($reserveCancelInfos, $resid)
    {
        $message = '';
        if ($reserveCancelInfos->data->errorMessage != '' ) {
            $message = $reserveCancelInfos->data->errorMessage;
        }
        $res = new SimpleXMLElement(self::XML_HEADER . '<root></root>');
        $resCancel = $res->addChild('reservationCancel');
        $resCancel->addChild('sigb', self::nameClass);
        $resCancel->addChild('resid', $resid);
        if (!empty($message)) {
            $res->addChild('error', $message);
        }
        $res->addChild('code', 0); // TODO : utilité ?

        return $res->asXML();
    }

    private function formatResultGetNotice($noticeInfos)
    {
        if (!empty($noticeInfos->error)) {
            return self::XML_HEADER . '<root><error>' . htmlspecialchars($noticeInfos->error) . '</error></root>';
        }
        $xmlItem = '';
        $xmlDescData = '';
        if ($noticeInfos->data->results) {
            $res = $noticeInfos->data->results[0];
            foreach ($res->SearchResultBibRecord->items as $item) {
                $xmlItem .=
                    '<item>' .
                    '<library>' .
                    '<name>' . $item->libraryName . '</name>' .
                    '</library>' .
                    '<code>' . $item->barCode . '</code>' .
                    '<id>' . $item->id . '</id>' .
                    '<cote>' . $item->cote . '</cote>' .
                    '<targetAudience>' .
                    '<name>' . $item->targetAudience . '</name>' .
                    '</targetAudience>' .
                    '<note>' . htmlspecialchars($item->note) . '</note>' .
                    '<price>' . $item->price . '</price>' .
                    '<inventoryDate>' . $item->inventoryDate . '</inventoryDate>' .
                    '<localization>' .
                    '<name>' . htmlspecialchars($item->localization) . '</name>' .
                    '</localization>' .
                    '<sublocalization>' .
                    '<name>' . htmlspecialchars($item->sublocalization) . '</name>' .
                    '</sublocalization>' .
                    '<support>' .
                    '<name>' . $item->support . '</name>' .
                    '</support>' .
                    '<loan>' . $item->availabilityStatus . '</loan>' .
                    '</item>';
            }

            if($res->SearchResultBibRecord) {
                $bibRecord = $res->SearchResultBibRecord;
                $docTypeName = isset($bibRecord->format) && count($bibRecord->format)  > 0 ? $bibRecord->format[0] : '';

                $xmlDescData =
                    '<data>' .
                    self::buildDocType($docTypeName) .
                    self::buildIsbnEan($bibRecord->ean) .
                    self::buildTitles($bibRecord) .
                    self::buildAllResponsibles($bibRecord) .
                    self::buildEditors($bibRecord) .
                    self::buildAllLanguages($bibRecord) .
                    self::buildNotes($bibRecord) .
                    self::buildPhysicalDescription($bibRecord) .
                    self::buildCollectionLinks($bibRecord) .
                    self::buildSerieLinks($bibRecord) .
                    '</data>';
            }


        }

        $res = simplexml_load_string(
            self::XML_HEADER .
            '<root>' .
            '<bibrecord>' . $xmlDescData . '</bibrecord>' .
            '<items>' . $xmlItem . '</items>' .
            '</root>'
        );

        return $res->asXML();
    }

    private function formatResultAccountDetails($account)
    {
        if (empty($account->error)) {
            $account->details->code = $account->details->barcode;
            unset($account->details->barcode);

            $account->details->secondaryname = $account->details->firstname;
            unset($account->details->firstname);

            $account->details->networkId = $this->idClient;

            // Delete duplicate loans and booking list
            unset($account->details->loans);
            unset($account->details->bookings);

            // Format booking list
            foreach ($account->bookings->list as $booking) {
                $this->reviseBibRecordInfo($booking);
            }
        }
        return serialize($account);
    }

    public function login($user, $pass, $ldap=false)
    {
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->post($this->buildPath("/user/login?username=" . $user . "&password=" . $pass));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultLogin($jsonresponse, $user);
    }

    public function accountDetails($userInt, $history = true)
    {
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);

        $this->oJSON->get($this->buildPath("/user/" . $userInt), false);
        $jsonresponseDetails = $this->decodeResponse($this->oJSON);

        $jsonresponse = new stdClass();
        if ($jsonresponseDetails->error == "") {
            $jsonresponse->details = $jsonresponseDetails->data;

            $this->bStandalone = true;
            $jsonresponse->loans->list = $jsonresponseDetails->data->loans;

            // Formatage des données Flora pour se conformer au format Decalog
            foreach ($jsonresponse->loans->list as $loan) {
                $this->reviseBibRecordInfo($loan);
                if(!empty($loan->endDate) && empty($loan->dueDate)) {
                    $loan->dueDate = $loan->endDate;
                    unset($loan->endDate);
                }
            }

            if ($history != "false" || $history != false) {
                $jsonresponse->history->list = $jsonresponseDetails->data->loans_history;

                // Formatage des données Flora pour se conformer au format Decalog
                foreach ($jsonresponse->history->list as $loanHistory) {
                    $this->reviseBibRecordInfo($loanHistory);
                    if(!empty($loanHistory->endDate)) {
                        $loanHistory->returnDate = $loanHistory->endDate;
                        unset($loanHistory->endDate);
                    }
                }
            }
            $jsonresponse->bookings->list = $jsonresponseDetails->data->bookings;
        } else {
            $jsonresponse->error = $jsonresponseDetails->error;
        }

        return $this->formatResultAccountDetails($jsonresponse);
    }

    public function getUserLoans($userInt, $serialized = false)
    {
        if (!$this->bStandalone) {
            $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        }
        $this->oJSON->get($this->buildPath("/user/" . $userInt . "/loans"), false);
        $jsonresponse = $this->decodeResponse($this->oJSON);

        if (empty($jsonresponse->error)) {
            if ($serialized != false){
                $loans = serialize($jsonresponse->data);
            } else {
                $loans = $jsonresponse->data;
            }

            // Formatage des données Flora pour se conformer au format Decalog
            foreach ($loans as $loan) {
                $this->reviseBibRecordInfo($loan);
                if(!empty($loan->endDate) && empty($loan->dueDate)) {
                    $loan->dueDate = $loan->endDate;
                    unset($loan->endDate);
                }
            }
        } else {
            if ($serialized != false){
                $loans = serialize($jsonresponse->error);
            } else {
                $loans = $jsonresponse->error;
            }
        }

        return $loans;
    }

    // TODO: n'existe plus chez Flora car "causait des problèmes avec les RGPD" (08/2019)
    public function getUserLoansHistory($userInt, $serialized = false)
    {
        return 'Not yet supported !';
        /*if (!$this->bStandalone) {
            $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        }
        $this->oJSON->get($this->buildPath("/user/" . $userInt . "/loans/history"), false);
        $jsonresponse = $this->decodeResponse($this->oJSON);

        if ($jsonresponse->error == "") {
            if ($serialized != false){
                $loansHistory = serialize($jsonresponse->data);
            } else {
                $loansHistory = $jsonresponse->data;
            }

            // Formatage des données Flora pour se conformer au format Decalog
            foreach ($loansHistory as $loanHistory) {
                $loanHistory->returnDate = $loanHistory->endDate;
                $this->reviseBibRecordInfo($loanHistory);
                self::reviseLoanOrBookingDates($loanHistory);
            }
        } else {
            if ($serialized != false){
                $loansHistory = serialize($jsonresponse->error);
            } else {
                $loansHistory = $jsonresponse->error;
            }
        }

        return $loansHistory;*/
    }

    // TODO: n'existe pas chez Flora actuellement sans récupérer l'intégralité des infos du compte abonné (08/2019)
    public function getUserBookingsHistory($userInt)
    {
        // Ces infos peuvent être récupérées en appelant la même URL que pour accountDetails -> toutes les infos du compte sont en plus remontées
        return 'Not yet supported !';
    }

    public function updateAccount($formDatas)
    {
        $errorReturn = 0;

        // Appel à Flora pour modifier les données
        $informationModified = array('email', 'password', 'newpassword', 'newpassword_confirmation');
        $userid = $formDatas['userid'];
        $data = array();
        foreach ($informationModified as $dataName) {
            if ($formDatas[$dataName] != '') {
                array_push($data, $dataName . '=' . $formDatas[$dataName]);
            }
        }
        $data = implode("&", $data);

        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->put($this->buildPath("/user/" . $userid), $data, false);
        $jsonresponse = $this->decodeResponse($this->oJSON);

        if (!empty($jsonresponse->error) || !empty($jsonresponse->message)) {
            $errorReturn = 1;
        }

        return $this->formatResultUpdateAccount(
            $jsonresponse,
            array(
                'username' => $formDatas['username'],
                'errorCode' => $errorReturn
            )
        );
    }

    // TODO: n'existe pas chez Flora actuellement (08/2019)
    public function userLostPassword($email)
    {
        return 'Not yet supported !';
    }

    public function prolongLoan($id,$userid="")
    {
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->post($this->buildPath('/loan/extend?itemid=' . $id . '&userid=' . $userid));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultProlongLoan($jsonresponse);
    }

    public function reserveInfo($idNotice, $userInt)
    {
        $id = self::getRecordId($idNotice);
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->get($this->buildPath("/booking/user/" . $userInt . "/bibrecord/default:UNIMARC:" . $id));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultReserveInfo(
            $jsonresponse,
            array(
                'idNotice' => 'default:UNIMARC:' . $id,
                'userInt'  => $userInt
            )
        );
    }

    public function reserveDocument($idNotice, $userInt, $site)
    {
        $id = self::getRecordId($idNotice);
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->post($this->buildPath("/booking/bibrecord?userid=" . $userInt . "&bibrecordid=default:UNIMARC:" . $id . "&site=" . $site));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultReserveDocument($jsonresponse, $userInt);
    }

    public function reserveCancel($resid, $userInt)
    {
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->delete($this->buildPath("/booking/user/".$userInt. "/" .$resid), false);
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultReserveCancel($jsonresponse, $resid);
    }

    public function copyDetails($idNotice, $institution, $userInt = "")
    {
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->get($this->buildPath("/catalog/bibrecords/default:UNIMARC:" . $idNotice . "/items"));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultCopyDetails($jsonresponse);
    }

    public function getNotice($idNotice)
    {
        $id = self::getRecordId($idNotice);
        $this->connect($this->hostData, $this->portData, $this->userData, $this->passData);
        $this->oJSON->get($this->buildPath("/catalog/bibrecords/default:UNIMARC:" . $id));
        $jsonresponse = $this->decodeResponse($this->oJSON);

        return $this->formatResultGetNotice($jsonresponse);

    }

    // TODO: Flora ne gère pas les documents électroniques actuellement (08/2019)
    public function reserveElectronicals($idElectronicals, $mode, $userInt)
    {
        return 'Not yet supported !';
    }

    // TODO: la notion de groupement de comptes n'existe pas chez Flora actuellement (08/2019)
    public function updateGroupAccount($formDatas)
    {
        return 'Not yet supported !';
    }

    // TODO: Not yet supported (08/2019)
    public function sendMessage($userInt, $mailId, $action, $objet, $text, $suggTitle, $suggAuthor, $suggEditor, $suggDocType)
    {
        return 'Not yet supported !';
    }

    private function reviseBibRecordInfo($obj) {
        if(empty($obj->recordId)) {
            $obj->recordId = $this->idClient . '_' . str_replace('default:UNIMARC:', '', $obj->bibrecordId);
        }
        unset($obj->bibrecordId);

        if(empty($obj->recordTitle)) {
            $obj->recordTitle = $obj->bibrecordTitle;
        }
        unset($obj->bibrecordTitle);

        if(empty($obj->recordResponsibles)) {
            $obj->recordResponsibles = $obj->bibrecordResponsibles;
        }
        unset($obj->bibrecordResponsibles);

        if(empty($obj->recordEditor)) {
            $obj->recordEditor = $obj->bibrecordEditor;
        }
        unset($obj->bibrecordEditor);

        if(empty($obj->recordPublishedDate)) {
            $obj->recordPublishedDate = $obj->bibrecordPublishedDate;
        }
        unset($obj->bibrecordPublishedDate);

        if(empty($obj->recordCommercialCode)) {
            $obj->recordCommercialCode = $obj->bibrecordCode;
        }
        unset($obj->bibrecordCode);

        if(empty($obj->recordType)) {
            $obj->recordType = $obj->bibrecordType;
        }
        unset($obj->bibrecordType);

        if(!empty($obj->returnLibrary)) {
            $obj->itemLibrary = new stdClass();
            $obj->itemLibrary->name = $obj->returnLibrary;
        }
        unset($obj->returnLibrary);
    }

    private static function buildCollectionLink($collectionTitle) {
        return
            '<collection>' .
            '<collectionTitle>' . $collectionTitle . '</collectionTitle>' .
            '<collectionIssn/>' .
            '<collectionVolume/>' .
            '</collection>';
    }

    private static function buildSerieLinks($bibRecord) {
        $serie = is_array($bibRecord->bibSeries) ? $bibRecord->bibSeries[0] : $bibRecord->bibSeries;
        if(!empty($serie)) {
            return self::buildCollectionLink($serie);
        }
        return '';
    }

    private static function buildCollectionLinks($bibRecord) {
        $collection = is_array($bibRecord->collection) ? $bibRecord->collection[0] : $bibRecord->collection;
        if(!empty($collection)) {
            return self::buildCollectionLink($collection);
        }
        return '';
    }

    private static function buildPhysicalDescription($bibRecord) {
        $physicalDescription = is_array($bibRecord->physical) ? implode(', ', $bibRecord->physical) : $bibRecord->physical;
        if(!empty($physicalDescription)) {
            return '<physicalDescription><materialImportance>'. htmlspecialchars($physicalDescription) . '</materialImportance></physicalDescription>';
        }
        return '';
    }

    private static function buildSummaries($bibRecord) {
        $xml = '';
        $summaries = is_array($bibRecord->description) ? $bibRecord->description : array($bibRecord->description);
        foreach ($summaries as $summary) {
            if(!empty($summary)) {
                $xml .= '<summary>' . htmlspecialchars($summary) . '</summary>';
            }
        }
        if(empty($xml)) {
            return $xml;
        }
        return '<summaries>' . $xml . '</summaries>';
    }

    private static function buildNotes($bibRecord) {
        $xml = '';
        $xml = self::buildSummaries($bibRecord);
        if(empty($xml)) {
            return $xml;
        }
        return '<notes>' . $xml . '</notes>';
    }

    private static function buildLanguage($language) {
        return
            '<language>' .
            '<languageName>' . $language . '</languageName>' .
            '</language>';
    }

    private static function buildLanguages($languages, $type) {
        $xml = '';
        $langs = is_array($languages) ? $languages : array($languages);
        foreach ($langs as $lang) {
            if(!empty($lang)) {
                $xml .= self::buildLanguage($lang);
            }
        }
        if(empty($xml)) {
            return $xml;
        }
        return '<' . $type . '>' . $xml . '</' . $type . '>';
    }

    private static function buildAllLanguages($bibRecord) {
        $xml = '';
        $xml .= self::buildLanguages($bibRecord->language, 'languages');
        $xml .= self::buildLanguages($bibRecord->languageOther, 'otherLanguages');
        return $xml;
    }

    private static function buildEditor($editor, $type, $publishYear) {
        return
            '<editor>' .
            '<editorName>'. $editor . '</editorName>' .
            '<editorType>' . $type . '</editorType>' .
            '<editorDate>' . $publishYear . '</editorDate>' .
            '<editorFunctions/>' .
            '</editor>';
    }

    private static function buildEditors($bibRecord) {
        $xml = '';
        $editors = is_array($bibRecord->publisher) ? $bibRecord->publisher : array($bibRecord->publisher);
        $publishYear = is_array($bibRecord->publishYear) ? $bibRecord->publishYear[0] : $bibRecord->publishYear;
        foreach ($editors as $editor) {
            if(!empty($editor)) {
                $xml .= self::buildEditor($editor, 'corporate', $publishYear);
            }
        }
        if(!empty($xml)) {
            $xml = '<editors>' . $xml . '</editors>';
        }
        return $xml;
    }

    private static function buildResponsible($responsible, $level, $functionCode) {
        return
            '<responsible>' .
            '<responsibleName>' . $responsible . '</responsibleName>' .
            '<responsibleType>PERSON</responsibleType>' .
            '<responsibleLevel>' . $level . '</responsibleLevel>' .
            '<responsibleFunctions>' .
            '<responsibleFunction>' .
            '<responsibleFunctionName>' . $functionCode . '</responsibleFunctionName>' .
            '</responsibleFunction>' .
            '</responsibleFunctions>' .
            '</responsible>';
    }

    private static function buildResponsibles($responsibles, $level, $functionCode) {
        $xml = '';
        $resps = is_array($responsibles) ? $responsibles : array($responsibles);
        foreach ($resps as $resp) {
            if(!empty($resp)) {
                $xml .= self::buildResponsible($resp, $level, $functionCode);
            }
        }
        return $xml;
    }

    private static function buildAllResponsibles($bibRecord) {
        $xml = self::buildResponsibles($bibRecord->author, 'primary', 'Auteur');
        $xml .= self::buildResponsibles($bibRecord->author2, 'secondary', 'Auteur');
        if(empty($xml)) {
            return $xml;
        }
        return '<responsibles>' . $xml . '</responsibles>';
    }

    private static function buildDocType($docTypeName) {
        if(!empty($docTypeName)) {
            return
                '<docType>' .
                '<docTypeName>' . $docTypeName . '</docTypeName>' .
                '</docType>';
        }
        return '';
    }

    private static function buildIsbnEan($isbnEan) {
        $ean = '';
        if(is_array($isbnEan) && count($isbnEan) > 0) {
            $ean = $isbnEan[0];
        }
        if(!empty($isbnEan)) {
            return '<isbn>' . $ean . '</isbn>';
        }
        return '';
    }

    private static function buildTitlePart($titlePartValue, $type, $subType) {
        return
            '<titlePart>' .
            '<titlePartType>' . $type . '</titlePartType>' .
            '<titlePartSubType>' . $subType . '</titlePartSubType>' .
            '<titlePartValue>' . $titlePartValue . '</titlePartValue>' .
            '</titlePart>';
    }

    private static function buildTitleParts($titleParts, $type, $subType) {
        $xml = '';
        $parts = is_array($titleParts) ? $titleParts : array($titleParts);
        foreach ($parts as $part) {
            if(!empty($part)) {
                $xml .= self::buildTitlePart($part, $type, $subType);
            }
        }
        return $xml;
    }

    private static function buildTitles($bibRecord) {
        $xml = '';
        $xmlFragment = '';
        $xmlFragment = self::buildTitleParts($bibRecord->title, 'main', 'title');
        $xmlFragment .= self::buildTitleParts($bibRecord->titleAlt, 'main', 'complement');
        if(!empty($xmlFragment )) {
            $xml .= '<main>' . $xmlFragment . '</main>';
        }
        if(empty($xml)) {
            return $xml;
        }
        return '<titles>' . $xml . '</titles>';
    }

    private static function getRecordId($constructedId) {
        // parts[0] : institution ; parts[1] : documentId
        $parts = explode('_', $constructedId);
        if(count($parts) == 2) {
            return $parts[1];
        }
        return $constructedId;
    }

    public static function version() {
        return self::version;
    }

    public static function infos() {
        return self::nameClass;
    }

    public static function fullInfos() {
        return 'SIGB : FLORA<br />Agent SIGB : ' . self::infos().' (version : '.self::version().')';
    }
}

