<?php

namespace Concrete\Core\Backup;

use Concrete\Core\File\Importer;
use Concrete\Core\Page\Feed;
use Concrete\Core\Sharing\SocialNetwork\Link;
use Concrete\Core\Tree\Tree;
use Page;
use Package;
use Stack;
use SinglePage;
use UserInfo;
use PageType;
use BlockType;
use Block;
use Group;
use PageTheme;
use Core;
use Database;
use Job;
use JobSet;
use PageTemplate;
use CollectionAttributeKey;
use Concrete\Core\StyleCustomizer\Inline\StyleSet;
use Concrete\Core\Block\BlockType\Set as BlockTypeSet;
use Concrete\Core\Attribute\Type as AttributeType;
use Concrete\Core\Attribute\Key\Category as AttributeKeyCategory;
use PermissionKeyCategory;
use PermissionKey;
use Concrete\Core\Permission\Access\Entity\Type as PermissionAccessEntityType;
use Concrete\Core\Workflow\Progress\Category as WorkflowProgressCategory;
use Concrete\Core\Permission\Access\Entity\GroupEntity as GroupPermissionAccessEntity;
use PermissionAccess;
use Concrete\Core\Captcha\Library as SystemCaptchaLibrary;
use Concrete\Core\Editor\Snippet as SystemContentEditorSnippet;
use Concrete\Core\Feature\Feature;
use Concrete\Core\Feature\Category\Category as FeatureCategory;
use Concrete\Core\Gathering\DataSource\DataSource as GatheringDataSource;
use Concrete\Core\Gathering\Item\Template\Template as GatheringItemTemplate;
use Concrete\Core\Gathering\Item\Template\Type as GatheringItemTemplateType;
use Concrete\Core\Page\Type\Composer\Control\Type\Type as PageTypeComposerControlType;
use Concrete\Core\Page\Type\PublishTarget\Type\Type as PageTypePublishTargetType;
use Concrete\Core\Conversation\Editor\Editor as ConversationEditor;
use Concrete\Core\Conversation\Rating\Type as ConversationRatingType;
use Concrete\Core\Conversation\FlagType\FlagType as ConversationFlagType;
use Concrete\Core\Validation\BannedWord\BannedWord as BannedWord;
use Concrete\Core\Page\Type\Composer\FormLayoutSetControl as PageTypeComposerFormLayoutSetControl;

class ContentImporter
{
    protected static $mcBlockIDs = array();
    protected static $ptComposerOutputControlIDs = array();

    public function importContentFile($file)
    {
        $sx = simplexml_load_file($file);
        $this->doImport($sx);
    }

    public function importContentString($string)
    {
        $sx = simplexml_load_string($string);
        $this->doImport($sx);
    }

    protected function doImport($sx)
    {
        $this->importSinglePageStructure($sx);
        $this->importStacksStructure($sx);
        $this->importBlockTypes($sx);
        $this->importBlockTypeSets($sx);
        $this->importConversationEditors($sx);
        $this->importConversationRatingTypes($sx);
        $this->importConversationFlagTypes($sx);
        $this->importPageTypePublishTargetTypes($sx);
        $this->importPageTypeComposerControlTypes($sx);
        $this->importBannedWords($sx);
        $this->importSocialLinks($sx);
        $this->importTrees($sx);
        $this->importFileImportantThumbnailTypes($sx);
        $this->importFeatures($sx);
        $this->importFeatureCategories($sx);
        $this->importGatheringDataSources($sx);
        $this->importGatheringItemTemplateTypes($sx);
        $this->importGatheringItemTemplates($sx);
        $this->importAttributeCategories($sx);
        $this->importAttributeTypes($sx);
        $this->importWorkflowTypes($sx);
        $this->importWorkflowProgressCategories($sx);
        $this->importAttributes($sx);
        $this->importAttributeSets($sx);
        $this->importThemes($sx);
        $this->importPermissionCategories($sx);
        $this->importPermissionAccessEntityTypes($sx);
        $this->importTaskPermissions($sx);
        $this->importPermissions($sx);
        $this->importJobs($sx);
        $this->importJobSets($sx);
        // import bare page types first, then import structure, then page types blocks, attributes and composer settings, then page content, because we need the structure for certain attributes and stuff set in master collections (like composer)
        $this->importPageTemplates($sx);
        $this->importPageTypesBase($sx);
        $this->importPageStructure($sx);
        $this->importPageFeeds($sx);
        $this->importPageTypeTargets($sx);
        $this->importPageTypeDefaults($sx);
        $this->importSinglePageContent($sx);
        $this->importStacksContent($sx);
        $this->importPageContent($sx);
        $this->importPackages($sx);
        $this->importConfigValues($sx);
        $this->importSystemCaptchaLibraries($sx);
        $this->importSystemContentEditorSnippets($sx);
    }

