/**
  * Given a possible action defined in $wgFbOpenGraphRegisteredActions,
  * this function translates the action into the proper Open Graph ID
  * (which usually looks like NAMESPACE:action).
  */
 private static function getAction($action)
 {
     global $wgFbOpenGraph, $wgFbNamespace, $wgFbOpenGraphRegisteredActions;
     if (FacebookAPI::isNamespaceSetup() && !empty($wgFbOpenGraph) && !empty($wgFbOpenGraphRegisteredActions) && !empty($wgFbOpenGraphRegisteredActions[$action])) {
         return $wgFbNamespace . ':' . $wgFbOpenGraphRegisteredActions[$action];
     }
     return false;
 }
 /**
 * Modify the preferences form. At the moment, we simply turn the user name
 * into a link to the user's facebook profile.
 * 
 * TODO: This hook no longer seems to work...
 *
 	public static function RenderPreferencesForm( $form, $output ) {
 		global $facebook, $wgUser;
 		
 		$ids = FacebookDB::getFacebookIDs($wgUser);
 		
 		$fb_user = $facebook->getUser();
 		if( $fb_user && count($ids) > 0 && in_array( $fb_user, $ids )) {
 			$html = $output->getHTML();
 			$name = $wgUser->getName();
 			$i = strpos( $html, $name );
 			if ($i !== FALSE) {
 				// If the user has a valid Facebook ID, link to the Facebook profile
 				try {
 					$fbUser = $facebook->api('/me');
 					// Replace the old output with the new output
 					$html = substr( $html, 0, $i ) .
 					        preg_replace("/$name/", "$name (<a href=\"$fbUser[link]\" " .
 					                     "class='mw-userlink mw-facebookuser'>" .
 					                     wfMsg('facebook-link-to-profile') . "</a>)",
 					                     substr( $html, $i ), 1);
 					$output->clearHTML();
 					$output->addHTML( $html );
 				} catch (FacebookApiException $e) {
 					error_log($e);
 				}
 			}
 		}
 		return true;
 	} // RenderPreferencesForm hook
 	
 	/**
 * Add several meta property namespace attributes to the <head> tag.
 * 
 * This hook follows the steps outlined in the Open Graph Beta tutorial:
 * https://developers.facebook.com/docs/beta/opengraph/tutorial/
 */
 static function SkinTemplateOutputPageBeforeExec(&$skin, &$tpl)
 {
     global $wgFbOpenGraph, $wgFbNamespace, $wgFbOpenGraphRegisteredObjects;
     // If there are no Open Graph tags, we can skip this step
     if (!empty($wgFbOpenGraph)) {
         $head = '<head prefix="og: http://ogp.me/ns#';
         // I think this is for the fb:app_id and fp:page_id meta tags (see link),
         // but your guess is as good as mine
         // https://developers.facebook.com/docs/opengraph/objects/builtin/
         $head .= ' fb: http://ogp.me/ns/fb#';
         if (FacebookAPI::isNamespaceSetup()) {
             $head .= " {$wgFbNamespace}: http://ogp.me/ns/fb/{$wgFbNamespace}#";
         }
         // Use article prefix for built-in type (when $wgFbOpenGraphRegisteredObjects['article'] is empty)
         if (empty($wgFbOpenGraphRegisteredObjects) || empty($wgFbOpenGraphRegisteredObjects['article'])) {
             $head .= ' article: http://ogp.me/ns/article#';
         }
         $head .= '">';
         $headElement = $tpl->data['headelement'];
         $headElement = str_replace('<head>', $head, $headElement);
         $tpl->set('headelement', $headElement);
     }
     return true;
 }
 /**
  * Performs the translation between generic Open Graph object types and
  * custom ones defined by this Facebook application.
  * 
  * @param string $generic
  */
 protected function translateType($generic)
 {
     global $wgFbNamespace, $wgFbOpenGraphRegisteredObjects;
     if (FacebookAPI::isNamespaceSetup()) {
         if (!empty($wgFbOpenGraphRegisteredObjects) && isset($wgFbOpenGraphRegisteredObjects[$generic])) {
             return $wgFbNamespace . ':' . $wgFbOpenGraphRegisteredObjects[$generic];
         } else {
             // "article" is special because it's a built-in type
             return $generic == 'article' ? $generic : $wgFbNamespace . ':' . $generic;
         }
     }
     return $generic;
 }
    /**
     * Special:Connect/Debug
     * 
     * This is the only subpage that can be called directly. It allows an admin
     * to verify that the app is set up correctly inside Facebook, and offers
     * to automatically fix some of the problems it detects.
     */
    private function debugView()
    {
        global $wgRequest, $wgOut, $wgFbNamespace, $wgFbLogo, $wgEmergencyContact, $wgStylePath, $wgVersion;
        // "Enter a page name to view it as an object in the Open Graph." Render a button that
        // submits the wpPageName field to Special:Connect/Debug and handle the submission here.
        // TODO: handle the redirect in execute() maybe
        // The following code is untested
        $pageName = $wgRequest->getText('wpPageName');
        if ($pageName != '') {
            $title = Title::newFromText($pageName);
            if (!$title instanceof Title) {
                $title = Title::newMainPage();
            }
            $url = 'https://developers.facebook.com/tools/debug/og/object?q=' . urlencode($title->getFullURL());
            $wgOut->redirect($url);
            return;
        }
        $wgOut->setPageTitle(wfMsg('facebook-debug-title'));
        // Include the JavaScript that lets us change the application properties
        if (version_compare($wgVersion, '1.17', '>=')) {
            $wgOut->addModules('ext.facebook.application');
        }
        $app = new FacebookApplication();
        $info = $app->getInfo();
        // If the request failed, 'id' will be the only field
        $id = $info['id'];
        unset($info['id']);
        if (empty($info)) {
            $wgOut->addHTML("No application information could be retrieved from Facebook.");
            return;
        }
        $server = '';
        // Lookup the server name
        if (isset($_SERVER['SERVER_NAME'])) {
            $server = $_SERVER['SERVER_NAME'];
        } elseif (isset($_SERVER['HOSTNAME'])) {
            $server = $_SERVER['HOSTNAME'];
        } elseif (isset($_SERVER['HTTP_HOST'])) {
            $server = $_SERVER['HTTP_HOST'];
        } elseif (isset($_SERVER['SERVER_ADDR'])) {
            $server = $_SERVER['SERVER_ADDR'];
        }
        // Might as well not show a blank logo
        if (!$info['icon_url'] && !empty($wgFbLogo)) {
            $info['icon_url'] = $wgFbLogo;
        }
        // Get a link to the creator's wiki page or Facebook profile page
        $creatorLink = '';
        if ($info['creator_uid']) {
            $creator = new FacebookUser($info['creator_uid']);
            if ($creator->getMWUser()->getId()) {
                $creatorLink = '<a href="' . $creator->getMWUser()->getUserPage()->getFullURL() . '">' . $creator->getMWUser()->getName() . '</a>';
            } else {
                $creatorLink = '<span class="mw-facebook-logo"><a ' . 'href="https://www.facebook.com/profile.php?id=' . $info['creator_uid'] . '">' . $info['creator_uid'] . '</a></span>';
            }
        }
        // The values of these fields are pulled from the extension messages
        $fields_with_msgs = array('privacy_policy_url' => 'privacypage', 'terms_of_service_url' => 'facebook-termsofservicepage', 'auth_dialog_headline' => 'facebook-auth-dialog-headline', 'auth_dialog_description' => 'facebook-auth-dialog-description', 'auth_dialog_perms_explanation' => 'facebook-auth-dialog-explanation');
        // Format is: (field_name, Display name, Description, Suggested value)
        $field_array = array(array('namespace', 'Namespace', 'Namespace your app uses for Open Graph', FacebookAPI::isNamespaceSetup() ? $wgFbNamespace : ''), array('website_url', 'Website URL', 'URL of the Main Page', Title::newMainPage()->getFullURL()), array('deauth_callback_url', 'Deauthorize URL', 'Set this to Special:Connect/Deauth', self::getTitleFor('Connect', 'Deauth')->getFullURL()), array('privacy_policy_url', 'Privacy policy URL', 'The Facebook Platform Terms of Service require a privacy policy URL', Title::newFromText(wfMsg($fields_with_msgs['privacy_policy_url']))->getFullURL()), array('terms_of_service_url', 'Terms of service URL', '', Title::newFromText(wfMsg($fields_with_msgs['terms_of_service_url']))->getFullURL()), array('app_domains', 'App domains', 'Domains and subdomains this app can use (e.g., "example.com" will enable *.example.com)', $server), array('contact_email', 'Contact email', 'Primary email used for important communication related to your app ($wgEmergencyContact)', !empty($wgEmergencyContact) ? $wgEmergencyContact : ''), array('user_support_email', 'User support email', 'Required by Facebook: Main contact email for this app ($wgEmergencyContact)', !empty($wgEmergencyContact) ? $wgEmergencyContact : ''), array('auth_dialog_headline', 'Auth dialog headline', 'Description that appears in the Auth Dialog (30 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_headline']))), array('auth_dialog_description', 'Auth dialog description', 'Description that appears in the Auth Dialog (140 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_description']))), array('auth_dialog_perms_explanation', 'Explanation for permissions', 'Provide an explanation for how your app plans to use extended permissions, if any (140 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_perms_explanation']))), array('daily_active_users', 'Daily active users', '', ''), array('weekly_active_users', 'Weekly active users', '', ''), array('monthly_active_users', 'Monthly active users', '', ''));
        // Build the html
        $html = '
