protected function buildPageTree()
    {
        $this->pageTree = array();
        foreach ($this->pages as $id => &$pageData) {
            // main index page
            if ($id === 'index') {
                $this->pageTree['']['/']['id'] = '/';
                $this->pageTree['']['/']['page'] = &$pageData;
                $pageData['tree_node'] = &$this->pageTree['']['/'];
                continue;
            }

            // get a page's node and branch
            $basename = basename($id);
            $branch = dirname($id);

            $isIndexPage = ($basename === 'index');
            if ($isIndexPage) {
                $basename = basename($branch);
                $branch = dirname($branch);
            }

            $branch = ($branch !== '.') ? $branch : '/';
            $node = ($branch !== '/') ? $branch . '/' . $basename : $basename;

            // skip inaccessible pages (e.g. drop "sub.md" if "sub/index.md" exists)
            if (isset($this->pageTree[$branch][$node]['page']) && !$isIndexPage) {
                continue;
            }

            // add node to page tree
            $isNewBranch = !isset($this->pageTree[$branch]);
            $this->pageTree[$branch][$node]['id'] = $node;
            $this->pageTree[$branch][$node]['page'] = &$pageData;

            $pageData['tree_node'] = &$this->pageTree[$branch][$node];

            // add parent nodes to page tree, if necessary
            while ($isNewBranch && $branch) {
                $parentNode = $branch;
                $parentBranch = ($branch !== '/') ? dirname($parentNode) : '';
                $parentBranch = ($parentBranch !== '.') ? $parentBranch : '/';

                $isNewBranch = !isset($this->pageTree[$parentBranch]);
                $this->pageTree[$parentBranch][$parentNode]['id'] = $parentNode;
                $this->pageTree[$parentBranch][$parentNode]['children'] = &$this->pageTree[$branch];

                $branch = $parentBranch;
            }
        }
    }