<?php
	class cBackupPage extends cAdminPage
	{  	 
    private $menuItem;
    
    function __construct( $smarty, $db, $action, $post, $get  )
    {
      parent::__construct( $smarty, $db, $action, $post, $get  );
      $this->menuItem = $this->menu->GetItemByLabel("Záloha");
      $this->menuItem->bSelected = true;
      
      $this->randomV = $this->GenerateRandomString(6);
      $_SESSION["oRandomV"] = $_SESSION["nRandomV"];
      $_SESSION["nRandomV"] = $this->randomV;
      $this->smarty->assign("randomV", $this->randomV);
      
      $query = "SELECT * FROM tImportData WHERE bLoadedBkp=1;";
      $result = $this->db->QueryToRow($query);
      if( $this->db->IsError() )
        $this->error = $this->db->GetError();
        
      $this->bLoadedBkp = $result;      
    }
    
    private function RestartSystem( &$error )
    {
      $result = true;
      $queryArray = array("UPDATE tStudents SET year=year+1;",
                          "DELETE c FROM tCourseToUser AS c, tStudents AS s WHERE c.id_user=s.id");
      
      for ( $i = 0; $i < count($queryArray) && $result; $i++ )
        $result = $this->db->Query($queryArray[$i]);
        
      if ( $result )
        return $this->CleanUp($error);

      $error = $this->db->GetError();
      return false;
    }
    
    private function CleanUpTestAnswers( $testID, &$error )
    {
      $result = true;
      $query = "SELECT * FROM tTestAnswer WHERE id_test=".$testID.";";
      $dbTAnswers = $this->db->QueryToArray($query);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }
      
      $query = "DELETE FROM tTestAnswer WHERE id_test=".$testID.";";
      $result = $this->db->Query( $query );
      
      for ( $i = 0; $i < count($dbTAnswers) && $result; $i++ )
      {
        $query = "DELETE FROM tTestAnswerToAnswer WHERE id_testAnswer=".$dbTAnswers[$i]["id"].";"; 
        $result = $this->db->Query( $query );
      } 
      $error = $this->db->GetError();
      return $result; 
    }
    
    private function CleanUpTests( $examID, &$error )
    {
      $result = true;
      $query = "SELECT * FROM tTest WHERE id_exam=".$examID.";";
      $dbTests = $this->db->QueryToArray($query);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }
      
      $query = "DELETE FROM tTest WHERE id_exam=".$examID.";";
      $result = $this->db->Query( $query );
      
      for ( $i = 0; $i < count($dbTests) && $result; $i++ )
      {
        $result = $this->CleanUpTestAnswers($dbTests[$i]["id"], $error);
      } 
      $error = $this->db->GetError();
      return $result; 
    }
    
    private function CleanUpExams( &$error )
    {
      $result = true;
      $fiveYearsAgo = time() - 157680000;
      $query = "SELECT * FROM tExam WHERE date < '".date( "Y-m-d H:i:s", $fiveYearsAgo )."';";
      $dbExams = $this->db->QueryToArray($query);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }
      
      $query = "DELETE FROM tExam WHERE date < '".date( "Y-m-d H:i:s", $fiveYearsAgo )."';";
      $result = $this->db->Query( $query );

      for ( $i = 0; $i < count($dbExams) && $result; $i++ )
      {  
        $query = "DELETE FROM tExamToUser WHERE id_exam=".$dbExams[$i]["id"].";";
        $result = $this->db->Query( $query );
        if ( $result )
          $result = $this->CleanUpTests($dbExams[$i]["id"], $error);
      }
      $error = $this->db->GetError();
      return $result; 
    }
        
    private function CleanUp( &$error )
    {
      $result = true;
      $queryArray = array("DELETE u, s FROM tUser AS u, tStudents AS s WHERE".
                          " u.id=s.id AND (s.bkp=1 OR s.year>8)",
                          "UPDATE tImportData SET bLoadedBkp=0");
      
      for ( $i = 0; $i < count($queryArray) && $result; $i++ )
        $result = $this->db->Query($queryArray[$i]);
        
      if ( $result )
        $this->CleanUpExams( $error );
        
      $error = $this->db->GetError();
      return $result;
    }
    
    private function GetDataFromLine($line)
    {
        $data = array();
        $oldPos = 0;
        $newPos = strpos( $line, "\0" );
        while ( $newPos )
        {
          $data[count($data)] = substr( $line, $oldPos, $newPos-$oldPos );
          $oldPos = $newPos+1;
          $newPos = strpos( $line, "\0", $oldPos );
        }
        $data[count($data)] = substr( $line, $oldPos, strlen($line)-$oldPos-1 );
        return $data;
    }
    
    private function RestoreStudents($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $result = false;
        $data = $this->GetDataFromLine( fgets($bkpfile) );
        
        $query = "SELECT * FROM tUser AS u, tStudents AS s WHERE u.id=s.id AND u.id=".$data[0].";";        
        $result = $this->db->QueryToRow($query);
        $error = $this->db->GetError();
        if ( empty($result) && empty($error) )
        { 
          $query = "INSERT INTO tUser VALUES (".$data[0].",'".$data[1]."','".$data[2]."','".$data[3]."',".
                   "'".$data[4]."','".$data[5]."','".$data[6]."','".$data[7]."',".$data[8].",".$data[9].");";
          
          if( $this->db->Query( $query ) )
          {
            $query = "INSERT INTO tStudents VALUES (".$data[0].",".$data[10].",9,1);";
            $result = $this->db->Query( $query );
          }
          $error = $this->db->GetError();        
        }
        else if ( empty($error) )
        {
          $result = true;
        }         
      }
      return $result;
    }
    
    private function RestoreExamUsers($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $data = $this->GetDataFromLine( fgets($bkpfile) );        
        $query = "INSERT INTO tExamToUser VALUES (".$data[0].",".$data[1].");";
        $result = $this->db->Query( $query );       
      }
      $error = $this->db->GetError();        
      return $result;      
    }

    private function RestoreTestAnswerToAnswer($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $data = $this->GetDataFromLine( fgets($bkpfile) );
        
        $query = "INSERT INTO tTestAnswerToAnswer VALUES (".$data[0].",".$data[1].",".$data[2].",".$data[3].");";
        $result = $this->db->Query( $query );       
      }
      $error = $this->db->GetError();        
      return $result;      
    }    
    
    private function RestoreTestAnswer($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $data = $this->GetDataFromLine( fgets($bkpfile) );
        
        $query = "INSERT INTO tTestAnswer VALUES (".$data[0].",".$data[1].",'".$data[2]."',".$data[3].",".
                 "".$data[4].",".$data[5].",'".$data[6]."','".$data[7]."');";
        $result = $this->db->Query( $query );       
        if( $result )
          $result = $this->RestoreTestAnswerToAnswer($bkpfile, $error);
      }
      $error = $this->db->GetError();        
      return $result;      
    }    
    
    private function RestoreTests($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $data = $this->GetDataFromLine( fgets($bkpfile) );
        
        $query = "INSERT INTO tTest VALUES (".$data[0].",".$data[1].",".$data[2].",".$data[3].",".
                 "'".$data[4]."',".$data[5].",'".$data[6]."',".$data[7].");";
        $result = $this->db->Query( $query );       
        if( $result )
          $result = $this->RestoreTestAnswer($bkpfile, $error);
      }
      $error = $this->db->GetError();        
      return $result;      
    }
    
    private function RestoreExams($bkpfile, &$error)
    {
      $result = true;
      $sCount = fgets($bkpfile);
      
      for ( $i = 0; $i < $sCount && $result; $i++ )
      {
        $data = $this->GetDataFromLine( fgets($bkpfile) );
        
        $query = "SELECT * FROM tExam WHERE id=".$data[0].";";
        $result = $this->db->QueryToArray($query);
        $error = $this->db->GetError();
        
        if ( empty($result) && empty($error) )
        {        
          $query = "INSERT INTO tExam VALUES (".$data[0].",".$data[1].",'".$data[2]."','".$data[3]."','".$data[4]."');";
          $result = $this->db->Query( $query );       
          if( $result )
          {
            $result = ($this->RestoreExamUsers($bkpfile, $error) && 
                       $this->RestoreTests($bkpfile, $error) );
          }
          $error = $this->db->GetError();
        }
        else if ( empty($error) )
        {
          $result = true;
        }      
      }
      $error = $this->db->GetError();        
      return $result;      
    }
    
    private function DoRestore($filename, &$error)
    {
      $result = false;
      $bkpfile = fopen(FPATH."backup/".$filename, "r");
      if ( $bkpfile )
      {
        $result = ($this->RestoreStudents($bkpfile, $error) && 
                   $this->RestoreExams($bkpfile, $error));
      }
      else
        $error = "Súbor '".$filename."' sa nepodarilo otvoriť."; 
        
      if ( $result )
      {
        $query = "UPDATE tImportData SET bLoadedBkp=1;";
        $result = $this->db->Query($query);
        $error = $this->db->GetError();
      }
      
      fclose($bkpfile);
      return $result;
    }
    
    private function BackupPutLine( $bkpfile, $params )
    {
      $lineLen = 0;
      $line = "";
      $count = count($params);
      for ( $i = 0; $i < $count; $i++ )
      {
        $lineLen += strlen($params[$i]) + 1;
        $line .= $params[$i].( $i < $count-1 ? "\0" : "\n" );
      }          
      return fputs($bkpfile, $line, $lineLen);
    }
    
    private function BackupStudents($bkpfile, &$error)
    {
      $query = "SELECT * FROM tStudents WHERE year>=8";
      $students = $this->db->QueryTOArray($query);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }
      
      fputs($bkpfile, count($students)."\n" );
      
      foreach ( $students as $studentRow )
      {
        $query = "SELECT * FROM tUser WHERE id=".$studentRow["id"].";";
        $student = $this->db->QueryToRow($query, MYSQL_NUM);
        if ( $this->db->IsError() )
        {
          $error = $this->db->GetError();
          return false;
        }
        $student[count($student)] = $studentRow["id_specialization"];
        $student[count($student)] = $studentRow["year"];

        if ( !$this->BackupPutLine( $bkpfile, $student ) )
          return false;
      }
      return true;
    }
    
    private function BackupTestAnswerToAnswer($bkpfile, $testAnswerID, &$error)
    {
      $query = "SELECT * FROM tTestAnswerToAnswer WHERE id_testAnswer=".$testAnswerID.";";
      $dbItems = $this->db->QueryToArray($query, MYSQL_NUM);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }

      fputs($bkpfile, count($dbItems)."\n" );
      
      foreach ( $dbItems as $dbItem )
      {
        if ( !$this->BackupPutLine( $bkpfile, $dbItem ) )
          return false;
      }
      return true;      

      fputs($bkpfile, count($dbItems)."\n" );
    }
    
    private function BackupTestAnswer($bkpfile, $testID, &$error)
    {
      $query = "SELECT * FROM tTestAnswer WHERE id_test=".$testID.";";
      $dbTestAnswers = $this->db->QueryToArray($query, MYSQL_NUM);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }

      fputs($bkpfile, count($dbTestAnswers)."\n" );
      
      foreach ( $dbTestAnswers as $dbTestAnswer )
      {
        if ( !($this->BackupPutLine( $bkpfile, $dbTestAnswer ) &&
               $this->BackupTestAnswerToAnswer( $bkpfile, $dbTestAnswer[0], $error ) ) )
          return false;
      }
      return true;      
    }
    
    private function BackupTests($bkpfile, $examID, &$error)
    {
      $query = "SELECT * FROM tTest WHERE id_exam=".$examID.";";
      $dbTests = $this->db->QueryToArray($query, MYSQL_NUM);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }

      fputs($bkpfile, count($dbTests)."\n" );
      
      foreach ( $dbTests as $dbTest )
      {
        if ( !($this->BackupPutLine( $bkpfile, $dbTest ) &&
               $this->BackupTestAnswer( $bkpfile, $dbTest[0], $error ) ) )
          return false;
      }
      return true;
    }
    
    private function BackupExamUsers($bkpfile, $examID, &$error)
    {
      $query = "SELECT * FROM tExamToUser WHERE id_exam=".$examID.";";
      $dbExamUsers = $this->db->QueryToArray($query, MYSQL_NUM);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }
      
      fputs($bkpfile, count($dbExamUsers)."\n" );

      foreach ( $dbExamUsers as $dbExamUser )
      {
        if ( !$this->BackupPutLine( $bkpfile, $dbExamUser ) )
          return false;
      }
      return true;
    }
    
    private function BackupExams($bkpfile, &$error)
    {
      $fiveYearsAgo = time() - 157680000;
      $query = "SELECT * FROM tExam WHERE date < '".date( "Y-m-d H:i:s", $fiveYearsAgo )."';";
      $dbExams = $this->db->QueryToArray($query, MYSQL_NUM);
      if ( $this->db->IsError() )
      {
        $error = $this->db->GetError();
        return false;
      }

      fputs($bkpfile, count($dbExams)."\n" );
      
      foreach ( $dbExams as $dbExam )
      {
        if ( !($this->BackupPutLine( $bkpfile, $dbExam ) &&
               $this->BackupExamUsers( $bkpfile, $dbExam[0], $error ) &&
               $this->BackupTests( $bkpfile, $dbExam[0], $error ) ) )
          return false;
      }
      return true;
    }
    
    /*
    * struktura zalohovaneho suboru:
    *   jednotlive informacie su od seba oddelene '/0'    
    *   pocet studentov, zoznam studentov 
    *       - student (udaje ako v tabulke tUser + id_specialization + year)        
    *
    *   
    */           
    private function DoBackup(&$error)
    {
      $result = false;
      $time = time();
      $bkpfile = fopen(FPATH."backup/".$time.".bkp", "w");
      
      if ( $this->BackupStudents($bkpfile, $error) && $this->BackupExams($bkpfile, $error) )
        $result = true;

      fclose($bkpfile);
      
      if ( !$result )
        unlink(FPATH."backup/".$time.".bkp");
      return $result;             
    }
    
    function Process()
    {
      switch ( $this->action )
      {
        case "do_cleanup":
          if ( $this->postParams["random"] != $_SESSION["oRandomV"] )
            $this->smarty->assign("error", "Nesprávne zadaný overovací reťazec!");
          else if ( $this->RestartSystem($this->error) )
            $this->smarty->assign("actionInfo", "Zahájenie nového ročníka prebehlo úspešne. Staré dáta boli vymazané z databázy.");
        break;
        
        case "do_backup":
          if ( $this->DoBackup($this->error) )
            $this->smarty->assign("actionInfo", "Záloha prebehla úspešne.");
          else if ( empty($this->error) )
            $this->smarty->assign("error", "Chyba pri vytváraní zálohy!");            
        break;
        
        case "load_backup":
          if ( $this->postParams["load"] )
          {
            if ( !$this->bLoadedBkp && $this->DoRestore($this->postParams["fname"], $this->error) )
            {
              $this->bLoadedBkp = true;
              $this->smarty->assign("actionInfo", "Dáta boli úspešne načítané.");
            }
          }
          else if ( $this->postParams["delete"] )
          {
            if ( unlink(FPATH."backup/".$this->postParams["fname"]) )
              $this->smarty->assign("actionInfo", "Záloha bola úspešne vymazaná.");
          }
        break;
        
        case "remove_backup":
          if ( $this->bLoadedBkp && $this->CleanUp($this->error) )
          {
            $this->bLoadedBkp = false;
            $this->smarty->assign("actionInfo", "Záloha bola úspešne odstránená z databázy.");            
          }
        break;          
      }            
      return empty($this->error);
    }
    
    function Draw()
    {
      if ( $this->bLoadedBkp )
      {      
    	 $this->smarty->assign("bLoadedBkp", true);
    	}
    	else
    	{
        $dir = dir(FPATH."backup/");
        $bkpList = array();
        $bkpCount = 0;
        
        while (false !== ($entry = $dir->read()))
        {
          $dotPos = strrpos( $entry, "." );
          $ext = substr( $entry, $dotPos+1 );
          $name = substr( $entry, 0, $dotPos );
          
          if ( $ext == "bkp" )
          {
            $bkpList[$bkpCount]["fname"] = $entry;
            $bkpList[$bkpCount++]["alias"] = date("d-m-Y H:i:s", $name);
          }   
        } 
             
        $this->smarty->assign("bkpCount", $bkpCount);
        $this->smarty->assign("bkpList", $bkpList);    
      }

      $this->smarty->assign("title", "Záloha systému");
      $this->smarty->assign("content", "backupMain.tpl");       
      parent::Draw();
    }
	}
?>
