$mform->set_data($link);
    // Print the header
    if ($blogtype == 'personal') {
        $PAGE->navbar->add(fullname($oubloguser), new moodle_url('/user/view.php', array('id' => $oubloguser->id)));
        $PAGE->navbar->add(format_string($oublog->name), new moodle_url('/mod/oublog/view.php', array('blog' => $blog)));
    } else {
        $PAGE->navbar->add($linkid ? $streditlink : $straddlink);
    }
    $PAGE->set_title(format_string($oublog->name));
    $PAGE->set_heading(format_string($course->fullname));
    echo $OUTPUT->header();
    echo '<br />';
    $mform->display();
    echo $OUTPUT->footer();
} else {
    if ($frmlink->link) {
        $frmlink->id = $frmlink->link;
        $frmlink->oublogid = $oublog->id;
        if (!oublog_edit_link($frmlink)) {
            print_error('couldnotaddlink', 'oublog');
        }
    } else {
        unset($frmlink->id);
        $frmlink->oublogid = $oublog->id;
        $frmlink->oubloginstancesid = $bloginstancesid;
        if (!oublog_add_link($frmlink)) {
            print_error('couldnotaddlink', 'oublog');
        }
    }
    redirect($viewurl);
}
/**
 * Start the import of personal blog data
 * @param string $dir path of directory containing backup data
 */
