<?php
/**
* Traverzování kolem stromu
*/

/**
*  Třída pro práci se stromovou strukturou
*/
class Kategorie extends Super{

  protected $id;
  protected $nazev;
  protected $rewrite_link;
  protected $meta_title;
  protected $meta_keywords;
  protected $meta_description;
  protected $leva;
  protected $prava;
  protected $predek;
  protected $hloubka;
  protected $stav;

  protected $getter = array( 'id', 'nazev', 'rewrite_link', 'meta_title', 'meta_keywords', 'meta_description',
    'leva', 'prava', 'predek', 'hloubka', 'stav');
  protected $setter = array( 'nazev', 'rewrite_link', 'meta_title', 'meta_keywords', 'meta_description',
    'leva', 'prava', 'predek', 'hloubka', 'stav');
  public $validate = array(
    'id'		   => array('digits' => 'true'),
		'nazev'        => array('required' => 'true','maxlength' => 150),
		'rewrite_link' => array('required' => 'true','maxlength' => 160),
		'meta_title'	   => array('maxlength' => 250),
  	'meta_keywords'	   => array('maxlength' => 250),
  	'meta_description' => array('maxlength' => 250),
  	'leva'	  => array('digits' => 'true'),
  	'prava'   => array('digits' => 'true'),
  	'predek'  => array('digits' => 'true'),
  	'hloubka' => array('digits' => 'true'),
  	'stav'    => array('required' => 'true', 'range' => '[0,1]')
  );
  public $valAll = array(
		'id'		   => true,
		'nazev'        => true,
		'rewrite_link' => true,
		'meta_title'	   => true,
  	'meta_keywords'	   => true,
  	'meta_description' => true,
  	'leva'	  => true,
  	'prava'   => true,
  	'predek'  => true,
  	'hloubka' => true,
  	'stav'    => true
  );

  public $state_validate = array();

  
/**
* proměnná pro ukládání informací o rodičovské položce
* @access private
* @var string
*/
  public $parent;
  
/**
* Konstruktor
* @param $table
*/ 
  function __construct($id = ''){
    $this->table = 'KATEGORIE';
  	$this->state_validate[0] = $this->valAll;
  	$this->state_validate[1] = $this->valAll; 
    $this->id = $id;
  }

