<?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 openkm\bean\LockInfo;
use openkm\bean\Record;
use openkm\definition\BaseRecord;
use openkm\util\UriHelper;
use Httpful\Request;
use openkm\util\Status;
use openkm\util\TypeException;
use openkm\exception\AccessDeniedException;
use openkm\exception\PathNotFoundException;
use openkm\exception\RepositoryException;
use openkm\exception\DatabaseException;
use Httpful\Exception\ConnectionErrorException;
use openkm\exception\UnknowException;
use openkm\exception\ItemExistsException;
use openkm\exception\ExtensionException;
use openkm\exception\AutomationException;
use openkm\exception\LockException;
use openkm\exception\IOException;

/**
 * RecordImpl
 *
 * @author sochoa
 */
class RecordImpl extends ClientImpl implements BaseRecord {

    /**
     * Create a new record 
     * 
     * The variable path into the parameter record, must be initializated. It indicates the folder path into OpenKM.
     * 
     *  $record = new Record();
     *  $record.setPath("/okm:root/PKI-100200");
     * 
     * Optionally can be set title variable, the other variables of the Record  ( record ) will not take any effect on record creation.
     * 
     * @param Record $record
     * @return Record Return as a result an object Record.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws ItemExistsException
     * @throws DatabaseException
     * @throws ExtensionException
     * @throws AutomationException
     * @throws UnknowException
     */
    public function createRecord(Record $record) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_CREATE);
            $client = Request::post($uri);
            $recordXML = new \SimpleXMLElement('<record></record>');
            $recordXML->addChild('author', $record->getAuthor());
            $recordXML->addChild('created', $record->getCreated());
            $recordXML->addChild('nodeClass', $record->getNodeClass());
            $recordXML->addChild('path', $record->getPath());
            $recordXML->addChild('permissions', $record->getPermissions());
            if ($record->isSubscribed() == 1) {
                $recordXML->addChild('subscribed', 'true');
            } else {
                $recordXML->addChild('subscribed', 'false');
            }
            $recordXML->addChild('uuid', $record->getUuid());
            //record
            if ($record->getLockInfo() != null) {
                //LockInfo
                $recordXML->addChild('nodePath', $record->getLockInfo()->getNodePath());
                $recordXML->addChild('owner', $record->getLockInfo()->getOwner());
                $recordXML->addChild('token', $record->getLockInfo()->getToken());
            }
            $recordXML->addChild('locked', $record->isLocked());
            $recordXML->addChild('title', $record->getTitle());

            foreach ($record->getCategories() as $category) {
                $categoryXML = $recordXML->addChild('categories');
                $categoryXML->addChild('author', $category->getAuthor());
                $categoryXML->addChild('created', $category->getCreated());
                $categoryXML->addChild('nodeClass', $category->getNodeClass());
                $categoryXML->addChild('path', $category->getPath());
                $categoryXML->addChild('permissions', $category->getPermissions());
                $categoryXML->addChild('subscribed', $category->isSubscribed());
                $categoryXML->addChild('uuid', $category->getUuid());
                $categoryXML->addChild('hasChildren', $category->isHasChildren());
                $categoryXML->addChild('style', $category->getStyle());
            }
            foreach ($record->getKeywords() as $keyword) {
                $recordXML->addChild('keywords', $keyword);
            }

            foreach ($record->getNotes() as $note) {
                $noteXML = $recordXML->addChild('notes');
                $noteXML->addChild('author', $note->getAuthor());
                $noteXML->addChild('date', $note->getDate());
                $noteXML->addChild('path', $note->getPath());
                $noteXML->addChild('text', $note->getText());
            }
            foreach ($record->getSubscriptors() as $subscriptor) {
                $recordXML->addChild('subscriptors', $subscriptor);
            }
            $client->body($recordXML->asXML());
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                return $this->phpRecord($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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::ITEM_EXISTS_EXCEPTION) {
                            throw new ItemExistsException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::EXTENSION_EXCEPTION) {
                            throw new ExtensionException($error . ': ' . $msg);
                        } else if ($error == TypeException::AUTOMATION_EXCEPTION) {
                            throw new AutomationException($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());
        }
    }

    /**
     * Get record properties
     * 
     * @param string $recId The uuid or path of the Record.
     * @return Record Return the record properties.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws UnknowException
     */
    public function getRecordProperties($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_GET_PROPERTIES);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::get($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                return $this->phpRecord($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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($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());
        }
    }

    /**
     * Delete a record.
     * 
     * @param string $recId The uuid or path of the Record.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws PathNotFoundException
     * @throws RepositoryException
     * @throws DatabaseException
     * @throws LockException
     * @throws AutomationException
     * @throws UnknowException
     */
    public function deleteRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_DELETE);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::delete($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::LOCK_EXCEPTION) {
                            throw new LockException($error . ': ' . $msg);
                        } else if ($error == TypeException::AUTOMATION_EXCEPTION) {
                            throw new AutomationException($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());
        }
    }

    /**
     * Record is definetivelly removed from repository.
     * 
     * Usually you will purge records into /okm:trash/userId - the personal trash user locations - but is possible to directly purge any record from the whole repository.
     * When a record is purged only will be able to be restored from a previously repository backup. The purge action remove the record definitely from the repository.
     * 
     * @param string $recId The uuid or path of the Record.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws PathNotFoundException
     * @throws RepositoryException
     * @throws DatabaseException
     * @throws ExtensionException
     * @throws UnknowException}
     */
    public function purgeRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_PURGE);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::EXTENSION_EXCEPTION) {
                            throw new ExtensionException($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());
        }
    }

    /**
     * Change the name of a Record.
     * 
     * @param string $recId The uuid or path of the Record.
     * @param string $newName The new name for the Record
     * @return Record Returns the Record
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws ItemExistsException
     * @throws ExtensionException
     * @throws UnknowException
     */
    public function renameRecord($recId, $newName) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_RENAME);
            $uri .= '?recId=' . urlencode($recId) . '&newName=' . urlencode($newName);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                return $this->phpRecord($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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::ITEM_EXISTS_EXCEPTION) {
                            throw new ItemExistsException($error . ': ' . $msg);
                        } else if ($error == TypeException::EXTENSION_EXCEPTION) {
                            throw new ExtensionException($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());
        }
    }

    /**
     * Move a record into a folder or record.
     * 
     * @param string $recId The uuid or path of the Record.
     * @param string $dstId The uuid or path of the Folder or Record
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws ExtensionException
     * @throws ItemExistsException
     * @throws AutomationException
     * @throws UnknowException
     */
    public function moveRecord($recId, $dstId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_MOVE);
            $uri .= '?recId=' . urlencode($recId) . '&dstId=' . urlencode($dstId);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::EXTENSION_EXCEPTION) {
                            throw new ExtensionException($error . ': ' . $msg);
                        } else if ($error == TypeException::ITEM_EXISTS_EXCEPTION) {
                            throw new ItemExistsException($error . ': ' . $msg);
                        } else if ($error == TypeException::AUTOMATION_EXCEPTION) {
                            throw new AutomationException($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());
        }
    }

    /**
     * Copy a record into a folder or record.
     * 
     * Only the security grants are copyed to destination, the metadata, keywords, etc. of the record are not copyed.
     * 
     * @param string $recId The uuid or path of the Record.
     * @param string $dstId The uuid or path of the Folder or Record
     * @param string $newName The new name for the Record. Value is null, record will preservate the same name.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws ExtensionException
     * @throws ItemExistsException
     * @throws AutomationException
     * @throws IOException
     * @throws UnknowException
     */
    public function copyRecord($recId, $dstId, $newName) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_COPY);
            $uri .= '?recId=' . urlencode($recId) . '&dstId=' . urlencode($dstId) . '&newName=' . $newName;
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::EXTENSION_EXCEPTION) {
                            throw new ExtensionException($error . ': ' . $msg);
                        } else if ($error == TypeException::ITEM_EXISTS_EXCEPTION) {
                            throw new ItemExistsException($error . ': ' . $msg);
                        } else if ($error == TypeException::AUTOMATION_EXCEPTION) {
                            throw new AutomationException($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());
        }
    }

    /**
     * Is valid Record
     * 
     * @param string $recId The uuid or path of the Record.
     * @return bool Return a boolean that indicate if the node is a record or not.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws UnknowException
     */
    public function isValidRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_IS_VALID);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::get($uri);
            $response = $this->getClientWithHTMLResponse($client);
            if ($response->code == Status::OK) {
                if ($response->body == 'true') {
                    return true;
                } else {
                    return false;
                }
            } 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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($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());
        }
    }

    /**
     * Get Record Children
     * 
     * @param string $fldId The uuid or path of the Folder or a record node.
     * @return array Return a list of all records which their parent is fldId.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws UnknowException
     */
    public function getRecordChildren($fldId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_GET_CHILDREN);
            $uri .= '?fldId=' . urlencode($fldId);
            $client = Request::get($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                $records = [];
                foreach ($response->body->record as $recordXML) {
                    $records[] = $this->phpRecord($recordXML);
                }
                return $records;
            } 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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($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());
        }
    }

    /**
     * Lock a record
     * 
     * Only the user who locked the record is allowed to unlock.
     * A locked record can not be modified by other users.
     * 
     * @param string $recId The uuid or path of the Record.
     * @return LockInfo Return an object with the Lock information
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws LockException
     * @throws UnknowException
     */
    public function lockRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_LOCK);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code == Status::OK) {
                return $this->phpLockInfo($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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::LOCK_EXCEPTION) {
                            throw new LockException($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());
        }
    }

    /**
     * Unlock a locked record.
     * 
     * Only the user who locked the document is allowed to unlock.
     * 
     * @param string $recId The uuid or path of the Record.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws LockException
     * @throws UnknowException
     */
    public function unlockRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_UNLOCK);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::LOCK_EXCEPTION) {
                            throw new LockException($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());
        }
    }

    /**
     * Unlock a locked document.
     * 
     * This method allows to unlcok any locked record.
     * It is not mandatory execute this action by the same user who previously executed the checkout lock action.
     * 
     * This action can only be done by a super user ( user with ROLE_ADMIN ).
     * 
     * @param string $recId The uuid or path of the Record.     
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws LockException
     * @throws UnknowException
     */
    public function forceUnlockRecord($recId) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_FORCE_UNLOCK);
            $uri .= '?recId=' . urlencode($recId);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::LOCK_EXCEPTION) {
                            throw new LockException($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());
        }
    }

    /**
     * Set record title.
     * 
     * @param string $recId The uuid or path of the Record.   
     * @param string $title The title of the Record
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws LockException
     * @throws UnknowException
     */
    public function setRecordTitle($recId, $title) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_SET_TITLE);
            $uri .= '?recId=' . urlencode($recId) . '&title=' . urlencode($title);
            $client = Request::put($uri);
            $response = $this->getClient($client);
            if ($response->code != Status::NO_CONTENT) {
                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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($error . ': ' . $msg);
                        } else if ($error == TypeException::LOCK_EXCEPTION) {
                            throw new LockException($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());
        }
    }

    /**
     * Get Record Path
     * 
     * @param string $uuid The uuid of the Record
     * @return string Convert record UUID to record path.
     * @throws ConnectionErrorException
     * @throws AccessDeniedException
     * @throws RepositoryException
     * @throws PathNotFoundException
     * @throws DatabaseException
     * @throws UnknowException
     */
    public function getRecordPath($uuid) {
        try {
            $uri = UriHelper::getUri($this->host, UriHelper::RECORD_GET_PATH);
            $uri .= '?uuid=' . urlencode($uuid);
            $client = Request::get($uri);
            $response = $this->getClientWithHTMLResponse($client);
            if ($response->code == Status::OK) {
                return (string) $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::REPOSITORY_EXCEPTION) {
                            throw new RepositoryException($error . ': ' . $msg);
                        } else if ($error == TypeException::PATH_NOT_FOUND_EXCEPTION) {
                            throw new PathNotFoundException($error . ': ' . $msg);
                        } else if ($error == TypeException::DATABASE_EXCEPTION) {
                            throw new DatabaseException($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());
        }
    }       

}