function migrate_backup($dir)
{
    global $DB, $CFG, $SOURCESERVER;
    $SOURCESERVER = 'http://learn.open.ac.uk';
    if (optional_param('acct', false, PARAM_BOOL)) {
        $SOURCESERVER = 'http://learnacct.open.ac.uk';
    }
    if ($kill = optional_param('kill', false, PARAM_BOOL)) {
        output('<b>Trial run</b>, will perform rollback on each instance.');
    }
    if ($tagsonly = optional_param('tagsonly', false, PARAM_BOOL)) {
        output('<b>Tags only</b>, will only fix tags, not add posts.');
    }
    // Load in XML.
    $doc = new DOMDocument();
    $doc->load($dir . '/oublog.xml');
    $instancetags = $doc->getElementsByTagName('INSTANCE');
    output('Total = ' . $instancetags->length . ' instances ');
    $total = required_param('total', PARAM_INT);
    $max = $total == 0 ? $instancetags->length + 1 : $total;
    output('Max instances to process: ' . $max);
    // Get xml that stores old instance ID's of those instances already processed.
    $donedoc = new DOMDocument();
    $done = array();
    $donetag = null;
    if (!optional_param('ignore', false, PARAM_BOOL) && file_exists($dir . '/imported.xml')) {
        $donedoc->load($dir . '/imported.xml');
        $donestr = $donedoc->saveXML();
        $donetag = $donedoc->getElementsByTagName('imported')->item(0);
        $tags = $donetag->childNodes->item(0);
        while ($tags != null) {
            // Store ids in array using fast looping.
            $done[$tags->nodeValue] = '';
            $tags->parentNode->removeChild($tags);
            $tags = $donetag->childNodes->item(0);
        }
        // Reinstate childnodes.
        $donedoc->loadXML($donestr);
        $donestr = null;
        output('Have already processed ' . count($done) . ' instances');
    } else {
        $donedoc->appendChild($donedoc->createElement('imported'));
    }
    $donetag = $donedoc->getElementsByTagName('imported')->item(0);
    $count = 0;
    $instances = array();
    // Stores data (as object) about each instance in array.
    $tags = $instancetags->item(0);
    // Fast looping of node list by always accessing first tag (faster than foreach).
    while ($tags != null && $count < $max) {
        $info = childnodes_to_object($tags);
        // Remove tag we just processed.
        $tags->parentNode->removeChild($tags);
        // Get the next tag to parse.
        $tags = $instancetags->item(0);
        // Have we processed this instance before? If so, skip.
        if (isset($done[$info->id])) {
            $info = null;
            continue;
        }
        $instances[$info->id] = $info;
        $info = null;
        $count++;
    }
    // Throw away xml as no longer need.
    $doc = null;
    $instancetags = null;
    $tags = null;
    output("Ready to process {$count} instances");
    // Process each blog instance - checking for existing user instance.
    $blog = $DB->get_record('oublog', array('global' => 1), 'id', MUST_EXIST);
    $blog->global = 1;
    output('Got global blog record');
    if (!($cm = get_coursemodule_from_instance('oublog', $blog->id))) {
        print_error('invalidcoursemodule');
    }
    $blogcontext = context_module::instance($cm->id);
    // Vars used to store blog user content xml data.
    $xmlcontent = new DOMDocument();
    $xmlfilenum = -1;
    $xpath = null;
    // Xpath for current content xml file.
    foreach ($instances as &$instance) {
        // Transaction per instance (ensure any existing are cleared up).
        if (isset($trans) && $trans instanceof moodle_transaction) {
            // Commit what has been done (errors will have rolled back already).
            $DB->commit_delegated_transaction($trans);
            $trans = null;
        }
        $trans = $DB->start_delegated_transaction();
        try {
            // Find/create user.
            if (!($instance->newuserid = oublog_search_create_user($instance))) {
                output("<b>Error: Skipping blog for {$instance->username}</b>");
                continue;
            }
            // Work out new instance number (either from new or existing record).
            if ($bloginst = $DB->get_record('oublog_instances', array('oublogid' => $blog->id, 'userid' => $instance->newuserid), 'id')) {
                $instance->newid = $bloginst->id;
                $bloginst = null;
            } else {
                if ($tagsonly) {
                    output("<b>Error: Skipping create instance for {$instance->username} as in tag only mode</b>");
                    continue;
                }
                // Create instance.
                $newbloginst = new stdClass();
                $newbloginst->oublogid = $blog->id;
                $newbloginst->userid = $instance->newuserid;
                $newbloginst->name = $instance->name;
                $newbloginst->summary = blogxml_isempty($instance->summary) ? '' : $instance->summary;
                $newbloginst->summary = oublog_decode_perbloglinks($newbloginst->summary, $xpath);
                $newbloginst->accesstoken = $instance->accesstoken;
                $newbloginst->views = $instance->views;
                if (!($instance->newid = $DB->insert_record('oublog_instances', $newbloginst))) {
                    output("<b>Failed to add blog instance {$instance->name}</b>");
                    continue;
                }
                $newbloginst = null;
                // Migrate any mystuff images in summary.
                if (strpos($instance->summary, '@@PLUGINFILE@@') || stripos($instance->summary, $SOURCESERVER . '/pix/smartpix.php/ou/s/')) {
                    $updaterec = new stdClass();
                    $updaterec->id = $instance->newid;
                    $updaterec->summary = oublog_add_files($instance->summary, $dir, $blogcontext->id, 'summary', $instance->newid);
                    $DB->update_record('oublog_instances', $updaterec);
                    $updaterec = null;
                }
            }
            output('Finished setup blog instance for ' . $instance->username . ' :new id=' . $instance->newid);
            // What is XML file for current instance, load if not current one.
            $instfilenum = get_filenumber($instance->id);
            if ($instfilenum != $xmlfilenum) {
                // Load our XML into current var.
                if (!$xmlcontent->load($dir . '/i' . $instfilenum . '.xml')) {
                    output('<b>Error: Failed to load user data</b> file number ' . $instfilenum);
                    continue;
                }
                $xmlfilenum = $instfilenum;
                $xpath = new DOMXPath($xmlcontent);
                // Get data from XML into vars for quick access.
                $alllinks = array();
                $linktags = $xmlcontent->getElementsByTagName('LINK');
                foreach ($linktags as $l) {
                    $linkob = childnodes_to_object($l);
                    if (!isset($alllinks[$linkob->oubloginstancesid])) {
                        $alllinks[$linkob->oubloginstancesid] = array();
                    }
                    $alllinks[$linkob->oubloginstancesid][] = $linkob;
                    $linkob = null;
                }
                $linktags = null;
                if ($tagsonly) {
                    $alllinks = array();
                    // Ignore any links in tag fix mode;
                }
                $allusers = array();
                $usertags = $xmlcontent->getElementsByTagName('USER');
                foreach ($usertags as $t) {
                    $allusers[$t->getAttribute('id')] = childnodes_to_object($t);
                }
                $usertags = null;
                $allposts = array();
                $posttags = $xmlcontent->getElementsByTagName('POST');
                $tag = $posttags->item(0);
                // Fast looping for posts as probably the most tags.
                while ($tag != null) {
                    $linkob = childnodes_to_object($tag);
                    $tag->parentNode->removeChild($tag);
                    $tag = $posttags->item(0);
                    if (!isset($linkob->oubloginstancesid)) {
                        continue;
                    }
                    if (!isset($allposts[$linkob->oubloginstancesid])) {
                        $allposts[$linkob->oubloginstancesid] = array();
                    }
                    $allposts[$linkob->oubloginstancesid][] = $linkob;
                    $linkob = null;
                }
                $posttags = null;
                $alltags = array();
                $tagtags = $xmlcontent->getElementsByTagName('TAG');
                foreach ($tagtags as $l) {
                    $linkob = childnodes_to_object($l);
                    if (!isset($linkob->postid)) {
                        continue;
                    }
                    if (!isset($alltags[$linkob->postid])) {
                        $alltags[$linkob->postid] = array();
                    }
                    $alltags[$linkob->postid][] = $linkob;
                    $linkob = null;
                }
                $tagtags = null;
                $alledits = array();
                $edittags = $xmlcontent->getElementsByTagName('EDIT');
                foreach ($edittags as $l) {
                    $linkob = childnodes_to_object($l);
                    if (!isset($linkob->postid)) {
                        continue;
                    }
                    if (!isset($alledits[$linkob->postid])) {
                        $alledits[$linkob->postid] = array();
                    }
                    $alledits[$linkob->postid][] = $linkob;
                    $linkob = null;
                }
                $edittags = null;
                if ($tagsonly) {
                    $alledits = array();
                    // Ignore any edits in tag fix mode;
                }
                $allcomments = array();
                $commenttags = $xmlcontent->getElementsByTagName('COMMENT');
                foreach ($commenttags as $l) {
                    $linkob = childnodes_to_object($l);
                    if (!isset($linkob->postid)) {
                        continue;
                    }
                    if (!isset($allcomments[$linkob->postid])) {
                        $allcomments[$linkob->postid] = array();
                    }
                    $allcomments[$linkob->postid][] = $linkob;
                    $linkob = null;
                }
                $commenttags = null;
                if ($tagsonly) {
                    $allcomments = array();
                    // Ignore any comments in tag fix mode;
                }
                output('Loaded user data file ' . $xmlfilenum);
            }
            // Store posts info for this instance (used in link checks).
            $postinfo = array();
            if (isset($allposts[$instance->id])) {
                // Create a clone of the array as it contains objects...
                $postinfo = serialize($allposts[$instance->id]);
                $postinfo = unserialize($postinfo);
            }
            // Create instance links.
            // $links = $xpath->query("/DATA/LINKS/LINK[OUBLOGINSTANCESID=$instance->id]");
            $links = array();
            if (isset($alllinks[$instance->id])) {
                $links = $alllinks[$instance->id];
            }
            $linksa = array();
            // Sort by SORTORDER - so lowest first.
            foreach ($links as $newlink) {
                // Create new link object and add to our new array.
                // $newlink = childnodes_to_object($link);
                $newlink->oubloginstancesid = $instance->newid;
                $newlink->oublogid = $blog->id;
                unset($newlink->id);
                if (!isset($newlink->sortorder)) {
                    $newlink->sortorder = 0;
                }
                $linksa[] = $newlink;
            }
            $links = null;
            // Sort by SORTORDER - so lowest first.
            usort($linksa, 'oublog_sort_links');
            foreach ($linksa as $link) {
                // Create link.
                $link->url = oublog_decode_perbloglinks($link->url, $xpath, $postinfo, $instance->userid);
                if (!oublog_add_link($link)) {
                    output("Error: Failed to create link for blog:{$instance->newid}");
                }
            }
            $linksa = null;
            // End of link creation code.
            output('Finished links');
            output('Processing posts');
            // PROCESS Blog posts.
            $instance->postmapping = array();
            // Store old + new ids.
            // $posts = $xpath->query("/DATA/POSTS/POST[OUBLOGINSTANCESID=$instance->id]");
            $posts = array();
            if (isset($allposts[$instance->id])) {
                $posts = $allposts[$instance->id];
            }
            output(count($posts) . ' posts to process');
            foreach ($posts as $newpost) {
                // Sort out post object ready to save.
                // $newpost = childnodes_to_object($post);
                $oldid = $newpost->id;
                unset($newpost->id);
                $newpost->groupid = 0;
                // Just in case!
                $newpost->oubloginstancesid = $instance->newid;
                if (!is_null($newpost->deletedby)) {
                    if ($tagsonly) {
                        continue;
                        // Don't update deleted post tags.
                    }
                    if ($newpost->deletedby == $instance->userid) {
                        // Most of the time will be blog user.
                        $newpost->deletedby = $instance->newuserid;
                    } else {
                        // Find mapped user id in this system.
                        // $users = $xpath->query("/DATA/USERS/USER[@id=$newpost->deletedby]");
                        $users = isset($allusers[$newpost->deletedby]) ? $allusers[$newpost->deletedby] : false;
                        if (!$users) {
                            $newpost->deletedby = false;
                        } else {
                            $newpost->deletedby = oublog_search_create_user($users);
                        }
                        if ($newpost->deletedby == false) {
                            output("Error: Failed to get/make user id for deletedby, old post id: {$oldid}");
                            $newpost->deletedby = $instance->newuserid;
                        }
                    }
                }
                if (!$tagsonly) {
                    if (!is_null($newpost->lasteditedby)) {
                        if ($newpost->lasteditedby == $instance->userid) {
                            // Most of the time will be blog user.
                            $newpost->lasteditedby = $instance->newuserid;
                        } else {
                            // Find mapped user id in this system.
                            // $users = $xpath->query("/DATA/USERS/USER[@id=$newpost->lasteditedby]");
                            $users = isset($allusers[$newpost->lasteditedby]) ? $allusers[$newpost->lasteditedby] : false;
                            if (!$users) {
                                $newpost->lasteditedby = false;
                            } else {
                                $newpost->lasteditedby = oublog_search_create_user($users);
                            }
                            if ($newpost->lasteditedby == false) {
                                output("Error: Failed to get/make user id for edited by, old post id: {$oldid}");
                                $newpost->lasteditedby = $instance->newuserid;
                            }
                        }
                    }
                    $newpost->message = oublog_decode_perbloglinks($newpost->message, $xpath, $postinfo, $instance->userid);
                    if (!($postid = $DB->insert_record('oublog_posts', $newpost))) {
                        output("<b>Error: Failed to create post, old id = {$oldid}</b>");
                        continue;
                    }
                } else {
                    // Tag fix only mode. Search for post previously created to use as $postid.
                    if (!($post = $DB->get_record_sql('select id, message from {oublog_posts} where oubloginstancesid
                             = :oubloginstancesid and timeposted = :timeposted and title = :title and deletedby is null', array('oubloginstancesid' => $instance->newid, 'timeposted' => $newpost->timeposted, 'title' => $newpost->title)))) {
                        output("<b>Error: Failed to find post (TAG FIX), old id = {$oldid}</b>");
                        continue;
                    }
                    $postid = $post->id;
                    $newpost->message = $post->message;
                    // Ensure matches that on system.
                    // Store existing tags so any extra added not removed.
                    $tagnames = oublog_get_post_tags($post);
                    $post = null;
                }
                $instance->postmapping[$oldid] = $postid;
                // Record old/new id mapping.
                output('', true);
                // Output dots.
                // Migrate any mystuff images in message.
                if (!$tagsonly && (strpos($newpost->message, '@@PLUGINFILE@@') || stripos($newpost->message, $SOURCESERVER . '/pix/smartpix.php/ou/s/'))) {
                    $updaterec = new stdClass();
                    $updaterec->id = $postid;
                    $updaterec->message = oublog_add_files($newpost->message, $dir, $blogcontext->id, 'message', $postid);
                    $DB->update_record('oublog_posts', $updaterec);
                    $updaterec = null;
                }
                // Add post tags (also used in search to save DB query).
                $newpost->tags = array();
                // $tags = $xpath->query("/DATA/TAGS/TAG[POSTID=$oldid]");
                if (!$tagsonly || empty($tagnames)) {
                    $tagnames = array();
                }
                $tags = array();
                if (isset($alltags[$oldid])) {
                    $tags = $alltags[$oldid];
                }
                foreach ($tags as $tag) {
                    $tagnames[] = $tag->tagname;
                }
                if (!empty($tagnames)) {
                    $tagnames = array_unique(array_filter($tagnames));
                    oublog_update_item_tags($instance->newid, $postid, $tagnames);
                    $newpost->tags = $tagnames;
                    $tagnames = null;
                }
                if (is_null($newpost->deletedby)) {
                    // Update search.
                    $newpost->id = $postid;
                    $newpost->userid = $instance->newuserid;
                    oublog_search_update($newpost, $cm);
                    output('', true);
                }
                $newpost = null;
            }
            $posts = null;
            // End Blog post processing.
            output('Finished Posts');
            // From now on all data is got from looping through postmapping array each time.
            // PROCESS Blog EDITS.
            foreach ($instance->postmapping as $oldpostid => $newpostid) {
                // $edits = $xpath->query("/DATA/EDITS/EDIT[POSTID=$oldpostid]");
                $edits = array();
                if (isset($alledits[$oldpostid])) {
                    $edits = $alledits[$oldpostid];
                }
                foreach ($edits as $newedit) {
                    // Sort out edit object ready to save.
                    // $newedit = childnodes_to_object($edit);
                    unset($newedit->id);
                    $newedit->postid = $newpostid;
                    if ($newedit->userid == $instance->userid) {
                        // Most of the time will be blog user.
                        $newedit->userid = $instance->newuserid;
                    } else {
                        // Find mapped user id in this system.
                        // $users = $xpath->query("/DATA/USERS/USER[@id=$newedit->userid]");
                        $users = isset($allusers[$newedit->userid]) ? $allusers[$newedit->userid] : false;
                        if (!$users) {
                            $newedit->userid = false;
                        } else {
                            $newedit->userid = oublog_search_create_user($users);
                        }
                        if ($newedit->userid == false) {
                            output("Error: Failed to get/make user id for edit rec, old post id: {$oldpostid}");
                            $newedit->userid = $instance->newuserid;
                        }
                    }
                    $newedit->oldmessage = oublog_decode_perbloglinks($newedit->oldmessage, $xpath, $postinfo, $instance->userid);
                    output('', true);
                    // Output dots.
                    // Migrate any mystuff images in message.
                    if (strpos($newedit->oldmessage, '@@PLUGINFILE@@') || stripos($newedit->oldmessage, $SOURCESERVER . '/pix/smartpix.php/ou/s/')) {
                        $newedit->oldmessage = oublog_add_files($newedit->oldmessage, $dir, $blogcontext->id, 'message', $newpostid);
                    }
                    if (!($newid = $DB->insert_record('oublog_edits', $newedit))) {
                        output("Error: Failed to create edit for old post id: {$oldpostid}");
                        continue;
                    }
                    $newedit = null;
                }
                $edits = null;
            }
            output('Finished edits');
            // End Blog EDITS processing.
            // Process blog comments (Standard + Approved only).
            foreach ($instance->postmapping as $oldpostid => $newpostid) {
                // $comments = $xpath->query("/DATA/COMMENTS/COMMENT[POSTID=$oldpostid]");
                $comments = array();
                if (isset($allcomments[$oldpostid])) {
                    $comments = $allcomments[$oldpostid];
                }
                foreach ($comments as $newcomment) {
                    // Sort out edit object ready to save.
                    // $newcomment = childnodes_to_object($comment);
                    $newcomment->postid = $newpostid;
                    if (!blogxml_isempty($newcomment->userid)) {
                        if ($newcomment->userid == $instance->userid) {
                            // Most of the time will be blog user.
                            $newcomment->userid = $instance->newuserid;
                        } else {
                            // Find mapped user id in this system.
                            // $users = $xpath->query("/DATA/USERS/USER[@id='$newcomment->userid']");
                            $users = isset($allusers[$newcomment->userid]) ? $allusers[$newcomment->userid] : false;
                            if (!$users || empty($users)) {
                                $newcomment->userid = false;
                            } else {
                                $newcomment->userid = oublog_search_create_user($users);
                            }
                            if ($newcomment->userid == false) {
                                output("Error: Failed to get/make user id for comment, old id: {$newcomment->id} file:{$xmlfilenum}");
                                continue;
                                // Skip this comment.
                            }
                        }
                    }
                    if (!blogxml_isempty($newcomment->deletedby)) {
                        if ($newcomment->deletedby == $instance->userid) {
                            // Most of the time will be blog user.
                            $newcomment->deletedby = $instance->newuserid;
                        } else {
                            // Find mapped user id in this system.
                            // $users = $xpath->query("/DATA/USERS/USER[@id=$newcomment->deletedby]");
                            $users = isset($allusers[$newcomment->deletedby]) ? $allusers[$newcomment->deletedby] : false;
                            if (!$users) {
                                $newcomment->deletedby = false;
                            } else {
                                $newcomment->deletedby = oublog_search_create_user($users);
                            }
                            if ($newcomment->deletedby == false) {
                                output("Error: Failed to get/make user id for comment deletedby, old id: {$newcomment->id}");
                                $newcomment->deletedby = $instance->newuserid;
                            }
                        }
                    }
                    $newcomment->message = oublog_decode_perbloglinks($newcomment->message, $xpath, $postinfo, $instance->userid);
                    unset($newcomment->id);
                    if (!($newid = $DB->insert_record('oublog_comments', $newcomment))) {
                        output("Error: Failed to create comment for old post id: {$oldpostid}");
                        continue;
                    }
                    output('', true);
                    // Output dots.
                    // Migrate any mystuff images in message.
                    if (strpos($newcomment->message, '@@PLUGINFILE@@') || stripos($newcomment->message, $SOURCESERVER . '/pix/smartpix.php/ou/s/')) {
                        $updaterec = new stdClass();
                        $updaterec->id = $newid;
                        $updaterec->message = oublog_add_files($newcomment->message, $dir, $blogcontext->id, 'messagecomment', $newid);
                        $DB->update_record('oublog_comments', $updaterec);
                        $updaterec = null;
                    }
                    $newcomment = null;
                }
                $comments = null;
            }
            output('Finished comments');
            // End comments.
            // Commit everything in this instance.
            if ($kill) {
                throw new moodle_exception('kill');
            } else {
                // Commit and save that instance has been imported.
                $trans->allow_commit();
                $trans->dispose();
                $donetag->appendChild($donedoc->createElement('instance', $instance->id));
                if (!$donedoc->save($dir . '/imported.xml')) {
                    output('<b>Error saving xml record of instance, will be picked up next save</b>');
                }
            }
        } catch (moodle_exception $e) {
            output('<b>Code error:</b> ' . $e->debuginfo);
            try {
                output('Rollback transation');
                $trans->rollback($e);
            } catch (moodle_exception $e) {
                output('<b>Code error:</b> ' . $e->debuginfo);
                $trans = null;
                continue;
            } catch (Exception $e) {
                output('<b>Code error:</b> ' . $e->debuginfo);
                $trans = null;
                continue;
            }
        } catch (Exception $e) {
            output('<b>Code error:</b> ' . $e->debuginfo);
            $trans->rollback($e);
            $trans = null;
            continue;
        }
        $trans = null;
    }
    output('<b>Finished</b>');
}