<?php
/**
 * Pimcore
 *
 * This source file is subject to the GNU General Public License version 3 (GPLv3)
 * For the full copyright and license information, please view the LICENSE.md and gpl-3.0.txt
 * files that are distributed with this source code.
 *
 * @copyright  Copyright (c) 2009-2016 pimcore GmbH (http://www.pimcore.org)
 * @license    http://www.pimcore.org/license     GNU General Public License version 3 (GPLv3)
 */

use Pimcore\Tool\Session;
use Pimcore\Tool;
Use Pimcore\Config;
use Pimcore\Model\Document;
use Pimcore\Model\Version;
use Pimcore\Model\Site;

class Admin_DocumentController extends \Pimcore\Controller\Action\Admin\Element
{

    /**
     * @var Document\Service
     */
    protected $_documentService;

    public function init()
    {
        parent::init();

        // check permissions
        $notRestrictedActions = array("doc-types");
        if (!in_array($this->getParam("action"), $notRestrictedActions)) {
            $this->checkPermission("documents");
        }

        $this->_documentService = new Document\Service($this->getUser());
    }

    public function getDataByIdAction()
    {

        $document = Document::getById($this->getParam("id"));
        if ($document->isAllowed("view")) {
            $this->_helper->json($document);
        }

        $this->_helper->json(array("success" => false, "message" => "missing_permission"));
    }