    protected static function getPackageObject($pkgHandle)
    {
        $pkg = false;
        if ($pkgHandle) {
            $pkg = Package::getByHandle($pkgHandle);
        }

        return $pkg;
    }

    protected function importStacksStructure(\SimpleXMLElement $sx)
    {
        if (isset($sx->stacks)) {
            foreach ($sx->stacks->stack as $p) {
                if (isset($p['type'])) {
                    $type = Stack::mapImportTextToType($p['type']);
                    Stack::addStack($p['name'], $type);
                } else {
                    Stack::addStack($p['name']);
                }
            }
        }
    }

    protected function importStacksContent(\SimpleXMLElement $sx)
    {
        if (isset($sx->stacks)) {
            foreach ($sx->stacks->stack as $p) {
                $stack = Stack::getByName($p['name']);
                if (isset($p->area)) {
                    $this->importPageAreas($stack, $p);
                }
            }
        }
    }

    protected function importSinglePageStructure(\SimpleXMLElement $sx)
    {
        if (isset($sx->singlepages)) {
            foreach ($sx->singlepages->page as $p) {
                $pkg = static::getPackageObject($p['package']);
                $spl = SinglePage::add($p['path'], $pkg);
                if (is_object($spl)) {
                    if (isset($p['root']) && $p['root'] == true) {
                        $spl->moveToRoot();
                    }
                    if ($p['name']) {
                        $spl->update(array('cName' => $p['name'], 'cDescription' => $p['description']));
                    }
                }
            }
        }
    }

    protected function importSinglePageContent(\SimpleXMLElement $sx)
    {
        if (isset($sx->singlepages)) {
            foreach ($sx->singlepages->page as $px) {
                $page = Page::getByPath($px['path'], 'RECENT');
                if (isset($px->area)) {
                    $this->importPageAreas($page, $px);
                }
                if (isset($px->attributes)) {
                    foreach ($px->attributes->children() as $attr) {
                        $ak = CollectionAttributeKey::getByHandle($attr['handle']);
                        if (is_object($ak)) {
                            $page->setAttribute((string) $attr['handle'], $ak->getController()->importValue($attr));
                        }
                    }
                }
            }
        }
    }

    public function setupPageNodeOrder($pageNodeA, $pageNodeB)
    {
        $pathA = (string) $pageNodeA['path'];
        $pathB = (string) $pageNodeB['path'];
        $numA = count(explode('/', $pathA));
        $numB = count(explode('/', $pathB));
        if ($numA == $numB) {
            if (intval($pageNodeA->originalPos) < intval($pageNodeB->originalPos)) {
                return -1;
            } else {
                if (intval($pageNodeA->originalPos) > intval($pageNodeB->originalPos)) {
                    return 1;
                } else {
                    return 0;
                }
            }
        } else {
            return ($numA < $numB) ? -1 : 1;
        }
    }

    protected function importPageContent(\SimpleXMLElement $sx)
    {
        if (isset($sx->pages)) {
            foreach ($sx->pages->page as $px) {
                if ($px['path'] != '') {
                    $page = Page::getByPath($px['path'], 'RECENT');
                } else {
                    $page = Page::getByID(HOME_CID, 'RECENT');
                }
                if (isset($px->area)) {
                    $this->importPageAreas($page, $px);
                }
                if (isset($px->attributes)) {
                    foreach ($px->attributes->children() as $attr) {
                        $ak = CollectionAttributeKey::getByHandle($attr['handle']);
                        if (is_object($ak)) {
                            $page->setAttribute((string) $attr['handle'], $ak->getController()->importValue($attr));
                        }
                    }
                }
                $page->reindex();
            }
        }
    }