  public function loadById($id, $hash = false, $postRestore = false) {
    $result = dibi::query('SELECT  E.*, S.NAZEV AS S_NAZEV, S.POPIS AS S_POPIS FROM ['.$this->table.'] AS E 
    	INNER JOIN STAV AS S ON S.STAV_ID = E.STAV AND ENTITA = %s
    	WHERE E.ID = %i;', $this->table, $id);

    if (count($result) == 0) {
      throw new Appliexception(1, 'Požadovaný záznam neexistuje', 'seznam', __METHOD__.' Neexistující záznam '.$id );
    }

    $row = $result->fetch()->getArrayCopy();
    $this->setFromRow($row);
    $this->my_stav = '<div title="'.$row['S_POPIS'].'" class="block_state"> '.$row['STAV'].' - '.$row['S_NAZEV'].'</div><br />';

    if ($hash) {
      $this->hash  = $this->getHash();
    } 

    $this->myStates();

    if ($postRestore) {
      $this->setFromPost();
    }
    return $this->toArray();
  }
  
/**
* vrací položku stromu podle URL jako pole
*/
  function loadByURL($url){
    $result = dibi::query('SELECT  E.*, S.NAZEV AS S_NAZEV, S.POPIS AS S_POPIS FROM ['.$this->table.'] AS E
    	INNER JOIN [STAV] S ON S.STAV_ID = E.STAV 
    	WHERE E.REWRITE_LINK = %s AND STAV = 1;', $url);

    if (count($result) == 0) {
      throw new Appliexception(1, 'Požadovaný záznam neexistuje', 'seznam', __METHOD__.' Neexistující záznam '.@$id );
    }

    $row = $result->fetch()->getArrayCopy();
    $this->setFromRow($row);
	}

  public function getAll($separator = '&nbsp;&rarr;&nbsp;') {

    $res = dibi::query('SELECT E.ID, E.NAZEV, E.LEVA, CONCAT(REPEAT("'.$separator.'", E.HLOUBKA - 1),E.NAZEV) AS TEXT,
     	(SELECT COUNT(*) FROM [KAT_PROD] WHERE ID_KAT = E.ID) AS PRODUCT_COUNT, E.REWRITE_LINK, E.STAV, S.NAZEV AS S_NAZEV 
		FROM ['.$this->table.'] AS E
		INNER JOIN `STAV` AS S ON S.STAV_ID = E.STAV AND S.ENTITA = %s
		WHERE LEVA > 1
		ORDER BY LEVA', $this->table);

    return $res->fetchAssoc('ID');
  }
  
  function getToSelect($separator = '', $block_left = '', $block_right = '', $first = true) {

    if (empty($separator)) {
      $separator = '&nbsp;&rarr;&nbsp;';
    }
    
    $query[] = 'SELECT K.ID, K.NAZEV, CONCAT(REPEAT("'.$separator.'", K.HLOUBKA),K.NAZEV) as TXT FROM ['.$this->table.'] K';
  
    if (!empty($block_left) AND !empty($block_right)){
      array_push($query, 'WHERE LEVA < %i OR PRAVA > %i', $block_left, $block_right);
    }
    
    array_push($query, 'ORDER BY leva');
    $result = dibi::query($query);

    if ($first AND (count($result) == 0)) {
      $this->checkFirst();
      return $this->getToSelect('','','',false);
    }
    return $result->fetchAssoc('ID');

  }  

  function checkFirst() {
    $result = dibi::query('SELECT ID FROM ['.$this->table.'] WHERE ID = %i', 1);  // HLAVNÍ KATEGORIE - ID = 1
    if (count($result) == 1) {
      return true;
    }
    elseif (count($result) == 0) {
      return self::insertFirst();
    }
    else {
      return false;
    }
  }
  
/**
* vloží Hlavní položku
* 
* @return mixed false / 1
* 
*/
  private function insertFirst(){
    $values = array(
    	'ID'      => 1,
     	'NAZEV'   => 'Hlavní kategorie',
     	'REWRITE_LINK' => 'Hlavni_kategorie',
    	'LEVA'    => 1,
    	'PRAVA'   => 2,
    	'PREDEK'  => 0,
    	'HLOUBKA' => 0,
    	'STAV'    => 0
    );
    dibi::query('INSERT INTO ['.$this->table.'] ',$values);

    return dibi::insertId();
  }
  
/**
* Počet položek ve stromu (včetně skrytých)
* @return int
*/
  function checkNumOfRows(){
    $result = dibi::query('SELECT COUNT(*) FROM ['.$this->table.']');
    return $result->fetchSingle();
  }
   
/**
* vymaže informace o rodičovské položce
*/
  function clearParent(){
    $this->parent = array();
    return true;
  }

/**
* nastaví info o rodičovské položce do $this->parent
* @param $left
* @return int
*/
  function select_parent($id){
    $this->clearParent();
    $result = dibi::query('SELECT * FROM ['.$this->table.'] WHERE ID = %i', $id);
    if (count($result) == 1) {
      $r = $result->fetchAssoc('ID');
      foreach($r as $item) {
        $this->parent = $item->getArrayCopy();
      }
      return true;
    }
    else {
      return false;
	}
  }

/**
* vrátí url podle názvu
* @param  $name
* @return string
*/ 
  public static function getUrl($name) {

    if (empty($name)) {
      die('FALSE');
    }

    $url = Tools::toURL($name);

    $result = dibi::query('SELECT REWRITE_LINK FROM [KATEGORIE] WHERE REWRITE_LINK LIKE %sql OR REWRITE_LINK LIKE %s 
    	ORDER BY REWRITE_LINK DESC LIMIT 1', '"'.mysql_escape_string($url).'\__"', $url);

    if (count($result) == 0) {
      return $url;
    }
    elseif (count($result) == 1) {
      $db_url = $result->fetchSingle();
      $numb = explode('_', $db_url);

      return $url.'_'.($numb[count($numb)-1] + 1);

    }

  }

/**
* přidá prvek do stromu
* @param $pred  - 0 - END, 1 - HOME
* @return bool
*/
  function addNode($pred = 0) {

    dibi::begin();
    if ($this->select_parent($this->predek) == false) {
	    dibi::rollback();
	    Tools::setMessage('Chyba při načítání nadřazené kategorie');
	    return false;
	}

	if ($pred == 0) {
	  $this->leva = $this->parent['PRAVA'];
	}
	else {
	  $this->leva = $this->parent['LEVA'] + 1;
	}

	$this->prava   = $this->leva + 1;
	$this->hloubka = $this->parent['HLOUBKA'] + 1;
	$this->predek  = $this->parent['ID'];
    $this->rewrite_link = $this->getUrl($this->rewrite_link);

	dibi::query('UPDATE ['.$this->table.'] SET leva = leva + 2 WHERE leva >= %i ORDER BY leva DESC', $this->leva);
	dibi::query('UPDATE ['.$this->table.'] SET prava = prava + 2 WHERE prava >= %i ORDER BY prava DESC', $this->leva);
    $this->insert();
    dibi::commit();

  }

/**
 * Zpracování a uložení změny záznamu
 * @param $id
 * @param $form_id
 */
  public function upravit($id,$form_id) {

    $diff = $this->checkDiff($id,$form_id);  // false, pokud se nic nezměnilo
    if ( $diff != false ) {

      $this->getDiffMess($diff);

    }

    $this->setFromPost();

    if (($_POST['predek_old'] == $_POST['predek']) AND ($_POST['pozice'] == 2)) {
      $this->update();
    }
    else {
      $this->moveTree($id,$this->predek,$_POST['pozice']);
    }
    return true;

  }
  
/**
* přesun části stromu
* @param  $id_moving, $id_parent
* @return bool
*/
  function moveTree($id_moving, $id_parent, $pred = 0){

    $this->select_parent($id_parent);
    $rozdil = $this->prava - $this->leva + 1;

    if ($pred == 1) {
      $leva = $this->parent['LEVA'] + 1;
    }
    else {
      $leva = $this->parent['PRAVA'];
    }
    
    $hloubka = $this->parent['HLOUBKA'] + 1;

    if ($leva > $this->leva) {
      $leva -= $rozdil;
    }
    
    if ($leva != $this->leva) {
      $min_leva  = min($leva, $this->leva);
      $max_prava = max($leva + $rozdil, $this->prava);
      $posun = $leva - $this->leva;
      if ($leva > $this->leva) {
          $rozdil = -$rozdil;
      }
      dibi::begin();
      dibi::query("UPDATE [$this->table]
        SET HLOUBKA = HLOUBKA + IF(@podstrom := LEVA >= $this->leva AND PRAVA <= $this->prava, " . ($hloubka -$this->hloubka) . ", 0),
            LEVA = LEVA + IF(@podstrom, $posun, IF(LEVA >= $min_leva, $rozdil, 0)),
            PRAVA = PRAVA + IF(@podstrom, $posun, IF(PRAVA < $max_prava, $rozdil, 0))
        WHERE PRAVA >= %i AND LEVA < %i"
      , $min_leva, $max_prava );
         
      $this->hloubka = '';
      $this->leva = '';
      $this->prava = '';

      $this->update();
      dibi::commit();

    }
    else {
      Tools::setMessage('Není co přesouvat!');
    }
  }

/**
* přesun uzlu se zachováním rodiče (změna pořadí)
* @param  $id1, $way = 'home'
* @return bool
*/
  public function moveNode( $id1, $way = 0 ){
    
    $this->loadById($id1);
    
    if ($way == 1) {
      $result = dibi::query('SELECT * FROM ['.$this->table.'] WHERE HLOUBKA = %i AND PRAVA = %i', $this->hloubka, $this->leva -1);
    }
    else {
      $result = dibi::query('SELECT * FROM ['.$this->table.'] WHERE HLOUBKA = %i AND LEVA = %i', $this->hloubka, $this->prava +1);
    }
      
    if (count($result) > 0) {
       $r = $result->fetchAll();
       $row = $r[0]->getArrayCopy();
       
       $k1 = abs($row['LEVA'] - $this->leva);
       $k2 = abs($row['PRAVA'] - $this->prava);

       $min_k = min($k1,$k2);
       $max_k = max($k1,$k2);
       $min_leva = min($row['LEVA'], $this->leva);
       $max_leva = max($row['LEVA'], $this->leva);
       $min_prava = min($row['PRAVA'], $this->prava);
       $max_prava = max($row['PRAVA'], $this->prava);
       
       dibi::query("UPDATE [$this->table]
        SET LEVA = LEVA + IF(@podstrom := LEVA >= $min_leva AND PRAVA <= $min_prava, $k2, -$k1),
            PRAVA = PRAVA + IF(@podstrom, $k2, -$k1)
        WHERE LEVA >= %i AND PRAVA <= %i"
      , $min_leva, $max_prava );
      
       return true;

    }
    else {
      Tools::setMessage('Záznam není kam posunout.', '', 1);
      return false;
    }

  }

/**
* vrátí cestu k uzlu
* 
* @param  $node
* @return string
*/ 
  function getWay() { 
    $result = dibi::query('SELECT E.NAZEV, E.REWRITE_LINK FROM KATEGORIE E 
		WHERE LEVA < %i AND PRAVA > %i AND STAV = 1 
    	ORDER BY LEVA', $this->leva, $this->prava);
    $r = $result->fetchAll();

}

/**
* smaže položku stromu, pokud nemá potomky
* 
* @param  $id
* @return bool
*/
	function deleteNode($id){

		dibi::begin();
    $node = $this->loadById($id);
		dibi::query('DELETE FROM ['.$this->table.'] WHERE LEVA >= %i AND PRAVA <= %i ',$node['leva'], $node['prava']);
		$rozdil = $node['prava'] - $node['leva'] + 1;
		dibi::query('UPDATE ['.$this->table.'] SET LEVA = LEVA - %i WHERE LEVA > %i', $rozdil, $node['prava']);
		dibi::query('UPDATE ['.$this->table.'] SET PRAVA = PRAVA - %i WHERE PRAVA > %i',$rozdil, $node['prava']);
		dibi::commit();
    return true;

	}

}
?>