<table>
	<tr>
		<td>
			<a href="' . $info['link'] . '">
				<img src="' . $info['logo_url'] . '" style="width:75px; height:75px; margin-right:8px;">
			</a>
		</td>
		<td><div>
			<h3 style="float:left;padding:0 !important;">
				<span style="padding-left: 22px; background:url(\'' . $info['icon_url'] . '\') no-repeat left center;">
					' . $info['name'] . '
				</span>
			</h3>
			<div style="font-size:0.9em;"><table cellpadding="0" cellspacing="0">
				<tr>
					<td><b>App ID:</b></td>
					<td style="padding:0 14px;"><a href="' . $info['link'] . '">' . $id . '</a></td>
				</tr>
				<tr>
					<td><b>App creator:</b></td>
					<td style="padding:0 14px;">' . $creatorLink . '</td>
				</td>
				<tr>
					<td colspan="2" style="font-size:0.95em">
						<a href="https://developers.facebook.com/apps/' . $id . '/summary">(Edit settings)</a>
					</td>
				</tr>
			</table></div>
		</div></td>
	</tr>
</table>
' . wfMsgWikiHtml('facebook-debug-msg') . '<br/>
<table>';
        // The icons we use are included in MW 1.17 (use bits.wikimedia.org if not available)
        if (version_compare($wgVersion, '1.17', '>=')) {
            $icon_base = $wgStylePath;
        } else {
            $icon_base = 'http://bits.wikimedia.org/skins-1.18';
        }
        $icons = array('ok' => array('tooltip' => 'OK', 'src' => $icon_base . '/common/images/tick-32.png'), 'warning' => array('tooltip' => 'Click to update', 'src' => $icon_base . '/common/images/warning-32.png'), 'error' => array('tooltip' => 'Click to update', 'src' => $icon_base . '/common/images/critical-32.png'));
        // Render each setting field of the application as a table row
        foreach ($field_array as $item) {
            $field = $item[0];
            // field_name
            $title = $item[1];
            // Display name
            $tip = $item[2];
            // Description
            $correct = $item[3];
            // Suggested value
            if ($field == 'app_domains') {
                continue;
            }
            // TODO: $field is an array and involves wildcards
            $icon = false;
            if ($correct != '') {
                if ($info[$field] == $correct) {
                    $icon = 'ok';
                } else {
                    switch ($field) {
                        // Critical errors
                        case 'namespace':
                        case 'deauth_callback_url':
                        case 'privacy_policy_url':
                            // Necessary per Facebook's TOS
                        // Necessary per Facebook's TOS
                        case 'user_support_email':
                            // Required: https://developers.facebook.com/blog/post/630/
                            $icon = 'error';
                            break;
                        default:
                            $icon = 'warning';
                    }
                }
            }
            // If the field's value came from a message, link to the message in NS_MEDIAWIKI
            foreach ($fields_with_msgs as $field_name => $msg_name) {
                if ($field == $field_name) {
                    $title = '<a href="' . Title::newFromText($fields_with_msgs[$field], NS_MEDIAWIKI)->getFullURL() . '">' . $title . '</a>';
                    break;
                }
            }
            // Also, if the message is a page name, link to the page (in red) if it doesn't exist
            if ($field == 'privacy_policy_url' || $field == 'terms_of_service_url') {
                $titleObj = Title::newFromText(wfMsg($fields_with_msgs[$field]));
                // Don't add a link to an empty $info[$field]
                if (!$titleObj->exists() && $info[$field] != '') {
                    $info[$field] = '<a href="' . $titleObj->getFullURL() . '" class="new">' . $info[$field] . '</a>';
                }
            }
            // Placeholder indicating particular field is empty
            if ($info[$field] == '') {
                $info[$field] = '<em>empty</em>';
            }
            // Generate the html for the row
            $html .= '
	<tr>
		<td style="text-align:right; padding:0;">
			' . ($tip == '' ? '' : '<img class="mw-facebook-tip" id="facebook-tip-' . $field . '" src="' . $wgStylePath . '/common/images/tooltip_icon.png" title="' . $tip . '" /> &nbsp;') . '
			<b>' . $title . ':</b>
		</td>
		<td class="facebook-field" id="facebook-field-' . $field . '" style="padding:0 0 0 16px; height:22px;">
			<div class="facebook-field-current">
				<span>' . $info[$field] . '</span>
				' . ($icon ? '&nbsp; ' . ($icon != 'ok' ? '<a href="#">' : '') . '<img src="' . $icons[$icon]['src'] . '" style="width:22px; height:22px;" title="' . $icons[$icon]['tooltip'] . '" />' . ($icon != 'ok' ? '</a>' : '') : '') . '
			</div>' . ($icon ? '
			<div class="facebook-field-' . $icon . '" style="display:none;">
				<span>' . $correct . '</span>
				&nbsp; <img src="' . $icons['ok']['src'] . '" style="width:22px; height:22px;" title="' . $icons['ok']['tooltip'] . ' " />
			</div>' : '') . '
		</td>
	</tr>';
        }
        $html .= '
</table><br/>';
        // Add an option to debug Open Graph objects
        $html .= '
<form action="' . $this->getTitle('Debug')->getLocalUrl() . '" method="POST" style="padding-left:14px;">
	<h3>' . wfMsg('facebook-object-debug-title') . '</h3>
	<label for="wpPageName"><p>' . wfMsg('facebook-object-debug') . '</p></label>
	<input name="wpPageName" id="wpPageName" size="42" value="" style="font-size:1.75em;" /> &nbsp;
	<input type="submit" value="' . wfMsg('facebook-debug') . '" name="Debug" />
</form>';
        $html .= "\n<br/><br/>\n";
        $wgOut->addHTML($html);
    }