    protected function importPageStructure(\SimpleXMLElement $sx)
    {
        if (isset($sx->pages)) {
            $nodes = array();
            $i = 0;
            foreach ($sx->pages->page as $p) {
                $p->originalPos = $i;
                $nodes[] = $p;
                $i++;
            }
            usort($nodes, array('static', 'setupPageNodeOrder'));
            $home = Page::getByID(HOME_CID, 'RECENT');

            foreach ($nodes as $px) {
                $pkg = static::getPackageObject($px['package']);
                $data = array();
                $user = (string) $px['user'];
                if ($user != '') {
                    $ui = UserInfo::getByUserName($user);
                    if (is_object($ui)) {
                        $data['uID'] = $ui->getUserID();
                    } else {
                        $data['uID'] = USER_SUPER_ID;
                    }
                }
                $cDatePublic = (string) $px['public-date'];
                if ($cDatePublic) {
                    $data['cDatePublic'] = $cDatePublic;
                }

                $data['pkgID'] = 0;
                if (is_object($pkg)) {
                    $data['pkgID'] = $pkg->getPackageID();
                }
                $args = array();
                $ct = PageType::getByHandle($px['pagetype']);
                $template = PageTemplate::getByHandle($px['template']);
                if ($px['path'] != '') {
                    // not home page
                    $page = Page::getByPath($px['path']);
                    if (!is_object($page) || ($page->isError())) {
                        $lastSlash = strrpos((string) $px['path'], '/');
                        $parentPath = substr((string) $px['path'], 0, $lastSlash);
                        $data['cHandle'] = substr((string) $px['path'], $lastSlash + 1);
                        if (!$parentPath) {
                            $parent = $home;
                        } else {
                            $parent = Page::getByPath($parentPath);
                        }
                        $page = $parent->add($ct, $data);
                    }
                } else {
                    $page = $home;
                }

                $args['cName'] = $px['name'];
                $args['cDescription'] = $px['description'];
                if (is_object($ct)) {
                    $args['ptID'] = $ct->getPageTypeID();
                }
                $args['pTemplateID'] = $template->getPageTemplateID();
                $page->update($args);
            }
        }
    }

    public function importPageAreas(Page $page, \SimpleXMLElement $px)
    {
        foreach ($px->area as $ax) {
            if (isset($ax->blocks)) {
                foreach ($ax->blocks->block as $bx) {
                    if ($bx['type'] != '') {
                        // we check this because you might just get a block node with only an mc-block-id, if it's an alias
                        $bt = BlockType::getByHandle((string) $bx['type']);
                        if (!is_object($bt)) {
                            throw new \Exception(t('Invalid block type handle: %s', strval($bx['type'])));
                        }
                        $btc = $bt->getController();
                        $btc->import($page, (string) $ax['name'], $bx);
                    } else {
                        if ($bx['mc-block-id'] != '') {
                            // we find that block in the master collection block pool and alias it out
                            $bID = array_search((string) $bx['mc-block-id'], self::$mcBlockIDs);
                            if ($bID) {
                                $mc = Page::getByID($page->getMasterCollectionID(), 'RECENT');
                                $block = Block::getByID($bID, $mc, (string) $ax['name']);
                                $block->alias($page);

                                if ($block->getBlockTypeHandle() == BLOCK_HANDLE_LAYOUT_PROXY) {
                                    // we have to go get the blocks on that page in this layout.
                                    $btc = $block->getController();
                                    $arLayout = $btc->getAreaLayoutObject();
                                    $columns = $arLayout->getAreaLayoutColumns();
                                    foreach ($columns as $column) {
                                        $area = $column->getAreaObject();
                                        $blocks = $area->getAreaBlocksArray($mc);
                                        foreach ($blocks as $_b) {
                                            $_b->alias($page);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (isset($ax->style)) {
                $area = \Area::get($page, (string) $ax['name']);
                $set = StyleSet::import($ax->style);
                $page->setCustomStyleSet($area, $set);
            }
        }
    }

    public static function addMasterCollectionBlockID($b, $id)
    {
        self::$mcBlockIDs[$b->getBlockID()] = $id;
    }

    public static function getMasterCollectionTemporaryBlockID($b)
    {
        if (isset(self::$mcBlockIDs[$b->getBlockID()])) {
            return self::$mcBlockIDs[$b->getBlockID()];
        }
    }

    public static function addPageTypeComposerOutputControlID(PageTypeComposerFormLayoutSetControl $control, $id)
    {
        self::$ptComposerOutputControlIDs[$id] = $control->getPageTypeComposerFormLayoutSetControlID();
    }

    public static function getPageTypeComposerFormLayoutSetControlFromTemporaryID($id)
    {
        if (isset(self::$ptComposerOutputControlIDs[$id])) {
            return self::$ptComposerOutputControlIDs[$id];
        }
    }

    protected function importPageTemplates(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetemplates)) {
            foreach ($sx->pagetemplates->pagetemplate as $pt) {
                $pkg = static::getPackageObject($pt['package']);
                $ptt = PageTemplate::getByHandle($pt['handle']);
                if (!is_object($ptt)) {
                    $ptt = PageTemplate::add(
                        (string) $pt['handle'],
                        (string) $pt['name'],
                        (string) $pt['icon'],
                        $pkg,
                        (string) $pt['internal']
                    );
                }
            }
        }
    }

    protected function importBlockTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->blocktypes)) {
            foreach ($sx->blocktypes->blocktype as $bt) {
                if (!is_object(BlockType::getByHandle((string) $bt['handle']))) {
                    $pkg = static::getPackageObject($bt['package']);
                    if (is_object($pkg)) {
                        BlockType::installBlockTypeFromPackage((string) $bt['handle'], $pkg);
                    } else {
                        BlockType::installBlockType((string) $bt['handle']);
                    }
                }
            }
        }
    }

    protected function importWorkflowTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->workflowtypes)) {
            foreach ($sx->workflowtypes->workflowtype as $wt) {
                $pkg = static::getPackageObject($wt['package']);
                $name = $wt['name'];
                if (!$name) {
                    $name = Core::make('helper/text')->unhandle($wt['handle']);
                }
                $type = \Concrete\Core\Workflow\Type::add($wt['handle'], $name, $pkg);
            }
        }
    }

