/**
	 * Fetches and preprocesses graph data that can be fed to graph drawer.
	 * @param $opts FormOptions
	 * @return \arrayof{String,Array} Data indexed by their date labels.
	 */
	protected function getData( FormOptions $opts ) {
		global $wgLang;
		$dbr = wfGetDB( DB_SLAVE );

		if ( $opts['count'] === 'registrations' ) {
			$so = new TranslateRegistrationStats( $opts );
		} else {
			$so = new TranslatePerLanguageStats( $opts );
		}

		$fixedStart = $opts->getValue( 'start' ) !== '';

		$now = time();
		$period = 3600 * 24 * $opts->getValue( 'days' );

		if ( $fixedStart ) {
			$cutoff = wfTimestamp( TS_UNIX, $opts->getValue( 'start' ) );
		} else {
			$cutoff = $now - $period;
		}
		$cutoff = self::roundTimestampToCutoff( $opts['scale'], $cutoff, 'earlier' );

		$start = $cutoff;

		if ( $fixedStart ) {
			$end = self::roundTimestampToCutoff( $opts['scale'], $start + $period, 'later' ) -1;
		} else {
			$end = null;
		}

		$tables = array();
		$fields = array();
		$conds = array();
		$type = __METHOD__;
		$options = array();

		$so->preQuery( $tables, $fields, $conds, $type, $options, $start, $end );
		$res = $dbr->select( $tables, $fields, $conds, $type, $options );
		wfDebug( __METHOD__ . "-queryend\n" );

		// Start processing the data
		$dateFormat = $so->getDateFormat();
		$increment = self::getIncrement( $opts['scale'] );

		$labels = $so->labels();
		$keys = array_keys( $labels );
		$values = array_pad( array(), count( $labels ), 0 );
		$defaults = array_combine( $keys, $values );

		$data = array();
		// Allow 10 seconds in the future for processing time
		$lastValue = $end !== null ? $end : $now + 10;
		while ( $cutoff <= $lastValue ) {
			$date = $wgLang->sprintfDate( $dateFormat, wfTimestamp( TS_MW, $cutoff ) );
			$cutoff += $increment;
			$data[$date] = $defaults;
		}

		// Processing
		$labelToIndex = array_flip( $labels );

		foreach ( $res as $row ) {
			$indexLabels = $so->indexOf( $row );
			if ( $indexLabels === false ) {
				continue;
			}

			foreach ( (array) $indexLabels as $i ) {
				if ( !isset( $labelToIndex[$i] ) ) {
					continue;

				}
				$date = $wgLang->sprintfDate( $dateFormat, $so->getTimestamp( $row ) );
				// Ignore values outside range
				if ( !isset( $data[$date] ) ) {
					continue;
				}

				$data[$date][$labelToIndex[$i]]++;
			}
		}

		// Don't display dummy label
		if ( count( $labels ) === 1 && $labels[0] === 'all' ) {
			$labels = array();
		}

		foreach ( $labels as &$label ) {
			if ( strpos( $label, '@' ) === false ) continue;
			list( $groupId, $code ) = explode( '@', $label, 2 );
			if ( $code && $groupId ) {
				$code = TranslateUtils::getLanguageName( $code, false, $wgLang->getCode() ) . " ($code)";
				$group = MessageGroups::getGroup( $groupId );
				$group = $group ? $group->getLabel() : $groupId;
				$label = "$group @ $code";
			} elseif ( $code ) {
				$label = TranslateUtils::getLanguageName( $code, false, $wgLang->getCode() ) . " ($code)";
			} elseif ( $groupId ) {
				$group = MessageGroups::getGroup( $groupId );
				$label = $group ? $group->getLabel() : $groupId;
			}
		}

		if ( $end == null ) {
			$last = array_splice( $data, -1, 1 );
			// Indicator that the last value is not full
			$data[key( $last ) . '*'] = current( $last );
		}

		return array( $labels, $data );
	}
 /**
  * Fetches and preprocesses graph data that can be fed to graph drawer.
  * @param $opts FormOptions
  * @return \arrayof{String,Array} Data indexed by their date labels.
  */
 protected function getData(FormOptions $opts)
 {
     global $wgLang;
     $dbr = wfGetDB(DB_SLAVE);
     if ($opts['count'] === 'registrations') {
         $so = new TranslateRegistrationStats($opts);
     } else {
         $so = new TranslatePerLanguageStats($opts);
     }
     $start = mktime('00', '00', '00', $opts->getValue('startmonth'), $opts->getValue('startday'), $opts->getValue('startyear'));
     $end = mktime('23', '59', '59', $opts->getValue('endmonth'), $opts->getValue('endday'), $opts->getValue('endyear'));
     /* Ensure that the first item in the graph has full data even
      * if it doesn't align with the given 'days' boundary */
     /*		$cutoff = $now - ( 3600 * 24 * $opts->getValue( 'days' ) );
     		if ( $opts['scale'] === 'hours' ) {
     			$cutoff -= ( $cutoff % 3600 );
     		} elseif ( $opts['scale'] === 'days' ) {
     			$cutoff -= ( $cutoff % 86400 );
     		} elseif ( $opts['scale'] === 'weeks' ) {
     			/* Here we assume that week starts on monday, which does not
     			 * always hold true. Go backwards day by day until we are on monday */
     /*while ( date( 'D', $cutoff ) !== "Mon" ) {
     				$cutoff -= 86400;
     			}
     			$cutoff -= ( $cutoff % 86400 );
     		} elseif ( $opts['scale'] === 'months' ) {
     			// Go backwards day by day until we are on the first day of the month
     			while ( date( 'j', $cutoff ) !== "1" ) {
     				$cutoff -= 86400;
     			}
     			$cutoff -= ( $cutoff % 86400 );
     		}*/
     $tables = array();
     $fields = array();
     $conds = array();
     $type = __METHOD__;
     $options = array();
     $so->preQuery($tables, $fields, $conds, $type, $options, $start, $end);
     $res = $dbr->select($tables, $fields, $conds, $type, $options);
     wfDebug(__METHOD__ . "-queryend\n");
     // Start processing the data
     $dateFormat = $so->getDateFormat();
     $increment = self::getIncrement($opts['scale']);
     $labels = $so->labels();
     $keys = array_keys($labels);
     $values = array_pad(array(), count($labels), 0);
     $defaults = array_combine($keys, $values);
     $data = array();
     // Allow 10 seconds in the future for processing time
     while ($start <= $end) {
         $date = $wgLang->sprintfDate($dateFormat, wfTimestamp(TS_MW, $start));
         $start += $increment;
         $data[$date] = $defaults;
     }
     // Processing
     $labelToIndex = array_flip($labels);
     foreach ($res as $row) {
         $indexLabels = $so->indexOf($row);
         if ($indexLabels === false) {
             continue;
         }
         foreach ((array) $indexLabels as $i) {
             if (!isset($labelToIndex[$i])) {
                 continue;
             }
             $date = $wgLang->sprintfDate($dateFormat, $so->getTimestamp($row));
             // Ignore values outside range
             if (!isset($data[$date])) {
                 continue;
             }
             $data[$date][$labelToIndex[$i]]++;
         }
     }
     // Don't display dummy label
     if (count($labels) === 1 && $labels[0] === 'all') {
         $labels = array();
     }
     foreach ($labels as &$label) {
         if (strpos($label, '@') === false) {
             continue;
         }
         list($groupId, $code) = explode('@', $label, 2);
         if ($code && $groupId) {
             $code = TranslateUtils::getLanguageName($code, false, $wgLang->getCode()) . " ({$code})";
             $group = MessageGroups::getGroup($groupId);
             $group = $group ? $group->getLabel() : $groupId;
             $label = "{$group} @ {$code}";
         } elseif ($code) {
             $label = TranslateUtils::getLanguageName($code, false, $wgLang->getCode()) . " ({$code})";
         } elseif ($groupId) {
             $group = MessageGroups::getGroup($groupId);
             $label = $group ? $group->getLabel() : $groupId;
         }
     }
     $last = array_splice($data, -1, 1);
     $data[key($last) . '*'] = current($last);
     return array($labels, $data);
 }