/**
  * execute
  *
  * Main entry point for class
  *
  * @author Krzysztof Krzyżaniak <*****@*****.**>
  *
  * @return integer: wikia id or null if wikia is not handled by WikiFactory
  */
 public function execute()
 {
     wfProfileIn(__METHOD__);
     global $wgCityId, $wgDevelEnvironment, $wgDBservers, $wgLBFactoryConf, $wgDBserver, $wgContLang;
     /**
      * Hook to allow extensions to alter the initialization.  For example,
      * setting the mCityID then returning true will override which wiki
      * to use.
      *
      * @author Sean Colombo
      */
     if (!wfRunHooks('WikiFactory::execute', array(&$this))) {
         wfProfileOut(__METHOD__);
         return $this->mWikiID;
     }
     /**
      * load balancer uses one method which demand wgContLang defined
      * See BugId: 12474
      */
     $wgContLang = new StubObject('wgContLang');
     /**
      * local cache, change to CACHE_ACCEL for local
      */
     global $wgWikiFactoryCacheType;
     $oMemc = wfGetCache($wgWikiFactoryCacheType);
     if (empty($this->mAlwaysFromDB)) {
         /**
          * remember! for http requests we only known $this->mServerName
          * (domain), $this->mCityId is unknown (set to false in constructor)
          */
         wfProfileIn(__METHOD__ . "-domaincache");
         $key = WikiFactory::getDomainKey($this->mServerName);
         $this->mDomain = $oMemc->get($key);
         $this->mDomain = isset($this->mDomain["id"]) ? $this->mDomain : array();
         $this->debug("reading from cache, key {$key}");
         wfProfileOut(__METHOD__ . "-domaincache");
     }
     if (!isset($this->mDomain["id"]) || $this->mAlwaysFromDB) {
         wfProfileIn(__METHOD__ . "-domaindb");
         /**
          * first run or cache expired
          */
         $dbr = $this->getDB();
         /**
          * interactive/cmdline case. We know city_id so we don't have to
          * ask city_domains table
          */
         if ($this->mCityID || $this->mCityDB) {
             $oRow = $dbr->selectRow(array("city_list"), array("city_id", "city_public", "city_factory_timestamp", "city_url", "city_dbname"), $this->mCityID ? array("city_list.city_id" => $this->mCityID) : array("city_list.city_dbname" => $this->mCityDB), __METHOD__ . '::domaindb');
             if (isset($oRow->city_id)) {
                 preg_match("/http[s]*\\:\\/\\/(.+)\$/", $oRow->city_url, $matches);
                 $host = rtrim($matches[1], "/");
                 $this->mCityID = $oRow->city_id;
                 $this->mWikiID = $oRow->city_id;
                 $this->mIsWikiaActive = $oRow->city_public;
                 $this->mCityHost = $host;
                 $this->mCityDB = $oRow->city_dbname;
                 $this->mTimestamp = $oRow->city_factory_timestamp;
                 $this->mDomain = array("id" => $oRow->city_id, "host" => $host, "active" => $oRow->city_public, "time" => $oRow->city_factory_timestamp, "db" => $this->mCityDB);
             }
         } else {
             /**
              * request from HTTPD case. We only know server name so we
              * have to ask city_domains table
              */
             $oRow = $dbr->selectRow(array("city_domains", "city_list"), array("city_list.city_id", "city_public", "city_factory_timestamp", "city_domain", "city_url", "city_dbname"), array("city_domains.city_id = city_list.city_id", "city_domains.city_domain" => $this->mServerName), __METHOD__ . '::servername');
             if (isset($oRow->city_id) && $oRow->city_id > 0) {
                 $oRow->city_domain = strtolower($oRow->city_domain);
                 preg_match("/http[s]*\\:\\/\\/(.+)\$/", $oRow->city_url, $matches);
                 $host = rtrim($matches[1], "/");
                 if ($oRow->city_domain == $this->mServerName && $this->mServerName) {
                     $this->mWikiID = $oRow->city_id;
                     $this->mIsWikiaActive = $oRow->city_public;
                     $this->mCityHost = $host;
                     $this->mCityDB = $oRow->city_dbname;
                     $this->mTimestamp = $oRow->city_factory_timestamp;
                     $this->mDomain = array("id" => $oRow->city_id, "host" => $host, "active" => $oRow->city_public, "time" => $oRow->city_factory_timestamp, "db" => $oRow->city_dbname);
                 }
             }
         }
         if (empty($this->mAlwaysFromDB) && !empty($this->mWikiID)) {
             /**
              * store value in cache
              */
             $oMemc->set(WikiFactory::getDomainKey($this->mServerName), $this->mDomain, $this->mExpireDomainCacheTimeout);
         }
         $this->debug("city_id={$this->mWikiID}, reading from database key {$this->mServerName}");
         wfProfileOut(__METHOD__ . "-domaindb");
     } else {
         /**
          * data taken from cache
          */
         $this->mWikiID = $this->mDomain["id"];
         $this->mCityHost = $this->mDomain["host"];
         $this->mIsWikiaActive = $this->mDomain["active"];
         $this->mTimestamp = isset($this->mDomain["time"]) ? $this->mDomain["time"] : null;
         $this->mCityDB = isset($this->mDomain["db"]) ? $this->mDomain["db"] : false;
     }
     /**
      * save default var values for Special:WikiFactory
      * @todo this should be smarter...
      */
     if ($this->mWikiID == 177) {
         $this->mSaveDefaults = true;
     }
     /**
      * redirection to another url
      */
     if ($this->mIsWikiaActive == 2) {
         $this->debug("city_id={$this->mWikiID};city_public={$this->mIsWikiaActive}), redirected to {$this->mCityHost}");
         header("X-Redirected-By-WF: 2");
         header("Location: http://{$this->mCityHost}/", true, 301);
         wfProfileOut(__METHOD__);
         exit(0);
     }
     /**
      * if $this->mCityURL different from city_url we redirect to city_url
      * (as main server)
      *
      * mCityHost may contain path after url (memory-alpha, dofus), we just
      * split this for comparing hosts.
      */
     list($host, $path) = array_pad(explode("/", $this->mCityHost, 2), 2, false);
     /**
      * check if domain from browser is different than main domain for wiki
      */
     $cond1 = !empty($host) && !empty($this->mServerName) && strtolower($host) != $this->mServerName;
     /**
      * check if not additional domain was used (then we redirect anyway)
      */
     $cond2 = !empty($host) && $this->mAlternativeDomainUsed && $host != $this->mOldServerName;
     if (($cond1 || $cond2) && empty($wgDevelEnvironment)) {
         $url = wfGetCurrentUrl();
         /**
          * now recombine url from parts
          */
         if (preg_match("!^/{$path}!", $url["path"]) == 0) {
             $url["path"] = "/{$path}" . $url["path"];
         }
         $target = $url["scheme"] . "://" . $host . $url["path"];
         $target = isset($url["query"]) ? $target . "?" . $url["query"] : $target;
         $this->debug("redirected from {$url["url"]} to {$target}");
         header("X-Redirected-By-WF: NotPrimary");
         header("Location: {$target}", true, 301);
         wfProfileOut(__METHOD__);
         exit(0);
     }
     /**
      * if wikia is not defined or is marked for closing we redirect to
      * Not_a_valid_Wikia
      * @todo the -1 status should probably be removed or defined more precisely
      */
     if (empty($this->mWikiID) || $this->mIsWikiaActive == -1) {
         if (!$this->mCommandLine) {
             global $wgNotAValidWikia;
             $this->debug("redirected to {$wgNotAValidWikia}, {$this->mWikiID} {$this->mIsWikiaActive}");
             if ($this->mIsWikiaActive < 0) {
                 header("X-Redirected-By-WF: MarkedForClosing");
             } else {
                 header("X-Redirected-By-WF: NotAValidWikia");
             }
             header("Location: {$wgNotAValidWikia}");
             wfProfileOut(__METHOD__);
             exit(0);
         }
     }
     /**
      * if wikia is disabled and is not Commandline mode we redirect it to
      * dump directory.
      */
     if (empty($this->mIsWikiaActive) || $this->mIsWikiaActive == -2) {
         if (!$this->mCommandLine) {
             global $wgNotAValidWikia;
             if ($this->mCityDB) {
                 $database = strtolower($this->mCityDB);
                 $redirect = sprintf("http://%s/wiki/Special:CloseWiki/information/%s", $wgDevelEnvironment ? "www.awc.wikia-inc.com" : "community.wikia.com", $database);
             } else {
                 $redirect = $wgNotAValidWikia;
             }
             $this->debug("disabled and not commandline, redirected to {$redirect}, {$this->mWikiID} {$this->mIsWikiaActive}");
             header("X-Redirected-By-WF: Dump");
             header("Location: {$redirect}");
             wfProfileOut(__METHOD__);
             exit(0);
         }
     }
     /**
      * for yellowikis.wikia check geolocation and for GB -> redirect to owikis
      * @author Przemek Piotrowski (Nef)
      */
     if (0 === strpos($this->mServerName, 'yellowikis.')) {
         header("X-Redirected-By-WF: Geo");
         global $wgLocationOfGeoIPDatabase;
         if (!empty($wgLocationOfGeoIPDatabase) && file_exists($wgLocationOfGeoIPDatabase)) {
             /**
              * ProxyTools methods cannot be used because PT is not loaded at this point.
              * PT cannot be just included as it requires a lot to be initialized first )-:
              *
              * Order is *important* here! Proxy are added "from the right side"
              * to the combined HTTP_X_FORWARDED_FOR + REMOTE_ADDR.
              */
             $ips = array();
             if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                 $ips = preg_split('/\\s*,\\s*/', $_SERVER['HTTP_X_FORWARDED_FOR']);
             }
             if (!empty($_SERVER['REMOTE_ADDR'])) {
                 $ips[] = $_SERVER['REMOTE_ADDR'];
             }
             if (!empty($ips[0])) {
                 require_once 'Net/GeoIP.php';
                 try {
                     $geoip = Net_GeoIP::getInstance($wgLocationOfGeoIPDatabase);
                     if ('GB' == $geoip->lookupCountryCode($ips[0])) {
                         header("X-Redirected-By-WF: Geo");
                         /**
                          * just exit, no redirect at all
                          */
                         wfProfileOut(__METHOD__);
                         exit(0);
                     }
                 } catch (Exception $e) {
                     #--- ignore exception, redirect is an option, not a necessity
                 }
             }
         }
     }
     /**
      * get info about city variables from memcached and then check,
      * maybe memcached is down and returned only error code
      */
     if (empty($this->mAlwaysFromDB)) {
         wfProfileIn(__METHOD__ . "-varscache");
         /**
          * first from serialized file
          */
         $key = WikiFactory::getVarsKey($this->mWikiID);
         $data = $oMemc->get($key);
         if (isset($data["stamp"]) && $data["stamp"] == $this->mTimestamp) {
             $this->mVariables = isset($data["data"]) && is_array($data["data"]) ? $data["data"] : array();
             $this->debug("wikifactory: reading from cache, key {$key}, count " . count($this->mVariables));
         } else {
             $this->debug("wikifactory: timestamp doesn't match. Cache expired");
         }
         wfProfileOut(__METHOD__ . "-varscache");
     }
     /**
      * if wgDBname is not defined we get all variables from database
      */
     if (!isset($this->mVariables["wgDBname"])) {
         wfProfileIn(__METHOD__ . "-varsdb");
         $dbr = $this->getDB();
         $oRes = $dbr->select(array("city_variables", "city_variables_pool"), array("cv_name", "cv_value"), array("cv_id = cv_variable_id", "cv_city_id = {$this->mWikiID}"), __METHOD__ . '::varsdb');
         while ($oRow = $dbr->fetchObject($oRes)) {
             #--- some magic, rewritting path, etc legacy data
             global $_variable_key, $_variable_value;
             set_error_handler("wfUnserializeHandler");
             $_variable_key = $oRow->cv_name;
             $_variable_value = $oRow->cv_value;
             $tUnserVal = unserialize($oRow->cv_value);
             restore_error_handler();
             if (!empty($wgDevelEnvironment) && $oRow->cv_name === "wgServer") {
                 /**
                  * skip this variable
                  */
                 unset($this->mVariables[$oRow->cv_name]);
                 $this->debug("{$oRow->cv_name} with value {$tUnserVal} skipped");
             } else {
                 $this->mVariables[$oRow->cv_name] = $tUnserVal;
             }
         }
         $dbr->freeResult($oRes);
         /**
          * wgArticlePath
          */
         if (!isset($this->mVariables['wgArticlePath'])) {
             $this->mVariables['wgArticlePath'] = $GLOBALS['wgArticlePath'];
         }
         /**
          * read tags for this wiki, store in global variable as array
          * @name $wgWikiFactoryTags
          */
         wfProfileIn(__METHOD__ . "-tagsdb");
         $this->mVariables["wgWikiFactoryTags"] = array();
         $sth = $dbr->select(array("city_tag", "city_tag_map"), array("id", "name"), array("city_tag.id = city_tag_map.tag_id", "city_id = {$this->mWikiID}"), __METHOD__ . '::tagsdb');
         while ($row = $dbr->fetchObject($sth)) {
             $this->mVariables["wgWikiFactoryTags"][$row->id] = $row->name;
         }
         $dbr->freeResult($sth);
         $this->debug("reading tags from database, id {$this->mWikiID}, count " . count($this->mVariables["wgWikiFactoryTags"]));
         wfProfileOut(__METHOD__ . "-tagsdb");
         if (empty($this->mAlwaysFromDB)) {
             /**
              * cache as well some values even if they are not defined in database
              * it will prevent GlobalTitle from doing empty selects
              * BugId: 12463
              */
             foreach ($this->mCacheAnyway as $cvar) {
                 if (!isset($this->mVariables[$cvar]) && isset($GLOBALS[$cvar])) {
                     $this->mVariables[$cvar] = $GLOBALS[$cvar];
                 }
             }
             /**
              * store values in memcache
              */
             $oMemc->set(WikiFactory::getVarsKey($this->mWikiID), array("stamp" => $this->mTimestamp, "data" => $this->mVariables), $this->mExpireValuesCacheTimeout);
         }
         $this->debug("reading from database, id {$this->mWikiID}, count " . count($this->mVariables));
         wfProfileOut(__METHOD__ . "-varsdb");
         /**
          * maybe upgrade database to current schema
          */
         if ($this->mCheckUpgrade === true) {
             $this->maybeUpgrade();
         }
     }
     // @author macbre
     wfRunHooks('WikiFactory::executeBeforeTransferToGlobals', array(&$this));
     /**
      * transfer configuration variables from database to GLOBALS
      */
     if (is_array($this->mVariables)) {
         foreach ($this->mVariables as $key => $value) {
             $tValue = $value;
             #--- check, maybe there are variables in variable
             if (is_string($tValue)) {
                 preg_match_all('/(\\$\\w+)[^\\w]*/', $tValue, $aMatches);
                 if (is_array($aMatches[1])) {
                     foreach ($aMatches[1] as $tKey) {
                         /**
                          * dolar sign in key should be removed
                          * (str_replace is faster than regexp)
                          */
                         $tKeyParsed = str_replace('$', '', $tKey);
                         if (!is_numeric($tKeyParsed)) {
                             #--- replace only if key is not $1, $2 etc.
                             if (array_key_exists($tKeyParsed, $this->mVariables)) {
                                 $tValue = str_replace($tKey, $this->mVariables[$tKeyParsed], $tValue);
                             } else {
                                 if (isset($GLOBALS[$tKeyParsed])) {
                                     $tValue = str_replace($tKey, $GLOBALS[$tKeyParsed], $tValue);
                                 }
                             }
                         }
                     }
                 }
             }
             /**
              * merge local values with global
              */
             switch ($key) {
                 case "wgNamespacesWithSubpagesLocal":
                     $this->LocalToGlobalArray($tValue, $GLOBALS["wgNamespacesWithSubpages"]);
                     break;
                 case "wgExtraNamespacesLocal":
                     $this->LocalToGlobalArray($tValue, $GLOBALS["wgExtraNamespaces"]);
                     break;
                 case "wgFileExtensionsLocal":
                     $this->LocalToGlobalArray($tValue, $GLOBALS["wgFileExtensions"], true);
                     break;
                 case "wgTrustedMediaFormatsLocal":
                     $this->LocalToGlobalArray($tValue, $GLOBALS["wgTrustedMediaFormats"]);
                     break;
                 case "wgFileBlacklistLocal":
                     $this->LocalToGlobalArray($tValue, $GLOBALS["wgFileBlacklist"]);
                     break;
             }
             if ($key == 'wgServer') {
                 $headers = Wikia::getAllHeaders();
                 if (array_key_exists('X-Original-Host', $headers) && !empty($headers['X-Original-Host'])) {
                     global $wgConf;
                     $tValue = 'http://' . $headers['X-Original-Host'];
                     $wgConf->localVHosts = array_merge($wgConf->localVHosts, array($headers['X-Original-Host']));
                 }
             }
             try {
                 if ($this->mSaveDefaults) {
                     $GLOBALS['wgPreWikiFactoryValues'][$key] = $tValue;
                 }
                 $GLOBALS[$key] = $tValue;
             } catch (Exception $e) {
                 #--- so far do nothing
             }
         }
     }
     $wgCityId = $this->mWikiID;
     /**
      * set/replace $wgDBname in $wgDBservers
      */
     if (isset($wgDBservers) && is_array($wgDBservers) && isset($this->mVariables["wgDBname"])) {
         foreach ($wgDBservers as $index => $server) {
             $wgDBservers[$index]["dbname"] = $this->mVariables["wgDBname"];
         }
     }
     if (isset($wgLBFactoryConf) && is_array($wgLBFactoryConf) && isset($this->mVariables["wgDBname"])) {
         $wgLBFactoryConf['serverTemplate']['dbname'] = $this->mVariables["wgDBname"];
         /**
          * set wgDBserver for cluster based on $wgLBFactoryConf
          */
         $cluster = isset($this->mVariables["wgDBcluster"]) ? $this->mVariables["wgDBcluster"] : "DEFAULT";
         if (isset($wgLBFactoryConf["sectionLoads"][$cluster])) {
             $keys = array_keys($wgLBFactoryConf["sectionLoads"][$cluster]);
             $db = array_shift($keys);
             if (isset($wgLBFactoryConf["hostsByName"][$db])) {
                 $wgDBserver = $wgLBFactoryConf["hostsByName"][$db];
                 $this->debug("wgDBserver for cluster {$cluster} set to {$wgDBserver}");
             }
         }
     }
     wfRunHooks('WikiFactory::onExecuteComplete', array(&$this));
     wfProfileOut(__METHOD__);
     /**
      * cleanup and finally return wiki id
      */
     LBFactory::destroyInstance();
     return $this->mWikiID;
 }