    public function treeGetChildsByIdAction()
    {

        $document = Document::getById($this->getParam("node"));

        $documents = array();
        if ($document->hasChilds()) {
            $limit = intval($this->getParam("limit"));
            if (!$this->getParam("limit")) {
                $limit = 100000000;
            }
            $offset = intval($this->getParam("start"));

            $list = new Document\Listing();
            if ($this->getUser()->isAdmin()) {
                $list->setCondition("parentId = ? ", $document->getId());
            } else {

                $userIds = $this->getUser()->getRoles();
                $userIds[] = $this->getUser()->getId();
                $list->setCondition("parentId = ? and
                                        (
                                        (select list from users_workspaces_document where userId in (" . implode(',', $userIds) . ") and LOCATE(CONCAT(path,`key`),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
                                        or
                                        (select list from users_workspaces_document where userId in (" . implode(',', $userIds) . ") and LOCATE(cpath,CONCAT(path,`key`))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
                                        )", $document->getId());
            }

            $list->setOrderKey(["index", "id"]);
            $list->setOrder(["asc","asc"]);

            $list->setLimit($limit);
            $list->setOffset($offset);

            $childsList = $list->load();

            foreach ($childsList as $childDocument) {
                // only display document if listing is allowed for the current user
                if ($childDocument->isAllowed("list")) {
                    $documents[] = $this->getTreeNodeConfig($childDocument);
                }
            }
        }

        if ($this->getParam("limit")) {
            $this->_helper->json(array(
                "offset" => $offset,
                "limit" => $limit,
                "total" => $document->getChildAmount($this->getUser()),
                "nodes" => $documents
            ));
        } else {
            $this->_helper->json($documents);
        }

        $this->_helper->json(false);
    }

    public function addAction()
    {

        $success = false;
        $errorMessage = "";

        // check for permission
        $parentDocument = Document::getById(intval($this->getParam("parentId")));
        if ($parentDocument->isAllowed("create")) {
            $intendedPath = $parentDocument->getFullPath() . "/" . $this->getParam("key");

            if (!Document\Service::pathExists($intendedPath)) {

                $createValues = array(
                    "userOwner" => $this->getUser()->getId(),
                    "userModification" => $this->getUser()->getId(),
                    "published" => false
                );

                $createValues["key"] = $this->getParam("key");

                // check for a docType
                $docType = Document\DocType::getById(intval($this->getParam("docTypeId")));
                if ($docType) {
                    $createValues["template"] = $docType->getTemplate();
                    $createValues["controller"] = $docType->getController();
                    $createValues["action"] = $docType->getAction();
                    $createValues["module"] = $docType->getModule();
                } else if ($this->getParam("type") == "page" || $this->getParam("type") == "snippet" || $this->getParam("type") == "email") {
                    $createValues["controller"] = Config::getSystemConfig()->documents->default_controller;
                    $createValues["action"] = Config::getSystemConfig()->documents->default_action;
                }

                switch ($this->getParam("type")) {
                    case "page":
                        $document = Document\Page::create($this->getParam("parentId"), $createValues, false);
                        $document->setTitle($this->getParam('title', null));
                        $document->setProperty("navigation_name", "text", $this->getParam('name', null), false);
                        $document->save();
                        $success = true;
                        break;
                    case "snippet":
                        $document = Document\Snippet::create($this->getParam("parentId"), $createValues);
                        $success = true;
                        break;
                    case "email": //ckogler
                        $document = Document\Email::create($this->getParam("parentId"), $createValues);
                        $success = true;
                        break;
                    case "link":
                        $document = Document\Link::create($this->getParam("parentId"), $createValues);
                        $success = true;
                        break;
                    case "hardlink":
                        $document = Document\Hardlink::create($this->getParam("parentId"), $createValues);
                        $success = true;
                        break;
                    case "folder":
                        $document = Document\Folder::create($this->getParam("parentId"), $createValues);
                        $document->setPublished(true);
                        try {
                            $document->save();
                            $success = true;
                        } catch (\Exception $e) {
                            $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
                        }
                        break;
                    default:
                        $classname = "\\Pimcore\\Model\\Document\\" . ucfirst($this->getParam("type"));

                        // this is the fallback for custom document types using prefixes
                        // so we need to check if the class exists first
                        if(!\Pimcore\Tool::classExists($classname)) {
                            $oldStyleClass = "\\Document_" . ucfirst($this->getParam("type"));
                            if(\Pimcore\Tool::classExists($oldStyleClass)) {
                                $classname = $oldStyleClass;
                            }
                        }

                        if (Tool::classExists($classname)) {
                            $document = $classname::create($this->getParam("parentId"), $createValues);
                            try {
                                $document->save();
                                $success = true;
                            } catch (\Exception $e) {
                                $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
                            }
                            break;
                        } else {
                            \Logger::debug("Unknown document type, can't add [ " . $this->getParam("type") . " ] ");
                        }
                        break;
                }
            } else {
                $errorMessage = "prevented adding a document because document with same path+key [ $intendedPath ] already exists";
                \Logger::debug($errorMessage);
            }
        } else {
            $errorMessage = "prevented adding a document because of missing permissions";
            \Logger::debug($errorMessage);
        }

        if ($success) {
            $this->_helper->json(array(
                "success" => $success,
                "id" => $document->getId(),
                "type" => $document->getType()
            ));
        } else {
            $this->_helper->json(array(
                "success" => $success,
                "message" => $errorMessage
            ));
        }


    }

    public function deleteAction()
    {
        if ($this->getParam("type") == "childs") {

            $parentDocument = Document::getById($this->getParam("id"));

            $list = new Document\Listing();
            $list->setCondition("path LIKE '" . $parentDocument->getFullPath() . "/%'");
            $list->setLimit(intval($this->getParam("amount")));
            $list->setOrderKey("LENGTH(path)", false);
            $list->setOrder("DESC");

            $documents = $list->load();

            $deletedItems = array();
            foreach ($documents as $document) {
                $deletedItems[] = $document->getFullPath();
                if ($document->isAllowed("delete")) {
                    $document->delete();
                }
            }

            $this->_helper->json(array("success" => true, "deleted" => $deletedItems));

        } else if ($this->getParam("id")) {
            $document = Document::getById($this->getParam("id"));
            if ($document->isAllowed("delete")) {
                try {
                    $document->delete();
                    $this->_helper->json(array("success" => true));
                } catch (\Exception $e) {
                    \Logger::err($e);
                    $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
                }
            }
        }

        $this->_helper->json(array("success" => false, "message" => "missing_permission"));
    }

    public function deleteInfoAction()
    {
        $hasDependency = false;

        try {
            $document = Document::getById($this->getParam("id"));
            $hasDependency = $document->getDependencies()->isRequired();
        } catch (\Exception $e) {
            \Logger::err("failed to access document with id: " . $this->getParam("id"));
        }

        $deleteJobs = array();

        // check for childs
        if ($document instanceof Document) {

            $deleteJobs[] = array(array(
                "url" => "/admin/recyclebin/add",
                "params" => array(
                    "type" => "document",
                    "id" => $document->getId()
                )
            ));

            $hasChilds = $document->hasChilds();
            if (!$hasDependency) {
                $hasDependency = $hasChilds;
            }

            $childs = 0;
            if ($hasChilds) {
                // get amount of childs
                $list = new Document\Listing();
                $list->setCondition("path LIKE '" . $document->getFullPath() . "/%'");
                $childs = $list->getTotalCount();

                if ($childs > 0) {
                    $deleteObjectsPerRequest = 5;
                    for ($i = 0; $i < ceil($childs / $deleteObjectsPerRequest); $i++) {
                        $deleteJobs[] = array(array(
                            "url" => "/admin/document/delete",
                            "params" => array(
                                "step" => $i,
                                "amount" => $deleteObjectsPerRequest,
                                "type" => "childs",
                                "id" => $document->getId()
                            )
                        ));
                    }
                }
            }

            // the object itself is the last one
            $deleteJobs[] = array(array(
                "url" => "/admin/document/delete",
                "params" => array(
                    "id" => $document->getId()
                )
            ));
        }

        $this->_helper->json(array(
            "hasDependencies" => $hasDependency,
            "childs" => $childs,
            "deletejobs" => $deleteJobs
        ));
    }

    public function updateAction()
    {

        $success = false;
        $allowUpdate = true;

        $document = Document::getById($this->getParam("id"));

        // this prevents the user from renaming, relocating (actions in the tree) if the newest version isn't the published one
        // the reason is that otherwise the content of the newer not published version will be overwritten
        if ($document instanceof Document\PageSnippet) {
            $latestVersion = $document->getLatestVersion();
            if ($latestVersion && $latestVersion->getData()->getModificationDate() != $document->getModificationDate()) {
                $this->_helper->json(array("success" => false, "message" => "You can't relocate if there's a newer not published version"));
            }
        }

        if ($document->isAllowed("settings")) {

            // if the position is changed the path must be changed || also from the childs
            if ($this->getParam("parentId")) {
                $parentDocument = Document::getById($this->getParam("parentId"));

                //check if parent is changed
                if ($document->getParentId() != $parentDocument->getId()) {

                    if (!$parentDocument->isAllowed("create")) {
                        throw new \Exception("Prevented moving document - no create permission on new parent ");
                    }

                    $intendedPath = $parentDocument->getPath();
                    $pKey = $parentDocument->getKey();
                    if (!empty($pKey)) {
                        $intendedPath .= $parentDocument->getKey() . "/";
                    }

                    $documentWithSamePath = Document::getByPath($intendedPath . $document->getKey());

                    if ($documentWithSamePath != null) {
                        $allowUpdate = false;
                    }

                    if($document->isLocked()) {
                        $allowUpdate = false;
                    }
                }
            }

            if ($allowUpdate) {
                $blockedVars = array("controller", "action", "module");

                if (!$document->isAllowed("rename") && $this->getParam("key")) {
                    $blockedVars[] = "key";
                    \Logger::debug("prevented renaming document because of missing permissions ");
                }

                foreach ($this->getAllParams() as $key => $value) {
                    if (!in_array($key, $blockedVars)) {
                        $document->setValue($key, $value);
                    }
                }

                // if changed the index change also all documents on the same level
                if ($this->getParam("index") !== null) {
                    $list = new Document\Listing();
                    $list->setCondition("parentId = ? AND id != ?", array($this->getParam("parentId"), $document->getId()));
                    $list->setOrderKey("index");
                    $list->setOrder("asc");
                    $childsList = $list->load();

                    $count = 0;
                    foreach ($childsList as $child) {
                        if ($count == intval($this->getParam("index"))) {
                            $count++;
                        }
                        $child->saveIndex($count);
                        $count++;
                    }
                }

                $document->setUserModification($this->getUser()->getId());
                try {
                    $document->save();
                    $success = true;
                } catch (\Exception $e) {
                    $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
                }
            } else {
                $msg = "Prevented moving document, because document with same path+key already exists or the document is locked. ID: " . $document->getId();
                \Logger::debug($msg);
                $this->_helper->json(array("success" => false, "message" => $msg));
            }
        } else if ($document->isAllowed("rename") && $this->getParam("key")) {
            //just rename
            try {
                $document->setKey($this->getParam("key"));
                $document->setUserModification($this->getUser()->getId());
                $document->save();
                $success = true;
            } catch (\Exception $e) {
                $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
            }
        } else {
            \Logger::debug("Prevented update document, because of missing permissions.");
        }

        $this->_helper->json(array("success" => $success));
    }

    public function docTypesAction()
    {

        if ($this->getParam("data")) {

            $this->checkPermission("document_types");

            if ($this->getParam("xaction") == "destroy") {

                $id = \Zend_Json::decode($this->getParam("data"));

                $type = Document\DocType::getById($id);
                $type->delete();

                $this->_helper->json(array("success" => true, "data" => array()));
            } else if ($this->getParam("xaction") == "update") {

                $data = \Zend_Json::decode($this->getParam("data"));

                // save type
                $type = Document\DocType::getById($data["id"]);

                $type->setValues($data);
                $type->save();

                $this->_helper->json(array("data" => $type, "success" => true));
            } else if ($this->getParam("xaction") == "create") {
                $data = \Zend_Json::decode($this->getParam("data"));
                unset($data["id"]);

                // save type
                $type = Document\DocType::create();
                $type->setValues($data);

                $type->save();

                $this->_helper->json(array("data" => $type, "success" => true));
            }
        } else {
            // get list of types
            $list = new Document\DocType\Listing();

            if ($this->getParam("sort")) {
                $list->setOrderKey($this->getParam("sort"));
                $list->setOrder($this->getParam("dir"));
            }

            $list->load();

            $docTypes = array();
            foreach ($list->getDocTypes() as $type) {
                if ($this->getUser()->isAllowed($type->getId(), "docType")) {
                    $docTypes[] = $type;
                }
            }

            $this->_helper->json(array("data" => $docTypes, "success" => true, "total" => count($docTypes)));
        }

        $this->_helper->json(false);
    }

    public function getDocTypesAction()
    {

        $list = new Document\DocType\Listing();
        if ($this->getParam("type")) {
            $type = $this->getParam("type");
            if (Document\Service::isValidType($type)) {
                $list->setCondition("type = ?", $type);
            }
        }
        $list->setOrderKey(array("priority", "name"));
        $list->setOrder(array("desc", "ASC"));
        $list->load();


        $docTypes = array();
        foreach ($list->getDocTypes() as $type) {
            $docTypes[] = $type;
        }

        $this->_helper->json(array("docTypes" => $docTypes));
    }

    public function getPathForIdAction()
    {

        $document = Document::getById($this->getParam("id"));
        die($document->getPath() . $document->getKey());
    }

    public function versionToSessionAction()
    {

        $version = Version::getById($this->getParam("id"));
        $document = $version->loadData();

        Session::useSession(function ($session) use ($document) {
            $key = "document_" . $document->getId();
            $session->$key = $document;
        }, "pimcore_documents");

        $this->removeViewRenderer();
    }

    public function publishVersionAction()
    {

        $this->versionToSessionAction();

        $version = Version::getById($this->getParam("id"));
        $document = $version->loadData();

        $currentDocument = Document::getById($document->getId());
        if ($currentDocument->isAllowed("publish")) {
            $document->setPublished(true);
            try {

                $document->setKey($currentDocument->getKey());
                $document->setPath($currentDocument->getPath());
                $document->setUserModification($this->getUser()->getId());

                $document->save();
            } catch (\Exception $e) {
                $this->_helper->json(array("success" => false, "message" => $e->getMessage()));
            }
        }

        $this->_helper->json(array("success" => true));
    }

    public function updateSiteAction()
    {

        $domains = $this->getParam("domains");
        $domains = str_replace(" ", "", $domains);
        $domains = explode("\n", $domains);

        try {
            $site = Site::getByRootId(intval($this->getParam("id")));
        } catch (\Exception $e) {
            $site = Site::create(array(
                "rootId" => intval($this->getParam("id"))
            ));
        }

        $site->setDomains($domains);
        $site->setMainDomain($this->getParam("mainDomain"));
        $site->setErrorDocument($this->getParam("errorDocument"));
        $site->setRedirectToMainDomain(($this->getParam("redirectToMainDomain") == "true") ? true : false);
        $site->save();

        $site->setRootDocument(null); // do not send the document to the frontend
        $this->_helper->json($site);
    }

    public function removeSiteAction()
    {

        $site = Site::getByRootId(intval($this->getParam("id")));
        $site->delete();

        $this->_helper->json(array("success" => true));
    }

    public function copyInfoAction()
    {

        $transactionId = time();
        $pasteJobs = array();

        Session::useSession(function ($session) use ($transactionId) {
            $session->$transactionId = array("idMapping" => array());
        }, "pimcore_copy");

        if ($this->getParam("type") == "recursive" || $this->getParam("type") == "recursive-update-references") {

            $document = Document::getById($this->getParam("sourceId"));

            // first of all the new parent
            $pasteJobs[] = array(array(
                "url" => "/admin/document/copy",
                "params" => array(
                    "sourceId" => $this->getParam("sourceId"),
                    "targetId" => $this->getParam("targetId"),
                    "type" => "child",
                    "enableInheritance" => $this->getParam("enableInheritance"),
                    "transactionId" => $transactionId,
                    "saveParentId" => true,
                    "resetIndex" => true
                )
            ));


            $childIds = array();
            if ($document->hasChilds()) {
                // get amount of childs
                $list = new Document\Listing();
                $list->setCondition("path LIKE '" . $document->getFullPath() . "/%'");
                $list->setOrderKey("LENGTH(path)", false);
                $list->setOrder("ASC");
                $childIds = $list->loadIdList();

                if (count($childIds) > 0) {
                    foreach ($childIds as $id) {
                        $pasteJobs[] = array(array(
                            "url" => "/admin/document/copy",
                            "params" => array(
                                "sourceId" => $id,
                                "targetParentId" => $this->getParam("targetId"),
                                "sourceParentId" => $this->getParam("sourceId"),
                                "type" => "child",
                                "enableInheritance" => $this->getParam("enableInheritance"),
                                "transactionId" => $transactionId
                            )
                        ));
                    }
                }
            }


            // add id-rewrite steps
            if ($this->getParam("type") == "recursive-update-references") {
                for ($i = 0; $i < (count($childIds) + 1); $i++) {
                    $pasteJobs[] = array(array(
                        "url" => "/admin/document/copy-rewrite-ids",
                        "params" => array(
                            "transactionId" => $transactionId,
                            "enableInheritance" => $this->getParam("enableInheritance"),
                            "_dc" => uniqid()
                        )
                    ));
                }
            }
        } else if ($this->getParam("type") == "child" || $this->getParam("type") == "replace") {
            // the object itself is the last one
            $pasteJobs[] = array(array(
                "url" => "/admin/document/copy",
                "params" => array(
                    "sourceId" => $this->getParam("sourceId"),
                    "targetId" => $this->getParam("targetId"),
                    "type" => $this->getParam("type"),
                    "enableInheritance" => $this->getParam("enableInheritance"),
                    "transactionId" => $transactionId,
                    "resetIndex" => ($this->getParam("type") == "child")
                )
            ));
        }


        $this->_helper->json(array(
            "pastejobs" => $pasteJobs
        ));
    }

    public function copyRewriteIdsAction()
    {

        $transactionId = $this->getParam("transactionId");

        $idStore = Session::useSession(function ($session) use ($transactionId) {
            return $session->$transactionId;
        }, "pimcore_copy");

        if (!array_key_exists("rewrite-stack", $idStore)) {
            $idStore["rewrite-stack"] = array_values($idStore["idMapping"]);
        }

        $id = array_shift($idStore["rewrite-stack"]);
        $document = Document::getById($id);

        if ($document) {
            // create rewriteIds() config parameter
            $rewriteConfig = array("document" => $idStore["idMapping"]);

            $document = Document\Service::rewriteIds($document, $rewriteConfig, array(
                "enableInheritance" => ($this->getParam("enableInheritance") == "true") ? true : false
            ));

            $document->setUserModification($this->getUser()->getId());
            $document->save();
        }

        // write the store back to the session
        Session::useSession(function ($session) use ($transactionId, $idStore) {
            $session->$transactionId = $idStore;
        }, "pimcore_copy");

        $this->_helper->json(array(
            "success" => true,
            "id" => $id
        ));
    }

    public function copyAction()
    {
        $success = false;
        $sourceId = intval($this->getParam("sourceId"));
        $source = Document::getById($sourceId);
        $session = Session::get("pimcore_copy");

        $targetId = intval($this->getParam("targetId"));
        if ($this->getParam("targetParentId")) {
            $sourceParent = Document::getById($this->getParam("sourceParentId"));

            // this is because the key can get the prefix "_copy" if the target does already exists
            if ($session->{$this->getParam("transactionId")}["parentId"]) {
                $targetParent = Document::getById($session->{$this->getParam("transactionId")}["parentId"]);
            } else {
                $targetParent = Document::getById($this->getParam("targetParentId"));
            }


            $targetPath = preg_replace("@^" . $sourceParent->getFullPath() . "@", $targetParent . "/", $source->getPath());
            $target = Document::getByPath($targetPath);
        } else {
            $target = Document::getById($targetId);
        }

        if ($target instanceof Document) {
            if ($target->isAllowed("create")) {
                if ($source != null) {
                    if ($this->getParam("type") == "child") {
                        $enableInheritance = ($this->getParam("enableInheritance") == "true") ? true : false;
                        $resetIndex = ($this->getParam("resetIndex") == "true") ? true : false;

                        $newDocument = $this->_documentService->copyAsChild($target, $source, $enableInheritance, $resetIndex);
                        $session->{$this->getParam("transactionId")}["idMapping"][(int)$source->getId()] = (int)$newDocument->getId();

                        // this is because the key can get the prefix "_copy" if the target does already exists
                        if ($this->getParam("saveParentId")) {
                            $session->{$this->getParam("transactionId")}["parentId"] = $newDocument->getId();
                        }

                        Session::writeClose();
                    } else if ($this->getParam("type") == "replace") {
                        $this->_documentService->copyContents($target, $source);
                    }

                    $success = true;
                } else {
                    \Logger::error("prevended copy/paste because document with same path+key already exists in this location");
                }
            } else {
                \Logger::error("could not execute copy/paste because of missing permissions on target [ " . $targetId . " ]");
                $this->_helper->json(array("success" => false, "message" => "missing_permission"));
            }
        }

        $this->_helper->json(array("success" => $success));
    }


    public function diffVersionsAction()
    {
        $versionFrom = Version::getById($this->getParam("from"));
        $docFrom = $versionFrom->loadData();
        $request = $this->getRequest();

        $sessionName = Tool\Session::getOption("name");
        $prefix = $request->getScheme() . "://" . $request->getHttpHost() . $docFrom->getFullPath() . "?pimcore_version=";
        $fromUrl = $prefix . $this->getParam("from") . "&" . $sessionName . "=" . $_COOKIE[$sessionName];
        $toUrl = $prefix . $this->getParam("to") . "&" . $sessionName . "=" . $_COOKIE[$sessionName];

        $fromFile = PIMCORE_SYSTEM_TEMP_DIRECTORY . "/version-diff-tmp-" . uniqid() . ".png";
        $toFile = PIMCORE_SYSTEM_TEMP_DIRECTORY . "/version-diff-tmp-" . uniqid() . ".png";
        $diffFile = PIMCORE_SYSTEM_TEMP_DIRECTORY . "/version-diff-tmp-" . uniqid() . ".png";

        if(\Pimcore\Image\HtmlToImage::isSupported() && class_exists("Imagick")) {
            \Pimcore\Image\HtmlToImage::convert($fromUrl, $fromFile);
            \Pimcore\Image\HtmlToImage::convert($toUrl, $toFile);

            $image1 = new Imagick($fromFile);
            $image2 = new Imagick($toFile);

            if($image1->getImageWidth() == $image2->getImageWidth() && $image1->getImageHeight() == $image2->getImageHeight()) {
                $result = $image1->compareImages($image2, Imagick::METRIC_MEANSQUAREERROR);
                $result[0]->setImageFormat("png");

                $result[0]->writeImage($diffFile);
                $result[0]->clear();
                $result[0]->destroy();

                $this->view->image = base64_encode(file_get_contents($diffFile));
                unlink($diffFile);
            } else {
                $this->view->image1 = base64_encode(file_get_contents($fromFile));
                $this->view->image2 = base64_encode(file_get_contents($toFile));
            }

            // cleanup
            $image1->clear();
            $image1->destroy();
            $image2->clear();
            $image2->destroy();

            unlink($fromFile);
            unlink($toFile);
        } else {
            $this->renderScript("document/diff-versions-unsupported.php");
        }
    }

    /**
     * @param $element
     * @return array
     */
    protected function getTreeNodeConfig($element)
    {
        $childDocument = $element;

        $tmpDocument = array(
            "id" => $childDocument->getId(),
            "text" => $childDocument->getKey(),
            "type" => $childDocument->getType(),
            "path" => $childDocument->getFullPath(),
            "basePath" => $childDocument->getPath(),
            "locked" => $childDocument->isLocked(),
            "lockOwner" => $childDocument->getLocked() ? true : false,
            "published" => $childDocument->isPublished(),
            "elementType" => "document",
            "leaf" => true,
            "permissions" => array(
                "view" => $childDocument->isAllowed("view"),
                "remove" => $childDocument->isAllowed("delete"),
                "settings" => $childDocument->isAllowed("settings"),
                "rename" => $childDocument->isAllowed("rename"),
                "publish" => $childDocument->isAllowed("publish"),
                "unpublish" => $childDocument->isAllowed("unpublish")
            )
        );

        // add icon
        $tmpDocument["iconCls"] = "pimcore_icon_" . $childDocument->getType();
        if (\Pimcore\Tool\Admin::isExtJS6()) {
            $tmpDocument["expandable"] = $childDocument->hasChilds();
            $tmpDocument["loaded"] = !$childDocument->hasChilds();
        }

        // set type specific settings
        if ($childDocument->getType() == "page") {
            $tmpDocument["leaf"] = false;
            $tmpDocument["expanded"] = $childDocument->hasNoChilds();
            $tmpDocument["permissions"]["create"] = $childDocument->isAllowed("create");
            $tmpDocument["iconCls"] = "pimcore_icon_page";

            // test for a site
            try {
                $site = Site::getByRootId($childDocument->getId());
                $tmpDocument["iconCls"] = "pimcore_icon_site";
                unset($site->rootDocument);
                $tmpDocument["site"] = $site;
            } catch (\Exception $e) {
            }
        } else if ($childDocument->getType() == "folder" || $childDocument->getType() == "link" || $childDocument->getType() == "hardlink") {
            $tmpDocument["leaf"] = false;
            $tmpDocument["expanded"] = $childDocument->hasNoChilds();

            if ($childDocument->hasNoChilds() && $childDocument->getType() == "folder") {
                $tmpDocument["iconCls"] = "pimcore_icon_folder";
            }
            $tmpDocument["permissions"]["create"] = $childDocument->isAllowed("create");
        } else if (method_exists($childDocument, "getTreeNodeConfig")) {
            $tmp = $childDocument->getTreeNodeConfig();
            $tmpDocument = array_merge($tmpDocument, $tmp);
        }

        $tmpDocument["qtipCfg"] = array(
            "title" => "ID: " . $childDocument->getId(),
            "text" => "Type: " . $childDocument->getType()
        );

        // PREVIEWS temporary disabled, need's to be optimized some time
        if ($childDocument instanceof Document\Page && Config::getSystemConfig()->documents->generatepreview) {
            $thumbnailFile = PIMCORE_TEMPORARY_DIRECTORY . "/document-page-previews/document-page-screenshot-" . $childDocument->getId() . ".jpg";

            // only if the thumbnail exists and isn't out of time
            if (file_exists($thumbnailFile) && filemtime($thumbnailFile) > ($childDocument->getModificationDate() - 20)) {
                $thumbnailPath = str_replace(PIMCORE_DOCUMENT_ROOT, "", $thumbnailFile);
                $tmpDocument["thumbnail"] = $thumbnailPath;
            }
        }

        $tmpDocument["cls"] = "";

        if (!$childDocument->isPublished()) {
            $tmpDocument["cls"] .= "pimcore_unpublished ";
        }

        if ($childDocument->isLocked()) {
            $tmpDocument["cls"] .= "pimcore_treenode_locked ";
        }
        if ($childDocument->getLocked()) {
            $tmpDocument["cls"] .= "pimcore_treenode_lockOwner ";
        }

        return $tmpDocument;
    }

    public function getIdForPathAction()
    {

        if ($doc = Document::getByPath($this->getParam("path"))) {
            $this->_helper->json(array(
                "id" => $doc->getId(),
                "type" => $doc->getType()
            ));
        } else {
            $this->_helper->json(false);
        }

        $this->removeViewRenderer();
    }


    /**
     * SEO PANEL
     */
    public function seopanelTreeRootAction()
    {

        $this->checkPermission("seo_document_editor");

        $root = Document::getById(1);
        if ($root->isAllowed("list")) {

            $nodeConfig = $this->getTreeNodeConfig($root);
            $nodeConfig["title"] = $root->getTitle();
            $nodeConfig["description"] = $root->getDescription();

            $this->_helper->json($nodeConfig);
        }

        $this->_helper->json(array("success" => false, "message" => "missing_permission"));
    }


    public function seopanelTreeAction()
    {

        $this->checkPermission("seo_document_editor");

        $document = Document::getById($this->getParam("node"));

        $documents = array();
        if ($document->hasChilds()) {

            $list = new Document\Listing();
            $list->setCondition("parentId = ?", $document->getId());
            $list->setOrderKey("index");
            $list->setOrder("asc");

            $childsList = $list->load();

            foreach ($childsList as $childDocument) {
                // only display document if listing is allowed for the current user
                if ($childDocument->isAllowed("list")) {

                    $list = new Document\Listing();
                    $list->setCondition("path LIKE ? and type = ?", array($childDocument->getFullPath() . "/%", "page"));

                    if ($childDocument instanceof Document\Page || $list->getTotalCount() > 0) {
                        $nodeConfig = $this->getTreeNodeConfig($childDocument);

                        if (method_exists($childDocument, "getTitle") && method_exists($childDocument, "getDescription")) {

                            // anaylze content
                            $nodeConfig["links"] = 0;
                            $nodeConfig["externallinks"] = 0;
                            $nodeConfig["h1"] = 0;
                            $nodeConfig["h1_text"] = "";
                            $nodeConfig["hx"] = 0;
                            $nodeConfig["imgwithalt"] = 0;
                            $nodeConfig["imgwithoutalt"] = 0;

                            $title = null;
                            $description = null;

                            try {

                                // cannot use the rendering service from Document\Service::render() because of singleton's ...
                                // $content = Document\Service::render($childDocument, array("pimcore_admin" => true, "pimcore_preview" => true), true);

                                $request = $this->getRequest();

                                $contentUrl = $request->getScheme() . "://" . $request->getHttpHost() . $childDocument->getFullPath();
                                $content = Tool::getHttpData($contentUrl, array(
                                    "pimcore_preview" => true,
                                    "pimcore_admin" => true,
                                    "_dc" => time()
                                ));

                                if ($content) {
                                    include_once("simple_html_dom.php");
                                    $html = str_get_html($content);
                                    if ($html) {
                                        $nodeConfig["links"] = count($html->find("a"));
                                        $nodeConfig["externallinks"] = count($html->find("a[href^=http]"));
                                        $nodeConfig["h1"] = count($html->find("h1"));

                                        $h1 = $html->find("h1", 0);
                                        if ($h1) {
                                            $nodeConfig["h1_text"] = strip_tags($h1->innertext);
                                        }

                                        $title = $html->find("title", 0);
                                        if ($title) {
                                            $title = html_entity_decode(trim(strip_tags($title->innertext)), null, "UTF-8");
                                        }

                                        $description = $html->find("meta[name=description]", 0);
                                        if ($description) {
                                            $description = html_entity_decode(trim(strip_tags($description->content)), null, "UTF-8");
                                        }

                                        $nodeConfig["hx"] = count($html->find("h2,h2,h4,h5"));

                                        $images = $html->find("img");
                                        if ($images) {
                                            foreach ($images as $image) {
                                                $alt = $image->alt;
                                                if (empty($alt)) {
                                                    $nodeConfig["imgwithoutalt"]++;
                                                } else {
                                                    $nodeConfig["imgwithalt"]++;
                                                }
                                            }
                                        }

                                        $html->clear();
                                        unset($html);
                                    }
                                }
                            } catch (\Exception $e) {
                                \Logger::debug($e);
                            }

                            if (!$title) {
                                $title = $childDocument->getTitle();
                            }
                            if (!$description) {
                                $description = $childDocument->getDescription();
                            }

                            $nodeConfig["title"] = $title;
                            $nodeConfig["description"] = $description;

                            $nodeConfig["title_length"] = mb_strlen($title);
                            $nodeConfig["description_length"] = mb_strlen($description);

                            if (mb_strlen($title) > 80
                                || mb_strlen($title) < 5
                                || mb_strlen($description) > 180
                                || mb_strlen($description) < 20
                                || $nodeConfig["h1"] != 1
                                || $nodeConfig["hx"] < 1
                            ) {
                                $nodeConfig["cls"] = "pimcore_document_seo_warning";
                            }
                        }

                        $documents[] = $nodeConfig;
                    }
                }
            }
        }

        $this->_helper->json($documents);
    }


    public function convertAction()
    {

        $document = Document::getById($this->getParam("id"));

        $type = $this->getParam("type");
        $class = "\\Pimcore\\Model\\Document\\" . ucfirst($type);
        if (Tool::classExists($class)) {
            $new = new $class;

            // overwrite internal store to avoid "duplicate full path" error
            \Zend_Registry::set("document_" . $document->getId(), $new);

            $props = get_object_vars($document);
            foreach ($props as $name => $value) {
                if (property_exists($new, $name)) {
                    $new->$name = $value;
                }
            }

            if($type == "hardlink" || $type == "folder") {
                // remove navigation settings
                foreach (["name", "title", "target", "exclude", "class", "anchor", "parameters", "relation", "accesskey", "tabindex"] as $propertyName) {
                    $new->removeProperty("navigation_" . $propertyName);
                }
            }

            $new->setType($type);
            $new->save();
        }

        $this->_helper->json(array("success" => true));
    }
}