    protected function importAttributeTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->attributetypes)) {
            foreach ($sx->attributetypes->attributetype as $at) {
                $pkg = static::getPackageObject($at['package']);
                $name = $at['name'];
                if (!$name) {
                    $name = Core::make('helper/text')->unhandle($at['handle']);
                }
                $type = AttributeType::getByHandle($at['handle']);
                if (!is_object($type)) {
                    $type = AttributeType::add($at['handle'], $name, $pkg);
                }
                if (isset($at->categories)) {
                    foreach ($at->categories->children() as $cat) {
                        $catobj = AttributeKeyCategory::getByHandle((string) $cat['handle']);
                        $catobj->associateAttributeKeyType($type);
                    }
                }
            }
        }
    }

    protected function importPermissionAccessEntityTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->permissionaccessentitytypes)) {
            foreach ($sx->permissionaccessentitytypes->permissionaccessentitytype as $pt) {
                $type = PermissionAccessEntityType::getByHandle((string) $pt['handle']);
                if (!is_object($type)) {
                    $pkg = static::getPackageObject($pt['package']);
                    $name = $pt['name'];
                    if (!$name) {
                        $name = Core::make('helper/text')->unhandle($pt['handle']);
                    }
                    $type = PermissionAccessEntityType::add($pt['handle'], $name, $pkg);
                }

                if (isset($pt->categories)) {
                    foreach ($pt->categories->children() as $cat) {
                        $catobj = PermissionKeyCategory::getByHandle((string) $cat['handle']);
                        $catobj->associateAccessEntityType($type);
                    }
                }
            }
        }
    }

    protected function importPackages(\SimpleXMLElement $sx)
    {
        if (isset($sx->packages)) {
            foreach ($sx->packages->package as $p) {
                $pkg = Package::getClass((string) $p['handle']);
                if (!$pkg->isPackageInstalled()) {
                    $pkg->install();
                }
            }
        }
    }

    protected function importThemes(\SimpleXMLElement $sx)
    {
        if (isset($sx->themes)) {
            foreach ($sx->themes->theme as $th) {
                $pkg = static::getPackageObject($th['package']);
                $pThemeHandle = (string) $th['handle'];
                $pt = PageTheme::getByHandle($pThemeHandle);
                if (!is_object($pt)) {
                    $pt = PageTheme::add($pThemeHandle, $pkg);
                }
                if ($th['activated'] == '1') {
                    $pt->applyToSite();
                }
            }
        }
    }

    protected function importPageTypePublishTargetTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetypepublishtargettypes)) {
            foreach ($sx->pagetypepublishtargettypes->type as $th) {
                $pkg = static::getPackageObject($th['package']);
                $ce = PageTypePublishTargetType::add((string) $th['handle'], (string) $th['name'], $pkg);
            }
        }
    }

    protected function importPageTypeComposerControlTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetypecomposercontroltypes)) {
            foreach ($sx->pagetypecomposercontroltypes->type as $th) {
                $pkg = static::getPackageObject($th['package']);
                $ce = PageTypeComposerControlType::add((string) $th['handle'], (string) $th['name'], $pkg);
            }
        }
    }

    protected function importPageTypesBase(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetypes)) {
            foreach ($sx->pagetypes->pagetype as $p) {
                PageType::import($p);
            }
        }
    }

    protected function importPageTypeTargets(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetypes)) {
            foreach ($sx->pagetypes->pagetype as $p) {
                PageType::importTargets($p);
            }
        }
    }

    protected function importPageTypeDefaults(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagetypes)) {
            foreach ($sx->pagetypes->pagetype as $p) {
                PageType::importContent($p);
            }
        }
    }

    protected function importConversationEditors(\SimpleXMLElement $sx)
    {
        if (isset($sx->conversationeditors)) {
            foreach ($sx->conversationeditors->editor as $th) {
                $pkg = static::getPackageObject($th['package']);
                $ce = ConversationEditor::add((string) $th['handle'], (string) $th['name'], $pkg);
                if ($th['activated'] == '1') {
                    $ce->activate();
                }
            }
        }
    }

    protected function importConversationRatingTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->conversationratingtypes)) {
            foreach ($sx->conversationratingtypes->conversationratingtype as $th) {
                $pkg = static::getPackageObject($th['package']);
                $ce = ConversationRatingType::add((string) $th['handle'], (string) $th['name'], $th['points'], $pkg);
            }
        }
    }

    protected function importBannedWords(\SimpleXMLElement $sx)
    {
        if (isset($sx->banned_words)) {
            foreach ($sx->banned_words->banned_word as $p) {
                $bw = BannedWord::add(str_rot13($p));
            }
        }
    }

    protected function importSocialLinks(\SimpleXMLElement $sx)
    {
        if (isset($sx->sociallinks)) {
            foreach ($sx->sociallinks->link as $l) {
                $sociallink = Link::getByServiceHandle((string) $l['service']);
                if (!is_object($sociallink)) {
                    $sociallink = new Link();
                    $sociallink->setURL((string) $l['url']);
                    $sociallink->setServiceHandle((string) $l['service']);
                    $sociallink->save();
                }
            }
        }
    }

    protected function importPageFeeds(\SimpleXMLElement $sx)
    {
        if (isset($sx->pagefeeds)) {
            foreach ($sx->pagefeeds->feed as $f) {
                $feed = Feed::getByHandle((string) $f->handle);
                if (!is_object($feed)) {
                    $feed = new Feed();
                }
                if ($f->parent) {
                    $feed->setParentID(self::getValue((string) $f->parent));
                }
                $feed->setTitle((string) $f->title);
                $feed->setDescription((string) $f->description);
                $feed->setHandle((string) $f->handle);
                if ($f->descendents) {
                    $feed->setIncludeAllDescendents(true);
                }
                if ($f->aliases) {
                    $feed->setDisplayAliases(true);
                }
                if ($f->featured) {
                    $feed->setDisplayFeaturedOnly(true);
                }
                if ($f->pagetype) {
                    $feed->setPageTypeID(self::getValue((string) $f->pagetype));
                }
                $contentType = $f->contenttype;
                $type = (string) $contentType['type'];
                if ($type == 'description') {
                    $feed->displayShortDescriptionContent();
                } elseif ($type == 'area') {
                    $feed->displayAreaContent((string) $contentType['handle']);
                }
                $feed->save();
            }
        }
    }
    protected function importTrees(\SimpleXMLElement $sx)
    {
        if (isset($sx->trees)) {
            foreach ($sx->trees->tree as $t) {
                Tree::import($t);
            }
        }
    }

    protected function importFileImportantThumbnailTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->thumbnailtypes)) {
            foreach ($sx->thumbnailtypes->thumbnailtype as $l) {
                $type = new \Concrete\Core\File\Image\Thumbnail\Type\Type();
                $type->setName((string) $l['name']);
                $type->setHandle((string) $l['handle']);
                $type->setWidth((string) $l['width']);
                $type->setHeight((string) $l['height']);
                $required = (string) $l['required'];
                if ($required) {
                    $type->requireType();
                }
                $type->save();
            }
        }
    }

    protected function importConversationFlagTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->flag_types)) {
            foreach ($sx->flag_types->flag_type as $p) {
                $bw = ConversationFlagType::add((string) $p);
            }
        }
    }

    protected function importSystemCaptchaLibraries(\SimpleXMLElement $sx)
    {
        if (isset($sx->systemcaptcha)) {
            foreach ($sx->systemcaptcha->library as $th) {
                $pkg = static::getPackageObject($th['package']);
                $scl = SystemCaptchaLibrary::add($th['handle'], $th['name'], $pkg);
                if ($th['activated'] == '1') {
                    $scl->activate();
                }
            }
        }
    }

    protected function importSystemContentEditorSnippets(\SimpleXMLElement $sx)
    {
        if (isset($sx->systemcontenteditorsnippets)) {
            foreach ($sx->systemcontenteditorsnippets->snippet as $th) {
                $pkg = static::getPackageObject($th['package']);
                $scs = SystemContentEditorSnippet::add($th['handle'], $th['name'], $pkg);
                if ($th['activated'] == '1') {
                    $scs->activate();
                }
            }
        }
    }

    protected function importJobs(\SimpleXMLElement $sx)
    {
        if (isset($sx->jobs)) {
            foreach ($sx->jobs->job as $jx) {
                $pkg = static::getPackageObject($jx['package']);
                $job = Job::getByHandle($jx['handle']);
                if (!is_object($job)) {
                    if (is_object($pkg)) {
                        Job::installByPackage($jx['handle'], $pkg);
                    } else {
                        Job::installByHandle($jx['handle']);
                    }
                }
            }
        }
    }

    protected function importJobSets(\SimpleXMLElement $sx)
    {
        if (isset($sx->jobsets)) {
            foreach ($sx->jobsets->jobset as $js) {
                $jso = JobSet::getByName((string) $js['name']);
                if (!is_object($jso)) {
                    $pkg = static::getPackageObject($js['package']);
                    if (is_object($pkg)) {
                        $jso = JobSet::add((string) $js['name'], $pkg);
                    } else {
                        $jso = JobSet::add((string) $js['name']);
                    }
                }
                foreach ($js->children() as $jsk) {
                    $j = Job::getByHandle((string) $jsk['handle']);
                    if (is_object($j)) {
                        $jso->addJob($j);
                    }
                }
            }
        }
    }

    protected function importConfigValues(\SimpleXMLElement $sx)
    {
        if (isset($sx->config)) {
            foreach ($sx->config->children() as $key) {
                $pkg = static::getPackageObject($key['package']);
                if (is_object($pkg)) {
                    \Config::save($pkg->getPackageHandle() . '::' . $key->getName(), (string) $key);
                } else {
                    \Config::save($key->getName(), (string) $key);
                }
            }
        }
    }

    protected function importDatabaseConfigValues(\SimpleXMLElement $sx)
    {
        if (isset($sx->databaseconfig)) {
            $config = Core::make('config/database');
            foreach ($sx->databaseconfig->children() as $key) {
                $pkg = static::getPackageObject($key['package']);
                if (is_object($pkg)) {
                    $config->save($pkg->getPackageHandle() . '::' . $key->getName(), (string) $key);
                } else {
                    $config->save($key->getName(), (string) $key);
                }
            }
        }
    }

    protected function importTaskPermissions(\SimpleXMLElement $sx)
    {
        if (isset($sx->taskpermissions)) {
            foreach ($sx->taskpermissions->taskpermission as $tp) {
                $pkg = static::getPackageObject($tp['package']);
                $tpa = TaskPermission::addTask($tp['handle'], $tp['name'], $tp['description'], $pkg);
                if (isset($tp->access)) {
                    foreach ($tp->access->children() as $ch) {
                        if ($ch->getName() == 'group') {
                            $g = Group::getByName($ch['name']);
                            if (!is_object($g)) {
                                $g = Group::add($ch['name'], $ch['description']);
                            }
                            $tpa->addAccess($g);
                        }
                    }
                }
            }
        }
    }

    protected function importPermissionCategories(\SimpleXMLElement $sx)
    {
        if (isset($sx->permissioncategories)) {
            foreach ($sx->permissioncategories->category as $pkc) {
                $pkg = static::getPackageObject($pkc['package']);
                $category = PermissionKeyCategory::getByHandle((string) $pkc['handle']);
                if (!is_object($category)) {
                    PermissionKeyCategory::add((string) $pkc['handle'], $pkg);
                }
            }
        }
    }

    protected function importWorkflowProgressCategories(\SimpleXMLElement $sx)
    {
        if (isset($sx->workflowprogresscategories)) {
            foreach ($sx->workflowprogresscategories->category as $wpc) {
                $pkg = static::getPackageObject($wpc['package']);
                WorkflowProgressCategory::add((string) $wpc['handle'], $pkg);
            }
        }
    }

    protected function importPermissions(\SimpleXMLElement $sx)
    {
        if (isset($sx->permissionkeys)) {
            foreach ($sx->permissionkeys->permissionkey as $pk) {
                if (is_object(PermissionKey::getByHandle((string) $pk['handle']))) {
                    continue;
                }
                $pkc = PermissionKeyCategory::getByHandle((string) $pk['category']);
                $c1 = $pkc->getPermissionKeyClass();
                $pkx = call_user_func(array($c1, 'import'), $pk);
                $assignments = array();

                if (isset($pk->access)) {
                    foreach ($pk->access->children() as $ch) {
                        if ($ch->getName() == 'group') {
                            /*
                             * Legacy
                             */
                            $g = Group::getByName($ch['name']);
                            if (!is_object($g)) {
                                $g = Group::add($g['name'], $g['description']);
                            }
                            $pae = GroupPermissionAccessEntity::getOrCreate($g);
                            $assignments[] = $pae;
                        }

                        if ($ch->getName() == 'entity') {
                            $type = PermissionAccessEntityType::getByHandle((string) $ch['type']);
                            $class = $type->getAccessEntityTypeClass();
                            if (method_exists($class, 'configureFromImport')) {
                                $pae = $class::configureFromImport($ch);
                                $assignments[] = $pae;
                            }
                        }
                    }
                }

                if (count($assignments)) {
                    $pa = PermissionAccess::create($pkx);
                    foreach($assignments as $pae) {
                        $pa->addListItem($pae);
                    }
                    $pt = $pkx->getPermissionAssignmentObject();
                    $pt->assignPermissionAccess($pa);
                }
            }
        }
    }

    protected function importFeatures(\SimpleXMLElement $sx)
    {
        if (isset($sx->features)) {
            foreach ($sx->features->feature as $fea) {
                $feHasCustomClass = false;
                if ($fea['has-custom-class']) {
                    $feHasCustomClass = true;
                }
                $pkg = static::getPackageObject($fea['package']);
                $fx = Feature::add((string) $fea['handle'], (string) $fea['score'], $feHasCustomClass, $pkg);
            }
        }
    }

    protected function importFeatureCategories(\SimpleXMLElement $sx)
    {
        if (isset($sx->featurecategories)) {
            foreach ($sx->featurecategories->featurecategory as $fea) {
                $pkg = static::getPackageObject($fea['package']);
                $fx = FeatureCategory::add($fea['handle'], $pkg);
            }
        }
    }

    protected function importAttributeCategories(\SimpleXMLElement $sx)
    {
        if (isset($sx->attributecategories)) {
            foreach ($sx->attributecategories->category as $akc) {
                $pkg = static::getPackageObject($akc['package']);
                $akx = AttributeKeyCategory::getByHandle($akc['handle']);
                if (!is_object($akx)) {
                    $akx = AttributeKeyCategory::add($akc['handle'], $akc['allow-sets'], $pkg);
                }
            }
        }
    }

    protected function importAttributes(\SimpleXMLElement $sx)
    {
        $db = Database::connection();
        if (isset($sx->attributekeys)) {
            foreach ($sx->attributekeys->attributekey as $ak) {
                $akc = AttributeKeyCategory::getByHandle($ak['category']);
                $akID = $db->GetOne('select akID from AttributeKeys where akHandle = ? and akCategoryID = ?', array($ak['handle'], $akc->getAttributeKeyCategoryID()));
                if (!$akID) {
                    $txt = Core::make('helper/text');
                    $c1 = overrideable_core_class('\\Core\\Attribute\\Key\\' . $txt->camelcase(
                            $akc->getAttributeKeyCategoryHandle()
                        ) . 'Key', DIRNAME_CLASSES . '/Attribute/Key/' . $txt->camelcase(
                            $akc->getAttributeKeyCategoryHandle()
                        ) . 'Key.php', (string) $akc->getPackageHandle()
                    );
                    call_user_func(array($c1, 'import'), $ak);
                }
            }
        }
    }

    protected function importAttributeSets(\SimpleXMLElement $sx)
    {
        if (isset($sx->attributesets)) {
            foreach ($sx->attributesets->attributeset as $as) {
                $set = \Concrete\Core\Attribute\Set::getByHandle((string) $as['handle']);
                $akc = AttributeKeyCategory::getByHandle($as['category']);
                if (!is_object($set)) {
                    $pkg = static::getPackageObject($as['package']);
                    $set = $akc->addSet((string) $as['handle'], (string) $as['name'], $pkg, $as['locked']);
                }
                foreach ($as->children() as $ask) {
                    $ak = $akc->getAttributeKeyByHandle((string) $ask['handle']);
                    if (is_object($ak)) {
                        $set->addKey($ak);
                    }
                }
            }
        }
    }

    protected function importGatheringDataSources(\SimpleXMLElement $sx)
    {
        if (isset($sx->gatheringsources)) {
            foreach ($sx->gatheringsources->gatheringsource as $ags) {
                $pkg = static::getPackageObject($ags['package']);
                $source = GatheringDataSource::add((string) $ags['handle'], (string) $ags['name'], $pkg);
            }
        }
    }

    protected function importGatheringItemTemplateTypes(\SimpleXMLElement $sx)
    {
        if (isset($sx->gatheringitemtemplatetypes)) {
            foreach ($sx->gatheringitemtemplatetypes->gatheringitemtemplatetype as $at) {
                $pkg = static::getPackageObject($at['package']);
                GatheringItemTemplateType::add((string) $at['handle'], $pkg);
            }
        }
    }

    protected function importGatheringItemTemplates(\SimpleXMLElement $sx)
    {
        if (isset($sx->gatheringitemtemplates)) {
            foreach ($sx->gatheringitemtemplates->gatheringitemtemplate as $at) {
                $pkg = static::getPackageObject($at['package']);
                $type = GatheringItemTemplateType::getByHandle((string) $at['type']);
                $gatHasCustomClass = false;
                $gatForceDefault = false;
                $gatFixedSlotWidth = 0;
                $gatFixedSlotHeight = 0;
                if ($at['has-custom-class']) {
                    $gatHasCustomClass = true;
                }
                if ($at['force-default']) {
                    $gatForceDefault = true;
                }
                if ($at['fixed-slot-width']) {
                    $gatFixedSlotWidth = (string) $at['fixed-slot-width'];
                }
                if ($at['fixed-slot-height']) {
                    $gatFixedSlotHeight = (string) $at['fixed-slot-height'];
                }
                $template = GatheringItemTemplate::add(
                    $type,
                    (string) $at['handle'],
                    (string) $at['name'],
                    $gatFixedSlotWidth,
                    $gatFixedSlotHeight,
                    $gatHasCustomClass,
                    $gatForceDefault,
                    $pkg
                );
                foreach ($at->children() as $fe) {
                    $feo = Feature::getByHandle((string) $fe['handle']);
                    if (is_object($feo)) {
                        $template->addGatheringItemTemplateFeature($feo);
                    }
                }
            }
        }
    }

    protected function importBlockTypeSets(\SimpleXMLElement $sx)
    {
        if (isset($sx->blocktypesets)) {
            foreach ($sx->blocktypesets->blocktypeset as $bts) {
                $pkg = static::getPackageObject($bts['package']);
                $set = BlockTypeSet::getByHandle((string) $bts['handle']);
                if (!is_object($set)) {
                    $set = BlockTypeSet::add((string) $bts['handle'], (string) $bts['name'], $pkg);
                }
                foreach ($bts->children() as $btk) {
                    $bt = BlockType::getByHandle((string) $btk['handle']);
                    if (is_object($bt)) {
                        $set->addBlockType($bt);
                    }
                }
            }
        }
    }

    public static function getValue($value)
    {
        if (preg_match(
            '/\{ccm:export:page:(.*?)\}|' .
            '\{ccm:export:file:(.*?)\}|' .
            '\{ccm:export:image:(.*?)\}|' .
            '\{ccm:export:pagetype:(.*?)\}|' .
            '\{ccm:export:pagefeed:(.*?)\}/i',
            $value,
            $matches
        )
        ) {
            if (isset($matches[1]) && $matches[1]) {
                $c = Page::getByPath($matches[1]);

                return $c->getCollectionID();
            }
            if (isset($matches[2]) && $matches[2]) {
                $db = Database::connection();
                $fID = $db->GetOne('select fID from FileVersions where fvFilename = ?', array($matches[2]));

                return $fID;
            }
            if (isset($matches[3]) && $matches[3]) {
                $db = Database::connection();
                $fID = $db->GetOne('select fID from FileVersions where fvFilename = ?', array($matches[3]));

                return $fID;
            }
            if (isset($matches[4]) && $matches[4]) {
                $ct = PageType::getByHandle($matches[4]);

                return $ct->getPageTypeID();
            }
            if (isset($matches[5]) && $matches[5]) {
                $pf = Feed::getByHandle($matches[5]);

                return $pf->getID();
            }
        } else {
            return $value;
        }
    }

    public function importFiles($fromPath, $computeThumbnails = true)
    {
        $fh = new Importer();

        if (!$computeThumbnails) {
            $fh->setRescanThumbnailsOnImport(false);
            $helper = Core::make('helper/file');
        }
        $contents = Core::make('helper/file')->getDirectoryContents($fromPath);
        foreach ($contents as $filename) {
            if (!is_dir($filename)) {
                $fv = $fh->import($fromPath . '/' . $filename, $filename);
                if (!$computeThumbnails) {
                    $types = \Concrete\Core\File\Image\Thumbnail\Type\Type::getVersionList();
                    foreach ($types as $type) {
                        // since we provide the thumbnails, we're going to get a list of thumbnail types
                        // and loop through them, assigning them to all the files.
                        $thumbnailPath = $fromPath . '/' . $type->getHandle() . '/' . $filename;
                        if (file_exists($thumbnailPath)) {
                            $fv->importThumbnail($type, $thumbnailPath);
                        }
                    }
                }
            }
        }
    }
}
