/**
  * @return string
  */
 function __toString()
 {
     $retval = "";
     $totalCurrTime = $this->raceResult->getTotalCurrTime();
     //echo var_dump($totalCurrTime);
     $this->getRaceTime();
     // this will setup $this->raceTime automatically
     foreach ($totalCurrTime as $i => $lineCross) {
         //var_dump($lineCross);
         $currTime = $lineCross['currTime'];
         $did = $lineCross['driverId'];
         $lap_i = $lineCross['lap_i'];
         // collect info
         // check if finished
         $finalLap = false;
         if ($currTime > $this->raceTime * 60) {
             $finalLap = true;
         }
         $headerString = "";
         $contentString = "";
         $contentFlashString = "";
         if (!$finalLap) {
             // header
             // Pos Name               LastLap Lap# Behind\N
             // 123 123456789012345678 1234567 1234 123456\N
             $headerString = "Pos Name               LastLap Lap# Behind\\N";
             // driver info
             $ctrd = new Timing\CurrTimeRaceData($currTime, $this->raceResult);
             foreach ($ctrd->currTimeDriverDataArr as $ctdd) {
                 /* @var $ctdd Timing\CurrTimeDriverData */
                 if (!empty($ctdd->lapNo)) {
                     $this_pos = $this->makeLengthString($ctdd->pos, 3, "right");
                     $this_name = $this->makeLengthString($ctdd->name, 18, "left");
                     $this_lastlap = $this->makeLengthString($ctdd->lastLap, 7, "left", "cut");
                     $this_lapNo = $this->makeLengthString($ctdd->lapNo, 4, "right");
                     $this_behind = $this->makeLengthString($ctdd->behind == 0 ? "" : $ctdd->behind, 6, "left", "cut");
                     if ($this->raceResult->getIdByName($ctdd->name) == $did) {
                         $contentFlashString .= "_\\N";
                     } else {
                         $contentFlashString .= "{$this_pos} {$this_name} {$this_lastlap} {$this_lapNo} {$this_behind}\\N";
                     }
                     $contentString .= "{$this_pos} {$this_name} {$this_lastlap} {$this_lapNo} {$this_behind}\\N";
                 }
             }
         } else {
             // header
             // Pos Name               LastLap Lap# RaceTime  Behind FastLap Consistency\N
             // 123 123456789012345678 1234567 1234 123456789 123456 1234567 12345678901\N
             $headerString = "Pos Name               LastLap Lap# RaceTime  Behind FastLap Consistency\\N";
             // driver info
             $ctrd = new Timing\CurrTimeRaceData($currTime, $this->raceResult);
             //var_dump($ctrd->currTimeDriverDataArr);
             foreach ($ctrd->currTimeDriverDataArr as $ctdd) {
                 /* @var $ctdd Timing\CurrTimeDriverData */
                 //var_dump($ctdd);
                 if (!empty($ctdd->lapNo)) {
                     $this_did = $this->raceResult->getIdByName($ctdd->name);
                     $this_pos = $this->makeLengthString($ctdd->pos, 3, "right");
                     $this_name = $this->makeLengthString($ctdd->name, 18, "left");
                     $this_lastlap = $this->makeLengthString($ctdd->lastLap, 7, "left", "cut");
                     $this_lapNo = $this->makeLengthString($ctdd->lapNo, 4, "right");
                     // check if current car is finishing its last lap, if not, put some fields with empty string.
                     if ($ctdd->lapNo >= $this->raceResult->driverList[$this_did]->lapData->getLapCount()) {
                         $this_behind = $this->makeLengthString($this->raceResult->driverList[$this_did]->behind, 6, "left", "cut");
                         $this_racetime = $this->makeLengthString($this->raceResult->driverList[$this_did]->totalTime, 9, "right", "cut");
                         $this_fastlap = $this->makeLengthString($this->raceResult->driverList[$this_did]->lapData->getBestlap(true), 7, "left", "cut");
                         $this_consistency = $this->makeLengthString($this->raceResult->driverList[$this_did]->lapData->getConsistency(true), 11, "left", "cut");
                     } else {
                         $this_behind = $this->makeLengthString($ctdd->behind == 0 ? "" : $ctdd->behind, 6, "left", "cut");
                         $this_racetime = $this->makeLengthString("", 9, "right", "cut");
                         $this_fastlap = $this->makeLengthString("", 7, "left", "cut");
                         $this_consistency = $this->makeLengthString("", 11, "left", "cut");
                     }
                     if ($this_did == $did) {
                         $contentFlashString .= "_\\N";
                     } else {
                         $contentFlashString .= "{$this_pos} {$this_name} {$this_lastlap} {$this_lapNo} {$this_racetime} {$this_behind} {$this_fastlap} {$this_consistency}\\N";
                     }
                     $contentString .= "{$this_pos} {$this_name} {$this_lastlap} {$this_lapNo} {$this_racetime} {$this_behind} {$this_fastlap} {$this_consistency}\\N";
                 }
             }
         }
         //var_dump($this->startTime);
         //var_dump($currTime);
         // check next cross line, if within 0.1s, deal with mid time
         if (isset($totalCurrTime[$i + 1])) {
             if ($totalCurrTime[$i + 1]['currTime'] - $currTime < 0.1) {
                 $flashIntervalTime = $totalCurrTime[$i + 1]['currTime'] - $currTime;
             } else {
                 $flashIntervalTime = 0.1;
             }
         }
         $lineStartTime = new TimeStamp($this->startTime + $currTime);
         $lineMidTime = new TimeStamp($this->startTime + $currTime + $flashIntervalTime);
         $lineEndTime = new TimeStamp($this->startTime + (isset($totalCurrTime[$i + 1]) ? $totalCurrTime[$i + 1]['currTime'] : $currTime + 10));
         $retval .= "Dialogue: 0,{$lineStartTime},{$lineMidTime},DefaultVCD,NTP,0,0,0,,{{$this->tags}}{$headerString}{$contentFlashString}\n";
         $retval .= "Dialogue: 0,{$lineMidTime},{$lineEndTime},DefaultVCD,NTP,0,0,0,,{{$this->tags}}{$headerString}{$contentString}\n";
     }
     return $retval;
 }
 function __construct($fileContent)
 {
     $this->raceResult = new Event\RaceResult("");
     $this->fileContent = $fileContent;
     $stage = "start";
     $currRaceDriverData = new Event\RaceDriverData();
     $top3racerCount = 0;
     $currracerId = 0;
     foreach ($this->fileContent as $line) {
         $cleanLine = trim($line);
         if (empty($cleanLine)) {
             if ($stage == "start") {
                 // do nothing
             } else {
                 if ($stage == "restOfRacerContent") {
                     // end of restOfRacerContent
                     $stage = "lapTimeHeader";
                 } else {
                     if ($stage == "lapTimeContent") {
                         $stage = "lapTimeHeader";
                     }
                 }
             }
         } else {
             if ($stage == "start") {
                 // collect race name
                 $this->raceResult->name = $cleanLine;
                 $stage = "win_by";
             } else {
                 if ($stage == "win_by") {
                     $stage = "date";
                 } else {
                     if ($stage == "date") {
                         $stage = "winner";
                     } else {
                         if ($stage == "winner") {
                             $stage = "top3racer_ln0";
                         } else {
                             if ($stage == "top3racer_ln0") {
                                 $top3racerCount++;
                                 $currRaceDriverData->finishPosition = $top3racerCount;
                                 $currRaceDriverData->carNum = strval($top3racerCount);
                                 $currRaceDriverData->name = $cleanLine;
                                 $stage = "top3racer_ln1";
                             } else {
                                 if ($stage == "top3racer_ln1") {
                                     $values = preg_split("/\\s+/u", $cleanLine);
                                     if (count($values) != 4) {
                                         echo "Error, line value doesn't have 4 components:";
                                         var_dump($values);
                                         exit;
                                     }
                                     $currRaceDriverData->bestLap = $values[0];
                                     $currRaceDriverData->totalLaps = $values[1];
                                     $currRaceDriverData->behind = $values[2];
                                     $currRaceDriverData->averageLap = $values[3];
                                     $stage = "top3racer_ln2";
                                 } else {
                                     if ($stage == "top3racer_ln2") {
                                         // both info used only in GKR, useless for me
                                         $this->raceResult->addDriver($currRaceDriverData);
                                         $currRaceDriverData = new Event\RaceDriverData();
                                         if ($top3racerCount < 3) {
                                             $stage = "top3racer_ln0";
                                         } else {
                                             $stage = "restOfRacerHeader";
                                         }
                                     } else {
                                         if ($stage == "restOfRacerHeader") {
                                             // it's fixed (hopefully), I don't care.
                                             $stage = "restOfRacerContent";
                                         } else {
                                             if ($stage == "restOfRacerContent") {
                                                 $values = preg_split("/\t+/u", $cleanLine);
                                                 if (count($values) != 7) {
                                                     echo "Error, line value doesn't have 7 components:";
                                                     var_dump($values);
                                                     exit;
                                                 }
                                                 $currRaceDriverData->carNum = $values[0];
                                                 $currRaceDriverData->finishPosition = intval($values[0]);
                                                 $currRaceDriverData->name = trim($values[1]);
                                                 $currRaceDriverData->bestLap = $values[2];
                                                 $currRaceDriverData->behind = $values[3];
                                                 // careful, this is about gap from leader
                                                 $currRaceDriverData->totalLaps = $values[4];
                                                 $currRaceDriverData->averageLap = $values[5];
                                                 // index=6 is RPM score, don't care
                                                 $this->raceResult->addDriver($currRaceDriverData);
                                                 $currRaceDriverData = new Event\RaceDriverData();
                                             } else {
                                                 if ($stage == "lapTimeHeader") {
                                                     $currRacerName = $cleanLine;
                                                     $currracerId = $this->raceResult->getIdByName($currRacerName);
                                                     if ($currracerId === -1) {
                                                         echo "current racer not found: \"{$currRacerName}\"";
                                                         exit;
                                                     }
                                                     $stage = "lapTimeContent";
                                                 } else {
                                                     if ($stage == "lapTimeContent") {
                                                         $values = preg_split("/\\s+/u", $cleanLine);
                                                         if (count($values) == 3) {
                                                             if ($this->raceResult->driverList[$currracerId]->lapData->isEmpty()) {
                                                                 // fill a dummy first lap based on first lap position, GKR doesn't count "before" first real lap data.
                                                                 $tempPos = str_replace("[", "", str_replace("]", "", $values[2]));
                                                                 $this->raceResult->driverList[$currracerId]->lapData->addLapTime(floatval($tempPos));
                                                             }
                                                             $this->raceResult->driverList[$currracerId]->lapData->addLapTime(floatval($values[1]));
                                                         }
                                                         // otherwise, empty lap data for being lapped
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     //var_dump($this->raceResult);
 }