<?php

              /*** specialni funkce pro vykonani urcitych operaci v db***/
              

/**
 * Otestuje existenci záznamu v databázi a záznam vrátí
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[sequence_id] pro určení větve. $webdoc[version] určuje verzi, pokud není bere se nejnovější   
 * \return array záznam z databáze
 */ 
function database_get_record()
{
  global $webdoc;
  $result=database_query("SELECT r.*, CONCAT(pc.name,' ',pc.surname) AS creator, CONCAT(pa.name,' ',pa.surname) AS approver, c.name AS category, ((SELECT MAX(version) FROM $webdoc[main_table] WHERE sequence_id=$webdoc[sequence_id])=r.version) AS current, rp.parent_id, rpr.name AS parent FROM $webdoc[main_table] r LEFT JOIN person pc ON r.creator_id=pc.person_id LEFT JOIN person pa ON r.approver_id=pa.person_id LEFT JOIN $webdoc[main_table]_category c ON r.category_id=c.category_id LEFT JOIN $webdoc[main_table]_parent rp ON r.sequence_id=rp.sequence_id LEFT JOIN $webdoc[main_table] rpr ON rp.parent_id=rpr.$webdoc[main_table]_id WHERE r.sequence_id=$webdoc[sequence_id]".(isset($webdoc["version"])?" and r.version=$webdoc[version]":"")." ORDER BY r.version DESC LIMIT 1");
  if (database_num_rows($result)!=1) return false; //zaznam existuje v db?
  if (!$record=database_fetch_array($result)) return false; //nacteni zaznamu
  if ($webdoc["main_table"]=="requirement")
  {
    $result=database_query("SELECT *, r.name AS dependence FROM requirement_dependence rd LEFT JOIN requirement r ON rd.dependence_id=r.sequence_id WHERE r.requirement_id IN (SELECT max(requirement_id) FROM requirement GROUP BY sequence_id) AND rd.requirement_id='$record[requirement_id]'");  
    if (($count=database_num_rows($result))===false) return false;
    for ($i=0; $i<$count; $i++)
    {
      $row=database_fetch_array($result);
      $record["dependences_id"][]=$row["dependence_id"];
      $record["dependences"][]=$row["dependence"];
    }
  }
  if ($webdoc["main_table"]=="product")
  {
//    $result=database_query("SELECT requirement_id, name AS requirement FROM requirement WHERE requirement_id IN (SELECT requirement_id FROM requirement_has_product WHERE product_id=$record[product_id])");  
    $result=database_query("SELECT r.requirement_id, r.name AS requirement, rhp.state_id, s.name AS state, rhp.priority_id, p.name AS priority FROM requirement r LEFT JOIN requirement_has_product rhp ON r.requirement_id=rhp.requirement_id LEFT JOIN states s ON rhp.state_id=s.state_id LEFT JOIN priorities p ON rhp.priority_id=p.priority_id  WHERE rhp.product_id=$record[product_id]");
    if (($count=database_num_rows($result))===false) return false;
    for ($i=0; $i<$count; $i++)
    {
      $row=database_fetch_array($result);
      $record["requirements_id"][]=$row["requirement_id"];
      $record["requirements"][]=$row["requirement"];
      $record["states_id"][]=$row["state_id"];
      $record["states"][]=$row["state"];
      $record["priorities_id"][]=$row["priority_id"];
      $record["priorities"][]=$row["priority"];
    }
  }
  return $record;
}

/**
 * Otestuje existenci záznamu kategorie v databázi a záznam vrátí
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[category_id] pro určení záznamu   
 * \return array záznam z databáze
 */ 
function database_get_category()
{
  global $webdoc;
  $result=database_query("SELECT c.*, IF(pa.parent_id IS NULL,'-',pa.name) AS parent, CONCAT(pe.name,' ',pe.surname) AS person FROM $webdoc[main_table] c LEFT JOIN $webdoc[main_table] pa ON c.parent_id=pa.category_id LEFT JOIN person pe on c.person_id=pe.person_id WHERE c.category_id=$webdoc[category_id] LIMIT 1");
  if (database_num_rows($result)==1) //zaznam existuje v db?
  {
    return database_fetch_array($result); //nebyla-li poslana nova data, nacteni do formulare
  }
  return false;
}

/**
 * vrátí historii požadavku, produktu, apod. 
 * \param array &$count počet vrácených záznamů
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[sequence_id] pro určení historické větve
 * \return array historie požadavků, produktů, apod. 
 */ 
function database_get_history(&$count)
{
  global $webdoc;  
  $result=database_query("SELECT *, ((SELECT MAX(version) FROM $webdoc[main_table] WHERE sequence_id='$webdoc[sequence_id]')=version) as current FROM $webdoc[main_table] WHERE sequence_id = '$webdoc[sequence_id]'");
  return database_fetch_result($result,$count);
}

/**
 * vrátí seznam požadavků, produktů, apod.
 * \param int &$count počet vrácených záznamů (na aktuální straně)
 * \param int &$total celkový počet záznamů
 * \param array [$pages] parametry stránky, které upřesňují, které záznamy se mají vypsat
 * \param array [$sort] sloupce, podle kterých se mají záznamy řadit 
 * \param array [$filter] filtr, podle ktereho se omezi dotaz. Na filtru jsou závislé parametry $count a $total
 * \param array [$columns] pole sloupců, na které se dotaz ptá. Určuje také, které tabulky se budou připojovat
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return array seznam požadavků, produktů, apod.
 */ 
function database_get_list(&$count,&$total,$pages=NULL,$sort=NULL,$columns=NULL,$filter=NULL)
{
  /**
   * Převede datum z formulářového pole do sql formátu. Funkce předpokládá korektní datum
   * \param string $date datum z formuláře
   * \return string datum v sql formátu       
   */  
  function sql_date($date)
  {
    $date_parse=date_parse($date);
    $date="$date_parse[year]-";
    $date.=($date_parse["month"]>0?"$date_parse[month]":"0")."-";
    $date.=($date_parse["day"]>0?"$date_parse[day]":"0")." ";
    $date.=($date_parse["hour"]>0?"$date_parse[hour]":"0").":";
    $date.=($date_parse["minute"]>0?"$date_parse[minute]":"0").":";
    $date.=($date_parse["second"]>0?"$date_parse[second]":"0");
    return $date;
  }
  
  global $webdoc;
  $filters=array(); //pole casti sql dotazu pro jednotlive filtry
  //filtrovani podle jmena a popisu (fultext)
  if (isset($filter["name"])) $filters[]="MATCH(m.name) AGAINST ('$filter[name]' IN BOOLEAN MODE)";
  if (isset($filter["description"]) && $webdoc["main_table"]!="test") $filters[]="MATCH(m.description) AGAINST ('$filter[description]' IN BOOLEAN MODE)";
  if (isset($filter["acceptance_criteria"]) && $webdoc["main_table"]=="test") $filters[]="MATCH(m.acceptance_criteria) AGAINST ('$filter[acceptance_criteria]' IN BOOLEAN MODE)";
  if (isset($filter["comments"]) && ($webdoc["main_table"]=="test" || $webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $filters[]="MATCH(m.comments) AGAINST ('$filter[comments]' IN BOOLEAN MODE)";
  if (isset($filter["sw_rev"]) && $webdoc["main_table"]=="test_run") $filters[]="MATCH(m.sw_rev) AGAINST ('$filter[sw_rev]' IN BOOLEAN MODE)";
  if (isset($filter["hw_rev"]) && $webdoc["main_table"]=="test_run") $filters[]="MATCH(m.hw_rev) AGAINST ('$filter[hw_rev]' IN BOOLEAN MODE)";
  if (isset($filter["setup"]) && $webdoc["main_table"]=="test_run") $filters[]="MATCH(m.setup) AGAINST ('$filter[setup]' IN BOOLEAN MODE)";
  if (isset($filter["result"]) && $webdoc["main_table"]=="test_run") $filters[]="MATCH(m.result) AGAINST ('$filter[result]' IN BOOLEAN MODE)";
  if (isset($filter["duration"]) && $webdoc["main_table"]=="test_run") $filters[]="MATCH(m.duration) AGAINST ('$filter[duration]' IN BOOLEAN MODE)";
  //filtrovani podle casovych udaju
  if (is_string($filter["created_from2"])) $filters[]="m.created>='".sql_date($filter["created_from2"])."'";
  if (is_string($filter["created_to2"])) $filters[]="m.created<='".sql_date($filter["created_to2"])."'";
  if (is_string($filter["approved_from2"])) $filters[]="m.approved>='".sql_date($filter["approved_from2"])."'";
  if (is_string($filter["approved_to2"])) $filters[]="m.approved<='".sql_date($filter["approved_to2"])."'";
  if ($webdoc["main_table"]=="test")
  {
    if (is_string($filter["terminate_from2"])) $filters[]="m.terminate>='".sql_date($filter["terminate_from2"])."'";
    if (is_string($filter["terminate_to2"])) $filters[]="m.terminate<='".sql_date($filter["terminate_to2"])."'";
  }
  elseif ($webdoc["main_table"]=="test_run")
  {
    if (is_string($filter["tested_from2"])) $filters[]="m.tested>='".sql_date($filter["tested_from2"])."'";
    if (is_string($filter["tested_to2"])) $filters[]="m.tested<='".sql_date($filter["tested_to2"])."'";
  }
  //filtrovani podle kategorii
  switch ($webdoc["main_table"])
  {
    case "requirement":
      $table_columns=array("m2.sequence_id","pc.person_id","pa.person_id","c.category_id","d.dependence_id"); //pole názvů sloupců, na které se vztahuje omezení v podmínce where.
      $names=array("parents_id","creators_id","approvers_id","categories_id","dependences_id"); //pole názvů proměnných u polí id hodnot. Pozice v poli $table_columns musí odpovídat pozici v poli $namess
    break;
    case "product":
      $table_columns=array("m2.sequence_id","pc.person_id","pa.person_id","c.category_id"); //pole názvů sloupců, na které se vztahuje omezení v podmínce where.
      $names=array("parents_id","creators_id","approvers_id","categories_id"); //pole názvů proměnných u polí id hodnot. Pozice v poli $table_columns musí odpovídat pozici v poli $namess
    break;
    case "test":
      $table_columns=array("pc.person_id","pa.person_id","pt.person_id"); //pole názvů sloupců, na které se vztahuje omezení v podmínce where.
      $names=array("creators_id","approvers_id","terminators_id"); //pole názvů proměnných u polí id hodnot. Pozice v poli $table_columns musí odpovídat pozici v poli $namess
    break;
    case "test_run":
      $table_columns=array("pc.person_id","pa.person_id","pts.person_id"); //pole názvů sloupců, na které se vztahuje omezení v podmínce where.
      $names=array("creators_id","approvers_id","testers_id"); //pole názvů proměnných u polí id hodnot. Pozice v poli $table_columns musí odpovídat pozici v poli $namess
    break;
  }
  foreach ($names as $name_key => $name) // $name - aktualni jmeno pole. je to klic pro pole $filter, napr. $filter[$name] muze byt $filter["categories_id"], $name_key - klic odpovidajic promenne $name
  {
    if (!isset($filter[$name])) continue; //filtr s aktualni hodnotou name neexistuje (nebyl zadan)
    $array_id=array_unique($filter[$name]); //pole id hodnot. Odstraneni duplicitnich prvku, aby nebyl dotaz zbytecne dlouhy
    foreach ($array_id as $key => $id) //zadani pres jednotlive id
    {
      if ($id>=-1)
      {
        if (isset($values)) $values.=" OR ";
        if ($id==-1) $values.="$table_columns[$name_key] IS NULL"; 
        else $values.="$table_columns[$name_key]='$id'"; //$table_columns[$name_key] muze byt napr. c.category_id
      }
    }
    $filters[]="($values)";
    unset($values);
  }
  //filtrovani podle bool promennych (pouze u requirements)
  if ($webdoc["main_table"]=="requirement")
  {
    if (isset($filter["active"])) $filters[]="m.active=".($filter["active"]==2?"1":"0");
    if (isset($filter["is_product_specific"])) $filters[]="m.is_product_specific ".($filter["is_product_specific"]==2?"IS NOT NULL":"IS NULL");
  }

  $i=0;
  foreach ($filters as $key => $filter_sql) //sestaveni jednotlivych casti dotazu filtru do jednoho retezce
  {
    if ($i>0) $filter_all.=" AND ";
    $filter_all.=$filter_sql;
    $i++;
  }
  if ($i>0) $filter_all=" AND ($filter_all)";

  //sestaveni dvou datazu: pro vypis zaznamu dle filtru a stranky ($query_main) a pro vypis celkoveho poctu zaznamu dle filtru ($query_total)
  //$query_part je spolecna cast obou dotazu (cast FROM, WHERE a GROUP BY)  
  if (!$sort) $sort=array(); 
  $query_part=" FROM $webdoc[main_table] m"; //hlavni tabulka
  if ((isset($columns["parent"]) || isset($filter["parents_id"]) || in_array("parent",$sort) || in_array("parent desc",$sort)) && ($webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $query_part.=" LEFT JOIN $webdoc[main_table]_parent p ON m.sequence_id=p.sequence_id LEFT JOIN $webdoc[main_table] m2 ON p.parent_id=m2.$webdoc[main_table]_id"; //propojeni s tabulkou rodicu a nasledne se zakladni tabulkou (pro ziskani sequence_id rodicu). pouze pri filtrovani podle rodicu
  if ((isset($columns["category"]) || isset($filter["categories_id"]) || in_array("category",$sort) ||  in_array("category desc",$sort)) && ($webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $query_part.=" LEFT JOIN $webdoc[main_table]_category c ON m.category_id=c.category_id"; //propojeni s tabulkou kategorii (pouze u requirements a produtcts)
  if (isset($columns["creator"]) || isset($filter["creators_id"]) || in_array("creator",$sort) || in_array("creator desc",$sort)) $query_part.=" LEFT JOIN person pc ON m.creator_id=pc.person_id"; //propojeni s tabulkou person pro zobrazeni autora zaznamu
  if (isset($columns["approver"]) || isset($filter["approvers_id"]) || in_array("approver",$sort) || in_array("approver desc",$sort)) $query_part.=" LEFT JOIN person pa ON m.approver_id=pa.person_id"; //propojeni s tabukou person pro zobrazeni jmena schvaluvatele zaznamu
  if ((isset($columns["terminator"]) || isset($filter["terminators_id"]) || in_array("terminator",$sort) || in_array("terminator desc",$sort)) && $webdoc["main_table"]=="test") $query_part.=" LEFT JOIN person pt ON m.terminator_id=pt.person_id"; //propojeni s tabukou person pro zobrazeni jmena ukoncovatele zaznamu
  if ((isset($columns["tester"]) || isset($filter["testers_id"]) || in_array("tester",$sort) || in_array("tester desc",$sort)) && $webdoc["main_table"]=="test_run") $query_part.=" LEFT JOIN person pts ON m.tester_id=pts.person_id"; //propojeni s tabukou person pro zobrazeni jmena ukoncovatele zaznamu
  if (isset($filter["dependences_id"]) && $webdoc["main_table"]=="requirement") $query_part.=" LEFT JOIN requirement_dependence d ON m.requirement_id=d.requirement_id"; //propojeni s tabulkou zavislosti (pouze cast requirement). Pouze pro filtrovani podle zavisloti
  
  $query_part.=" WHERE 1 ";
  if (isset($_GET["subpage2"]) && ($_GET["subpage2"]=="history" || ($_GET["subpage2"]=="export" && $webdoc["main_table"]!="test_run" && $_GET["export"]=="history_to_xls"))) $query_part.=" AND m.sequence_id = '$webdoc[sequence_id]'"; //vypis historie -  omezeni na jedno sequence_id
  elseif ($webdoc["main_table"]!="test_run") $query_part.=" AND m.$webdoc[main_table]_id IN (SELECT MAX($webdoc[main_table]_id) FROM $webdoc[main_table] GROUP BY sequence_id)"; //vypis aktualnich (v historii) zaznamu, neplati pro test_run
  if (!isset($_GET["subpage2"]) || $_GET["subpage2"]=="export") //filtr jen pro list.php 
  {
    $query_part.=$filter_all; //pripojeni filtru
    $query_part.=" GROUP BY m.$webdoc[main_table]_id"; //seskupeni
  }
  
  //hlavni dotaz pro vypis zaznamu dle filtru a stranky (cast SELECT - cteni nastavenych sloupcu a cast LIMIT)
  $query_main="SELECT m.name, m.$webdoc[main_table]_id"; //zobrazeni nazvu a id zaznamu
  if ($webdoc["main_table"]!="test_run") $query_main.=", m.sequence_id"; //zobrazeni sequence_id zaznamu
  if (isset($_GET["subpage2"]) && ($_GET["subpage2"]=="history" || ($_GET["subpage2"]=="export" && $webdoc["main_table"]!="test_run" && $_GET["export"]=="history_to_xls"))) $query_main.=", m.version, ((SELECT MAX(version) FROM $webdoc[main_table] WHERE sequence_id='$webdoc[sequence_id]')=m.version) AS current"; //zobrazeni verze (v url) a rozliseni aktualniho zaznamu od ostatnich
  if ((isset($columns["category"]) ||  in_array("category",$sort) ||  in_array("category desc",$sort)) && ($webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $query_main.=", c.name as category"; //zobrazeni jmena kategorie (pouze u requirements a produtcts)
  if ((isset($columns["parent"]) ||  in_array("parent",$sort) ||  in_array("parent desc",$sort)) && ($webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $query_main.=", m2.name AS parent"; //zobrazeni jmena rodice
  if (isset($columns["created"])) $query_main.=", m.created"; //zobrazeni casu vytvoreni zaznamu
  if (isset($columns["creator"]) || in_array("creator",$sort) || in_array("creator desc",$sort)) $query_main.=", CONCAT(pc.name,' ',pc.surname) AS creator"; //zobrazeni creatora (jmeno a prijmeni)
  if (isset($columns["approved"])) $query_main.=", m.approved"; //zobrazeni casu schvaleni zaznamu
  if (isset($columns["approver"]) || in_array("approver",$sort) || in_array("approver desc",$sort)) $query_main.=", CONCAT(pa.name,' ',pa.surname) AS approver"; //zobrazeni approvera (jmeno a prijmeni)
  if (isset($columns["tested"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.tested"; //zobrazeni casu testovani zaznamu
  if ((isset($columns["tester"]) || in_array("tester",$sort) || in_array("tester desc",$sort)) && $webdoc["main_table"]=="test_run") $query_main.=", CONCAT(pts.name,' ',pts.surname) AS tester"; //zobrazeni testera (jmeno a prijmeni)
  if (isset($columns["sw_rev"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.sw_rev"; //zobrazeni sw_rev
  if (isset($columns["hw_rev"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.hw_rev"; //zobrazeni hw_rev
  if (isset($columns["setup"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.setup"; //zobrazeni setup
  if (isset($columns["result"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.result"; //zobrazeni result
  if (isset($columns["duration"]) && $webdoc["main_table"]=="test_run") $query_main.=", m.duration"; //zobrazeni duration
  if (isset($columns["active"]) && $webdoc["main_table"]=="requirement") $query_main.=", IF(m.active=1,'Yes','No') AS active"; //zobrazeni, zda je zaznam aktivni
  if (isset($columns["description"]) && ($webdoc["main_table"]!="test")) $query_main.=", m.description"; //zobrazeni popisu
  if (isset($columns["acceptance_criteria"]) && $webdoc["main_table"]=="test") $query_main.=", m.acceptance_criteria"; //zobrazeni acceptance_criteria
  if (isset($columns["comments"]) && ($webdoc["main_table"]=="test" || $webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $query_main.=", m.comments"; //zobrazeni komentaru
  if (isset($columns["is_product_specific"]) && $webdoc["main_table"]=="requirement") $query_main.=", IF(m.is_product_specific IS NOT NULL,'Yes','No') AS is_product_specific"; //zobrazeni, zda je zaznam na miru produtku
  if (isset($columns["terminate"]) && $webdoc["main_table"]=="test") $query_main.=", m.terminate"; //zobrazeni casu ukonceni zaznamu
  if ((isset($columns["terminator"]) || in_array("terminator",$sort) || in_array("terminator desc",$sort)) && $webdoc["main_table"]=="test") $query_main.=", CONCAT(pt.name,' ',pt.surname) AS terminator"; //zobrazeni terminatora (jmeno a prijmeni)
  $query_main.=$query_part;
  if (count($sort)>0)
  {
    foreach ($sort as $key => $name)
    {
      if (isset($order)) $order.=", ";
      $order.=$name;
    }
    $query_main.=" ORDER BY $order";
  } 
  if (isset($pages)) $query_main.=" LIMIT $pages[from], $pages[records]";
    
  //dotaz pro zjisteni celkoveho poctu zaznamu dle filtru (nezavisle na strance)
  $query_total="SELECT COUNT(*) AS total FROM (SELECT 1$query_part) AS tab";
  $result=database_query($query_total);
  extract(database_fetch_array($result)); //vrati pocet vsech zaznamu do promenne $total
  $result=database_query($query_main);
  return database_fetch_result($result,$count);
}

function database_get_select($table,$records=NULL)
{
  global $webdoc;
  // ulozeni zavislosti u requirements
  if (is_array($records))
  {
    //kopie zavislosti, aby z nich bylo mozne odmazat prazdne prvky a zaroven se po odmazani zobrazil formular ve stejnem stavu\
    $records=array_unique($records); //odstraneni duplicitnich prvku, aby se do db neukladal stejny radek vicekrat
    foreach ($records as $key => $id) //zadani jednotlivych id zaznamu do dotazu
    {
      if ($id<0 || $id=="") unset($records[$key]); //odstraneni neplatnych id (nebyl vybran v selectu zazny zaznam)
      else $where.="OR m.$table"."_id=$id ";
    }
  }
  switch ($table)
  {
    case "requirement": $result=database_query("SELECT m.name, m.$table"."_id, m.sequence_id, ((SELECT MAX(version) FROM $table WHERE sequence_id=m.sequence_id)>m.version) AS old FROM $table m WHERE m.$table"."_id IN (SELECT MAX($table"."_id) FROM $table GROUP BY sequence_id) $where ORDER BY sequence_id, requirement_id"); break;
    case "states": case "priorities": $result=database_query("SELECT * FROM $table"); break;
    default: return false;
  }
  return database_fetch_result($result,$count);
}

/**
 * Vrátí textový výpis filtru
 * \param array $filter proměnné filtru
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky
 */
function database_get_filter($filter)
{
  /**
   * Vrátí textový výpis jednoho parametru filtru, je-li typu array
   * \param array $filter proměnné filtru
   * \param string $name název proměnné filtru   
   * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky
   */  
  function get_array($filter,$name)
  {
    global $webdoc;
    foreach ($filter[$name] as $key => $id) //průchod id hodnotami
    {
      if ($id==-1) //root hodnoty
      {
        switch ($name)
        {
          case "categories_id": $text_root="--[ROOT]--"; break;
          case "parents_id": $text_root="--[NO PARENT]--"; break;
          case "approvers_id": $text_root="--[NO APPROVER]--"; break;
          case "testers_id": $text_root="--[NO TESTER]--"; break;
          case "terminators_id": $text_root="--[NO TERMINATOR]--"; break;
          case "dependences_id": $text_root="--[INDEPENDENT]--"; break;
        }
        continue;
      }
      if (isset($where)) $where.=" OR ";
      switch ($name)
      {
        case "categories_id": $where.="category_id='$id'"; break;
        case "parents_id": case "dependences_id": $where.="sequence_id='$id'"; break;
        case "creators_id": case "approvers_id": case "testers_id": case "terminators_id": $where.="person_id='$id'"; break;
      }
    }

    if (isset($where)) //vytvoreni dotazu
    {
      switch ($name)
      {
        case "categories_id": $result=database_query("SELECT name FROM $webdoc[main_table]_category WHERE $where"); break;
        case "parents_id": case "dependences_id": $result=database_query("SELECT name FROM $webdoc[main_table] WHERE $webdoc[main_table]_id IN (SELECT MAX( $webdoc[main_table]_id ) FROM $webdoc[main_table] GROUP BY sequence_id) AND (($where)) GROUP BY $webdoc[main_table]_id"); break;
        case "creators_id": case "approvers_id": case "testers_id": case "terminators_id": $result=database_query("SELECT CONCAT(name,' ',surname) AS name FROM person WHERE $where"); break;
      }
          
      while (list($name)=database_fetch_array($result))
      {
        if (isset($text)) $text.=", ";
        $text.="$name";
      }
    }
    if (isset($text_root) && isset($text)) $text_root.=", ";
    return $text_root.$text;
  }
  
  global $webdoc;

  if (!isset($filter)) return;
  if (isset($filter["name"])) $filter_text[]="Name: $filter[name]";
  if (isset($filter["categories_id"]) && ($webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $filter_text[]="Categories: ".get_array($filter,"categories_id");
  if (isset($filter["parents_id"])) $filter_text[]="Parents: ".get_array($filter,"parents_id");
  if (isset($filter["created_from"]) || isset($filter["created_to"]))
  {
    $text="Created";
    if (isset($filter["created_from"])) $text.=" from: $filter[created_from]";
    if (isset($filter["created_from"]) && isset($filter["created_to"])) $text.=",";
    if (isset($filter["created_to"])) $text.=" to: $filter[created_to]";
    $filter_text[]=$text;
  }
  if (isset($filter["creators_id"])) $filter_text[]="Creators: ".get_array($filter,"creators_id");
  if (isset($filter["approved_from"]) || isset($filter["approved_to"]))
  {
    $text="Approved";
    if (isset($filter["approved_from"])) $text.=" from: $filter[approved_from]";
    if (isset($filter["approved_from"]) && isset($filter["approved_to"])) $text.=",";
    if (isset($filter["approved_to"])) $text.=" to: $filter[approved_to]";
    $filter_text[]=$text;
  }  
  if (isset($filter["approvers_id"])) $filter_text[]="Approvers: ".get_array($filter,"approvers_id");
  if ((isset($filter["tested_from"]) || isset($filter["tested_to"])) && $webdoc["main_table"]=="test_run")
  {
    $text="Tested";
    if (isset($filter["tested_from"])) $text.=" from: $filter[tested_from]";
    if (isset($filter["tested_from"]) && isset($filter["tested_to"])) $text.=",";
    if (isset($filter["tested_to"])) $text.=" to: $filter[tested_to]";
    $filter_text[]=$text;
  }
  if (isset($filter["testers_id"]) && $webdoc["main_table"]=="test_run") $filter_text[]="Testers: ".get_array($filter,"testers_id");
  if (isset($filter["sw_rev"]) && $webdoc["main_table"]=="test_run") $filter_text[]="SW Rev: $filter[sw_rev]";
  if (isset($filter["hw_rev"]) && $webdoc["main_table"]=="test_run") $filter_text[]="HW Rev: $filter[hw_rev]";
  if (isset($filter["setup"]) && $webdoc["main_table"]=="test_run") $filter_text[]="Setup: $filter[setup]";
  if (isset($filter["result"]) && $webdoc["main_table"]=="test_run") $filter_text[]="Result: $filter[result]";
  if (isset($filter["duration"]) && $webdoc["main_table"]=="test_run") $filter_text[]="Duration: $filter[duration]";
  if (isset($filter["active"]) && $webdoc["main_table"]=="requirement")
  {
    if ($filter["active"]==2) $filter_text[]="Active: active";
    else $filter_text[]="Active: not active";
  }
  if (isset($filter["description"]) && $webdoc["main_table"]!="test") $filter_text[]="Description: $filter[description]";
  if (isset($filter["acceptance_criteria"]) && $webdoc["main_table"]=="test") $filter_text[]="Acceptance criteria: $filter[acceptance_criteria]";
  if (isset($filter["comments"]) && ($webdoc["main_table"]=="test" || $webdoc["main_table"]=="requirement" || $webdoc["main_table"]=="product")) $filter_text[]="Comments: $filter[comments]";
  if ((isset($filter["terminate_from"]) || isset($filter["terminate_to"])) && $webdoc["main_table"]=="test")
  {
    $text="Terminated";
    if (isset($filter["terminate_from"])) $text.=" from: $filter[terminate_from]";
    if (isset($filter["terminate_from"]) && isset($filter["terminate_to"])) $text.=",";
    if (isset($filter["terminate_to"])) $text.=" to: $filter[terminate_to]";
    $filter_text[]=$text;
  }
  if (isset($filter["terminators_id"]) && $webdoc["main_table"]=="test") $filter_text[]="Terminators: ".get_array($filter,"terminators_id");  
  if (isset($filter["dependences_id"]) && $webdoc["main_table"]=="requirement") $filter_text[]="Dependences: ".get_array($filter,"dependences_id");
  if (isset($filter["is_product_specific"]) && $webdoc["main_table"]=="requirement")
  {
    if ($filter["is_product_specific"]==2) $filter_text[]="Is product specific: specific";
    else $filter_text[]="Is product specific: not specific";
  }

  return $filter_text;
}

/**
 * vrátí seznam uživatelů
 * \param int &$count bude nastaveno na počet vrácených uživatelů
 */
function database_get_person_list(&$count)
{
  $result=database_query("SELECT * FROM person ORDER BY person_id");
  return database_fetch_result($result,$count);
}

/**
 * vrátí seznam kategorií. existuje-li $webdoc["category_id"], je vrácen seznam bez tohoto záznamu
 * \param int &$count počet vrácených záznamů
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return array seznam kategorií
 */ 
function database_get_categories_list(&$count,&$total,$pages=NULL,$sort=NULL)
{
  global $webdoc;

  $query_total="SELECT COUNT(*) AS total FROM $webdoc[main_table]";
  $result=database_query($query_total);
  extract(database_fetch_array($result)); //vrati pocet vsech zaznamu do promenne $total

  $query_main="SELECT c.*, cp.name AS parent, CONCAT(p.name,' ',p.surname) AS person FROM $webdoc[main_table] c LEFT JOIN person p ON c.person_id=p.person_id LEFT JOIN $webdoc[main_table] cp ON c.parent_id=cp.category_id";
  if (isset($sort))
  {
    foreach ($sort as $key => $name)
    {
      if (isset($order)) $order.=", ";
      $order.=$name;
    }
    $query_main.=" ORDER BY $order";
  } 
  if (isset($pages)) $query_main.=" LIMIT $pages[from], $pages[records]";
  $result=database_query($query_main);
  return database_fetch_result($result,$count);
}

/**
 * zjistí zda kategorie existuje
 * \param int $category_id category_id kategorie
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky   
 * \return bool true, pokud kategorie existuje, false, pokud neexistuje   
 */
function database_test_existing_category($category_id)
{
  global $webdoc;
  $result=database_query("SELECT category_id FROM $webdoc[main_table]_category WHERE category_id=$category_id LIMIT 1");
  return (database_num_rows($result)==1); //zaznam existuje v db?
}

/**
 * zjistí zda záznamy existuji (testuje se id záznamů)
 * \param array $records_id záznamu
 * \param bool [$self] pokud je true, zde v $records_id obsahuje aktuální $webdoc[sequence_id]. V takovém případě funkce vrátí false, jinak true. Výchozí hodnota $self je false (netestuje se) 
 * \return bool true, pokud všechny záznamy existují, false, pokud alespoň jeden záznam neexistuje   
 */
function database_test_existing_records($records_id,$table,$self=false)
{
  global $webdoc;
  
  switch ($table)
  {
    case "states": $name_id="state_id"; break;
    case "priorities": $name_id="priority_id"; break;
    case "parent": $name_id="sequence_id"; $table="$webdoc[main_table]_parent"; break; //v teto variante jsou ve skutecnosti v $records_id hodnoty sequence_id 
    default: $name_id=$table."_id";
  }
  if (count($records_id)==0) return true; //neni zadny zaznam, neni co testovat
  if (!is_array($records_id)) return false; //musi byt pole
  $records_id=array_unique($records_id); //odstraneni duplikatnich id
  if ($self && in_array($webdoc["sequence_id"],$records_id)) return false; //testovani, zda se v $sequences_id vyskytuje aktualni $webdoc["sequence_id"]. V takovem pripade by zaznam byl zavisly sam na sobe, funkce vrati false
  foreach ($records_id as $key => $id) //zadani jednotlivych id zaznamu do dotazu
  {
    if ($id<0 || $id=="") return false; //odstraneni neplatnych id (nebyl vybran v selectu zazny zaznam)
    else //pridani do dotazu
    {
      if (isset($where)) $where.=" OR "; 
      $where.="$name_id=$id";
    }
  }
  $result=database_query("SELECT $name_id FROM $table WHERE $where");
  return (database_num_rows($result)==count($records_id)); //pokud dotaz vrati stejny pocet zaznamu jako je pocet prvku pole $records_id, existuji vsechny zaznamy a vrati true. jinak false
}


/**
 * zjistí, zda záznam může odkazovat na rodiče. Konrola stavu (při ukládání), kdy rodič záznamu by měl být jeho potomek, což nelze
 * \param int [$category_id] záznam, na který odkazuje ukládaný záznam (parent_id) 
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[category_id] pro určení záznamu
 * \return bool true, pokud záznam může odkazovat na rodiče, false, pokud na rodiče odkazovat nemůže 
 */
function database_test_category($category_id=NULL)
{
  global $webdoc;
  if (!isset($category_id)) return true; //ukládaný záznam neodkazuje na rodiče, není třeba testovat
  if ($category_id==$webdoc["category_id"]) return false; //ukládaný záznam ukazuje sám na sebe, což nesmí nastat 
  //ukládaný záznam má rodiče  
  $list=database_get_categories_list($count,$total); //načtení všech záznamů do pole
  do //opakokované hledání, dokud se není nalezen kořen stromu (ukončeno příkazem return) nebo dokud není nalezen rodičovský záznam (tj. parent_id ukazuje na neexistující záznam)
  {
    $found=false; //identifikátor nalezení rodiče
    foreach ($list as $key => $row) //průchod polem záznamů
    {
      if ($row["category_id"]==$category_id) //nalezen rodičovský záznam
      {
        if ($row["category_id"]==$row["parent_id"]) return false; //záznam ukazuje na sebe, nemělo by nastat 
        if (!isset($row["parent_id"])) return true; //záznam nemá parent_id, je tedy na kořeni stromu a hledání se ukončí. Záznamy na sebe neukazují navzájem
        if ($row["parent_id"]==$webdoc["category_id"]) return false; //záznam ukazuje na ukládání záznam. To nemůže nastat, došlo by ke smyčce
        $found=true; //záznam má parent_id. Hledání pokračuje, dokud se nedojde ke kořeni stromu 
        $category_id=$row["parent_id"];//hledání dalšího rodičovského záznamu (o úroveň výš)
      }
    }
  } while ($found);//hledání pokračuje, dokud není nalezen konec stromu, případně dokud není splněna některé z podmínek pro return
  return false; //nebyl nalezen rodič - chyba v db
}

/**
 * setřídí kategorie do stromové struktury
 * \param int &$count počet kategorií ve stromu
 * \param string $table uruje tabulku requirement_category nebo product_category 
 * \param int [$without_id] category_id kategorie, která nebude zařazena ve stromu, včetně potomků. Nebude tak možné zadat rodiče sama sebe nebo svého potomka
 * \param array [$start] umoznuje nastavit vlastni volby na začátek stromu 
 * \return array kategorie seřazené do stromové struktury vhodné pro zobrazní funkcí html_options ve smarty. Klíč je category_id, hodnota je jméno kategorie      
 */
function database_get_categories_tree(&$count,$table,$without_id=NULL,$start=array(NULL=>"- - -"))
{
  /**
   * vloží záznam $row1 do setříděného seznamu $list2 přiřazením správné hodnoty klíče
   * \param array &$list2 pole již setříděných záznamů
   * \param array $row1 záznam čekající na zatřídění
   * \return bool true, pokud byl záznam zařezen. False, pokud nebyl zařezen, což se stane v případě, že některý z nadřazených záznamů ještě není v setříděném seznamu    
   */ 
  function put_row(&$list2,$row1)
  {
    //$parent_key je klíč rodiče, max_key je klíč následujícího záznamu (může být na jiné úrovni a pokud je rodič poslední záznam, tak nebude existovat), $new_key je nové vypočítaná hodnota klíče z $parent_key a $next_key
    ksort($list2); //setřídění záznamů
    //průchod setříděným polem záznamů. hledá se rodič s odpovídajícím category_id
    foreach ($list2 as $key => $row2)
    {
      if (isset($parent_key)) //v předchozím průchodu byl nalezen rodič (v další podmínce if)
      { 
        $next_key=$key; //uložení klíče sousedního záznamu za rodičem (nový záznam se vloží mezi ně)
        break; //ukončení cyklu
      }
      if ($row1["parent_id"]==$row2["category_id"]) //rodičovský záznam nalezen
      {
        $parent_key=$key; //uloží se jeho hodnota klíče
        $parent_level=$row2["level"]; //a úroveň
      }
    }
    if (isset($parent_key)) //byl nalezen rodič
    {
      if (!isset($next_key)) $next_key=$parent_key+1; //pokud rodič neměl následovníka (byl na konci)
      $new_key=($next_key-$parent_key)/2+$parent_key; //výpočet klíče vkládaného záznamu
      $row1["level"]=$parent_level+1; //úroveň o jedno vnoření
      for ($i=0; $i<$row1["level"]; $i++) $row1["name"]="&nbsp;&nbsp;&nbsp;".$row1["name"]; //odsazení
      $list2["$new_key"]=$row1; //vložení do záznamu mezi rodiče a jeho následovníka
      return true;
    }
    return false;
  }

  $result=database_query("SELECT category_id,parent_id,name FROM $table".(isset($without_id)?" WHERE category_id<>$without_id":"")); //vrátí seznam kategorií bez záznamu s hodnotou $without_id
  $list=database_fetch_result($result,$count);
  if ($count==0) return $start; //pokud je seznam prázdný vrátí se pouze prvek stromu pro výběr bez rodiče
  //odstranění těch záznamů, které jsou potomkem editovaného záznamu nebo těch záznamů, jejihž parent_id ukazuje na neexistujícího rodiče (v případě chybných dat - teoretická možnost), aby nedošlo k zacyklení
  do //opakované odstraňování záznamů. Cyklus se ukončí, pokud v posledním průchodu k žádnému odstranění nedošlo
  {
    $deleted=false; //identifikátor odstranění záznamu
    foreach ($list as $key => $row) //průchod hodnotami parent_id v poli
    {
      if (!isset($row["parent_id"])) continue; //záznam je na počátku stromu (nemá rodiče), nebude odstraněn. Pokračuje se dalším záznamem
      foreach ($list as $key2 => $row2) //záznam má rodiče, který se v dalším cyklud foreach vyhledá. Pokud rodič existuje, záznam nebude odstraněn. 
      {
        if ($row["parent_id"]==$row2["category_id"]) continue 2;//rodič byl nalezen
      }
      unset($list[$key]);//odstranění záznamu
      $deleted=true;
      $count--; //snížení počtu záznamů
    }
  } while ($deleted); //ukončení cyklu, nedošlo-li k ostranění
  
  $list2=Array(); //seřazené pole podle vnořených kategorií (zatím prázdné)
  $i=0;//nový klíč pro pole $list2. U záznamů v kořeni stromu (úroveň 0) je to celé číslo. U vkládaných záznamů pomocí funkce put_row je to desetinné číslo v datovém typu string vypočítané tak, aby po setřídění byl záznam na správné pozici 
  while (count($list)>0) //opakované vkládání, dokud se nevyprázní $list a nenaplní $list2
  {
    foreach ($list as $key => $row) //průchod polem $list
    {
      if (!isset($row["parent_id"])) //kategorie nemá rodiče
      {
        $list2["$i"]=$row; //vložení na konec stromu
        unset($list[$key]); //vymazání z původního seznamu
        $list2["$i"]["level"]=0; //nultá úroveň
        $i++;
      }
      else //kategorie má rodiče
      {
        //vyhledání rodiče a vložení záznamu na správné místo ve stromu. Pokud rodič ještě ve stromu není, nedeojde ke vložení a funkce vrátí false. Ke vložení dojde až po vložení všech nadřazených záznamů v dalších průchodech cyklu while.
        if (put_row($list2,$row)) unset($list[$key]); //byl-li záznam vložen do stromu, smaže se z původního seznamu
      }
    }
  }
  
  ksort($list2); //setřídění pole podle klíčů
  $tree=$start; //pole pro setříděný strom. první prvek bude prázdný pro možnost bez rodiče
  //vložení stromu do vhodného pole pro vygenerování pole select ve smarty. Klíč je category_id, hodnota je jméno kategorie (odsazené podle úrovně).
  foreach ($list2 as $key => $row)
  {
    $tree[$row["category_id"]]=$row["name"];
  }
  return $tree;
}

/**
 * uloží záznam a vrátí jeho record_id (requirement_id, product_id...), sequence_id a version
 * \param array $record - pole položek z formuláře
 * \param int &$record_id id uloženého záznamu (requirement_id, product_id...)
 * \param int &$version verze záznamu
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[sequence_id] pro určení větve. $webdoc[version] určuje verzi, pokud není bere se nejnovější   
 * \return bool false, pokud se uložení nezdařilo  
 */ 
function database_save_record($record,&$record_id,&$sequence_id,&$version)
{
  global $webdoc;

  if ($_GET["subpage2"]=="copy")
  {
    if (!$result=database_query("SELECT r.$webdoc[main_table]_id FROM $webdoc[main_table] r WHERE r.sequence_id=$webdoc[sequence_id]".(isset($webdoc["version"])?" and r.version=$webdoc[version]":"")." ORDER BY r.version DESC LIMIT 1")) return false;
    if (database_num_rows($result)!=1) return false;
    $parent=database_fetch_array($result);
    if (!isset($parent["$webdoc[main_table]_id"])) return false;
  }
  
  // ziskani version a u novych pozadavku ulozeni a ziskani sequence_id
  if ($_GET["subpage2"]=="new" || $_GET["subpage2"]=="copy") //ulozeni noveho pozadavku
  {
    if (database_query("INSERT INTO $webdoc[main_table]_parent (parent_id) VALUES(".($_GET["subpage2"]=="copy"?"'".$parent["$webdoc[main_table]_id"]."'":"NULL").")")) //ulozeni do requirement_parent - nova vetev
    {
      $sequence_id=database_insert_id(); //ziskani noveho sequence_id
      $version=0; //$version u novych pozadavku je vzdy 0
    }
    else return false;
  }
  elseif ($_GET["subpage2"]=="edit") //editace, ulozeni nove verze pozadavku
  {
    if ($result=database_query("SELECT MAX(version)+1 as version FROM $webdoc[main_table] WHERE sequence_id='$sequence_id'")) //zjisteni noveho version
    {
      extract(database_fetch_array($result)); //ziskani $version 
    }
    else return false;
  }

  // ulozeni samotnych dat
  $query="INSERT INTO $webdoc[main_table] (sequence_id, version, category_id, created, creator_id, name, description, comments";
  if ($webdoc["main_table"]=="requirement") $query.=", active, is_product_specific";
  $query.=") VALUES('$sequence_id','$version',".(isset($record["category_id"])?$record["category_id"]:"NULL").",now(),'$_SESSION[_auth]','$record[name]','$record[description]','$record[comments]'";
  if ($webdoc["main_table"]=="requirement") $query.=", 1, ".(isset($record["is_product_specific"])?$record["is_product_specific"]:"NULL");
  $query.=")";
  if (database_query($query)) $record_id=database_insert_id(); //ziskani record_id (requirement_id, product_id)
  else return false;
  
  // ulozeni zavislosti u requirements
  if ($webdoc["main_table"]=="requirement" && is_array($record["dependences_id"]))
  {
    //kopie zavislosti, aby z nich bylo mozne odmazat prazdne prvky a zaroven se po odmazani zobrazil formular ve stejnem stavu\
    $dependences_id=array_unique($record["dependences_id"]); //odstraneni duplicitnich prvku, aby se do db neukladal stejny radek vicekrat
    foreach ($dependences_id as $key => $id) //zadani jednotlivych id zaznamu do dotazu
    {
      if ($id<0 || $id=="") unset($dependences_id[$key]); //odstraneni neplatnych id (nebyl vybran v selectu zazny zaznam)
      else //pridani do dotazu
      {
        if (isset($values)) $values.=" , "; 
        $values.="('$record_id', '$id')";
      }
    }
    if (count($dependences_id)>0)
    {
      if (!database_query("INSERT INTO requirement_dependence (requirement_id,dependence_id) VALUES $values")) return false;
    }
  }
  
  // ulozeni provazanych pozadavku u product
  if ($webdoc["main_table"]=="product" && is_array($record["requirements_id"]))
  {
    $requirements_id=array();
    //odstraneni duplicitnich prvku, aby se do db neukladal stejny radek vicekrat
    foreach ($record["requirements_id"] as $key => $id)
    {
      foreach ($requirements_id as $key2 => $id2) if ($id==$id2) continue 2;
      $requirements_id[$key]=$id;
      $states_id[$key]=$record["states_id"][$key];
      $priorities_id[$key]=$record["priorities_id"][$key];
    }
    foreach ($requirements_id as $key => $id) //zadani jednotlivych id zaznamu do dotazu
    {
      if ($id<0 || $id=="") unset($requirements_id[$key]); //odstraneni neplatnych id (nebyl vybran v selectu zazny zaznam)
      else //pridani do dotazu
      {
        if (isset($values)) $values.=" , "; 
        $values.="('$record_id', '$id', '$states_id[$key]', '$priorities_id[$key]')";
      }
    }
    if (count($requirements_id)>0)
    {
      if (!database_query("INSERT INTO requirement_has_product (product_id, requirement_id, state_id, priority_id) VALUES $values")) return false;
    }
  }

  // oznameni o uspesne editaci nebo presmerovani na editaci po uspesnem vytvoreni nove vetve  
  if ($_GET["subpage2"]=="new" || $_GET["subpage2"]=="copy")
  {
    $url="./?subpage1=$_GET[subpage1]&subpage2=edit&sequence_id=$sequence_id"; //nova url
    $_SESSION["$webdoc[main_table]_sequence_id"]=$sequence_id; //session se sequence_id aktualni vetve
    $_SESSION["$webdoc[main_table]_record_saved"]=true; //session, ktera zpusobi zobrazeni hlasky o uspesnem ulozeni po pristim nacteni v editaci
    header("location: $url"); //presmerovani
    echo database_get_message("record_saved")." ".database_get_message("continue")." <a href=\"$url\">".database_get_message("here")."</a>."; //zobrazeni hlasky pokud prohlizec nepodporuje presmerovani
    exit;
  }
  else return true;
}

/**
 * uloží kategorii a vrátí její category_id
 * \param array $record - pole položek z formuláře
 * \param int &$category_id záznamu uložené kategorie
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[category_id] pro určení kategorie   
 * \return bool false, pokud se uložení nezdařilo  
 */ 
function database_save_category($record,&$category_id)
{
  global $webdoc;
  if ($_GET["subpage3"]=="new") //ulozeni nove kategorie
  {
    if (database_query("INSERT INTO $webdoc[main_table] (parent_id, name, description, time, person_id) VALUES(".(isset($record["parent_id"])?"'$record[parent_id]'":"NULL").", '$record[name]', '$record[description]', now(), '$_SESSION[_auth]')")) //ulozeni nove kategorie
    {
      $category_id=database_insert_id(); //ziskani category_id nove kategorie
    }
    else return false;
  }
  elseif ($_GET["subpage3"]=="edit") //editace, ulozeni nove verze pozadavku
  {
    if (!database_query("UPDATE $webdoc[main_table] SET parent_id=".(isset($record["parent_id"])?"'$record[parent_id]'":"NULL").", name='$record[name]', description='$record[description]', time=now(), person_id='$_SESSION[_auth]' WHERE category_id='$webdoc[category_id]'")) //ulozeni nove kategorie
      return false;
  }      

  // oznameni o uspesne editaci nebo presmerovani na editaci po uspesnem vytvoreni nove vetve  
  if ($_GET["subpage3"]=="new")
  {
    $url="./?subpage1=$_GET[subpage1]&subpage2=$_GET[subpage2]&subpage3=edit&category_id=$category_id"; //nova url
    $_SESSION["$webdoc[main_table]_category_id"]=$category_id; //session se sequence_id aktualni vetve
    $_SESSION["$webdoc[main_table]_record_saved"]=true; //session, ktera zpusobi zobrazeni hlasky o uspesnem ulozeni po pristim nacteni v editaci
    header("location: $url"); //presmerovani
    echo database_get_message("record_saved")." ".database_get_message("continue")." <a href=\"$url\">".database_get_message("here")."</a>."; //zobrazeni hlasky pokud prohlizec nepodporuje presmerovani
    exit;
  }
  else return true;
}

/**
 * vymaže kategorii
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[category_id] pro určení kategorie
 * \return bool true, pokud se podařilo záznam smazat, false, pokud se ho smazat nepodařilo 
 */
function database_delete_category()
{
  global $webdoc;
  if (database_query("DELETE FROM $webdoc[main_table] WHERE category_id=$webdoc[category_id]")) return true;
  return false;
}

/**
 * zjistí, zda má kategorie potomky (kategorie nebo požadavky, produkty)
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky, $webdoc[category_id] pro určení kategorie
 * \return bool true, pokud má kategorie potomky, false, pokud nemá potomky 
 */
function database_has_category_children()
{
  global $webdoc;
  $result=database_query("SELECT parent_id FROM $webdoc[main_table] WHERE parent_id=$webdoc[category_id]");//dotaz vrátí kategorie, které jsou nejbližším potomkem (o úroveň níž) testované katagorie
  if (database_num_rows($result)>0) return true; //testovaná kategorie obsahuje další kategorie
  $table=substr($webdoc["main_table"],0,strpos($webdoc["main_table"],"_category"));//určení tabulky se záznamy (requirement, product)
  $result=database_query("SELECT category_id FROM $table WHERE $table"."_id IN (SELECT max($table"."_id) FROM $table GROUP BY sequence_id) AND category_id=$webdoc[category_id]");//dotaz zjistí požadavky (produkty), které jsou v testované kategorii
  if (database_num_rows($result)>0) return true; //v testované kategorii jsou požadavky (produkty)
  return false; //testovaná kategorie neobsahuje žádné další kategorie nebo požadavky (produtky)
}

/**
 * schválení záznamu
 * \param int $record_id
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return bool true, pokud byl záznam schválen, jinak false  
 */
function database_approve_record($record_id)
{
  global $webdoc;
  return database_query("UPDATE $webdoc[main_table] SET approved=now(), approver_id='$_SESSION[_auth]' WHERE $webdoc[main_table]_id=$record_id");
}

/**
 * vyrazeni záznamu
 * \param int $record_id
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return bool true, pokud byl záznam schválen, jinak false  
 */
function database_terminate_record($record_id)
{
  global $webdoc;
  return database_query("UPDATE $webdoc[main_table] SET terminate=now(), terminator_id='$_SESSION[_auth]' WHERE $webdoc[main_table]_id=$record_id");
}

/**
 * oznaceni Test Runu jako hotoveho
 * \param int $record_id
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return bool true, pokud byl záznam schválen, jinak false  
 */
function database_tested_record($record_id)
{
  global $webdoc;
  return database_query("UPDATE $webdoc[main_table] SET tested=now(), tester_id='$_SESSION[_auth]' WHERE $webdoc[main_table]_id=$record_id");
}

/**
 * aktivace/deaktivace záznamu
 * \param int $record_id
 * \param bool [$activate] je-li true, aktivuje se záznam, je-li false, deaktivuje se. Výchozí hodnota je false 
 * \global array $webdoc je očekáváno $webdoc[main_table] pro určení tabulky 
 * \return bool true, pokud byla operace úspěšná, jinak false  
 */
function database_active_record($record_id,$activate=false)
{
  global $webdoc;
  return database_query("UPDATE $webdoc[main_table] SET active='".($activate?"1":"0")."' WHERE $webdoc[main_table]_id=$record_id");
}

/**
 * kontrola prihlasovacich udaju - funkce pouzita pouze v jednom pripade
 * pri spravnem prihlaseni nastaveni session, ktere uchovava person_id
 */ 
function database_get_auth($name,$pass)
{
  global $template, $message, $webdoc;
  $pass_sha1 = sha1($pass); // prevedeni zadaneho hesla na hash, algoritmus SHA1
  $result=database_query("SELECT * FROM person WHERE name LIKE '$name' AND pass LIKE '$pass_sha1' AND active NOT LIKE '0'");
  if (database_num_rows($result)==1) //zaznam existuje v db
  {
    $result_db = database_fetch_array($result);
    $_SESSION["$webdoc[main_table]_auth"]=$result_db["person_id"];
    $_SESSION["$webdoc[main_table]_role_id"]=$result_db["role_id"];
    $url="./"; // presmerovani na main-page
    header("location: $url");
  }
  else //porovnani se nazdarilo - vypsani chybove hlasky
  {
    $webdoc["message"][]=database_get_message("bad_auth");
    return false;
  }
}

/**
 * 1 - na kontrolu, zda v databazi Person neni jiz stejny login pri pridavani noveho uzivatele
 * 2 - na kontrolu, autorizace
 * 3 - na porovnani, zda k zadanemu loginu pasuje person_id   
 */ 
function database_get_auth_select($value1,$value2,$what)
{
  global $webdoc, $template, $message;
  
  switch ($what)
  {
  case "1":
    $result=database_query("SELECT * FROM person WHERE login LIKE '$value1'"); // adduser
    if (database_num_rows($result)==1) return false;
    else return true;
  break;
  
  case "2":
    $result=database_query("SELECT * FROM person WHERE person_id LIKE '$value1'"); // adduser
    if (database_num_rows($result)==0) return false;
    else return database_fetch_array($result); 
  break;
  
  case "3":
    $result=database_query("SELECT * FROM person WHERE login LIKE '$value1' AND person_id LIKE '$value2'"); // adduser
    if (database_num_rows($result)==1) return false;
    else return true;
  break;
  
  }
}

/**
 * ulozeni testu
 * \param record - pole polozek k vlozeni 
 */
function database_save_record_test($record)
{
  global $webdoc, $template, $message;
  
  if ($webdoc[main_table]=="test_run")
  {
    if (isset ($record["edit"]))
    {
      if (!database_query("UPDATE $webdoc[main_table] SET name='$record[name]', sw_rev='$record[sw_rev]', hw_rev='$record[hw_rev]', setup='$record[setup]', result='$record[result]', duration='$record[duration]', description='$record[description]' WHERE test_run_id=$record[test_run_id]"))
      {
        $webdoc["message"][]=database_get_message("error_saving");
        return false;
      }
      $_SESSION["$webdoc[main_table]_record_saved"]=true;
      $url="./?subpage1=test_run&subpage2=list";
      header("location: $url"); 
    }
    else
    {
      if (!database_query("INSERT INTO test_run (product_id, test_id, name, creator_id, created, tester_id, tested, approver_id, approved, sw_rev, hw_rev, setup, result, duration, description) VALUES ('$record[product_id]', '$record[test_id]', '$record[name]', '$webdoc[auth]', now(), ".(isset($record["tester_id"])?"'$record[tester_id]'":"NULL").", ".(isset($record["tested"])?"'$record[tested]'":"0").", ".(isset($record["approver_id"])?"'$record[approver_id]'":"NULL").", ".(isset($record["approved"])?"'$record[approved]'":"0").", '$record[sw_rev]', '$record[hw_rev]', '$record[setup]', '$record[result]', '$record[duration]', '$record[description]')"))
      {
        $webdoc["message"][]=database_get_message("error_saving");
        return false;
      }
      $_SESSION["$webdoc[main_table]_record_saved"]=true;
      $url="./?subpage1=test_run&subpage2=list";
      header("location: $url");
    }
  }
  else
  {
  if ($record["edit"])
  {
    $result=database_query("SELECT * FROM test WHERE test_id LIKE '$record[test_id]'");
    $result_db=database_fetch_array($result);
    $record["version"]=($result_db["version"])+1;
    $record["sequence_id"]=$result_db["sequence_id"];
    if (!database_query("INSERT INTO test (sequence_id, version, name, creator_id, created, approver_id, approved, acceptance_criteria, comments, terminator_id, terminate) VALUES ('$record[sequence_id]', '$record[version]', '$record[name]', '$record[creator_id]', '$record[created]', ".(isset($record["approver_id"])?"'$record[approver_id]'":"NULL").", ".(isset($record["approved"])?"'$record[approved]'":"0").", '$record[acceptance_criteria]', '$record[comments]', ".(isset($record["terminator_id"])?"'$record[terminator_id]'":"NULL").", ".(isset($record["terminate"])?"'$record[terminate]'":"0").")"))
    {
      $webdoc["message"][]=database_get_message("error_saving");
      return false;
    }
    $result=database_query("SELECT MAX(test_id) AS test_id FROM test"); //zjisteni noveho test_id
    $result_db = database_fetch_array($result);
    $new_test_id=$result_db["test_id"];   
    $result=database_query("SELECT * FROM requirement_has_test WHERE test_id LIKE '$record[test_id]'");
    if (database_num_rows($result)==0) return false;
    else
    {
     while ($zaznam = database_fetch_array($result))
      {
        if (!database_query("INSERT INTO requirement_has_test (requirement_id, test_id) VALUES ('$zaznam[requirement_id]', '$new_test_id')"))
        {
          $webdoc["message"][]=database_get_message("error_saving");
          return false;
        }
      }
    }
    $_SESSION["$webdoc[main_table]_record_saved"]=true;
    $url="./?subpage1=tests&subpage2=list";
    header("location: $url");      
  }
  else
  {
  $record["version"]=0;

  $result=database_query("SELECT MAX(sequence_id) AS sequence_id FROM test"); //zjisteni noveho sequence_id
  $result_db = database_fetch_array($result);
  $record["sequence_id"]=($result_db["sequence_id"])+1;   
  
  if (!database_query("INSERT INTO test (sequence_id, version, name, creator_id, created, approver_id, approved, acceptance_criteria, comments, terminator_id, terminate) VALUES ('$record[sequence_id]', '$record[version]', '$record[name]', '$record[creator_id]', '$record[created]', ".(isset($record["approver_id"])?"'$record[approver_id]'":"NULL").", ".(isset($record["approved"])?"'$record[approved]'":"0").", '$record[acceptance_criteria]', '$record[comments]', ".(isset($record["terminator_id"])?"'$record[terminator_id]'":"NULL").", ".(isset($record["terminate"])?"'$record[terminate]'":"0").")"))
  {
    $webdoc["message"][]=database_get_message("error_saving");
    return false;
  }
    
  $result=database_query("SELECT MAX(test_id) AS test_id FROM test"); //zjisteni noveho test_id
  $result_db = database_fetch_array($result);
  $record["test_id"]=($result_db["test_id"]);
  
  if (database_query("INSERT INTO requirement_has_test (requirement_id, test_id) VALUES ('$record[requirement_id]', '$record[test_id]')"))
    {
      $_SESSION["$webdoc[main_table]_record_saved"]=true;
      $url="./?subpage1=tests&subpage2=list";
      header("location: $url");
    }
    else
    {
      $webdoc["message"][]=database_get_message("error_saving");
      return false;
    }
  }
  }   
}

/**
 * vytvoreni record pro editaci testu
 */ 
function database_get_record_test($id)
{
  global $webdoc, $template, $message;
  if ($webdoc[main_table]=="test_run") $result=database_query("SELECT * FROM $webdoc[main_table] WHERE test_run_id LIKE '$id'");
  else $result=database_query("SELECT * FROM $webdoc[main_table] WHERE test_id LIKE '$id'");
  
  if (database_num_rows($result)==0) return false;
  else 
  { 
   if ($webdoc["main_table"]=="test" OR $webdoc["main_table"]=="test_run") return database_fetch_array($result);
   else return database_fetch_result($result,$row);
  }
} 
 

/**
 * ulozeni noveho zaznamu do Person
 * 1 - proste ulozeni po vyplneni formulare Add user
 * 2 - pouziti pri editaci, kdy nedochazi ke zmene hesla
 * 3 - pouziti pri editaci, kdy dochazi je zmene hesla   
 */ 
function database_save_record_auth($record,$what)
{
  global $webdoc, $template, $message;
  
  switch ($what)
  {
  case "1":
    $pass=sha1($record["pass"]);
    if (database_query("INSERT INTO person (login, pass, role_id, name, surname, email, register_id, register_time, active) VALUES ('$record[login]', '$pass', '$record[role_id]', '$record[name]', '$record[surname]', '$record[email]', '$record[register_id]', '$record[register_time]', '$record[active]')"))
    {
      $_SESSION["$webdoc[main_table]_new_auth"]=1;
      $url="./?subpage1=$_GET[subpage1]&subpage2=list_auth";
      header("location: $url");
    }
    else
    {
      $webdoc["message"][]=database_get_message("error_saving");
      return false;
    }
  break;
  
  case "2":
    if (database_query("UPDATE person SET login = '$record[login]', role_id = '$record[role_id]', name = '$record[name]', surname = '$record[surname]', email = '$record[email]', active = '$record[active]' WHERE person_id = $record[person_id]"))
    {
      $_SESSION["$webdoc[main_table]_edit_auth"]=1;
      $url="./?subpage1=$_GET[subpage1]&subpage2=list_auth";
      header("location: $url");
    }
    else
    {
      $webdoc["message"][]=database_get_message("error_edit");
      return false;
    }
  break;
  
  case "3":
    $pass=sha1($record["pass"]);
    if (database_query("UPDATE person SET login = '$record[login]', pass = '$pass', role_id = '$record[role_id]', name = '$record[name]', surname = '$record[surname]', email = '$record[email]', active = '$record[active]' WHERE person_id = $record[person_id]"))
    {
      $_SESSION["$webdoc[main_table]_edit_auth"]=1;
      $url="./?subpage1=$_GET[subpage1]&subpage2=list_auth";
      header("location: $url");
    }
    else
    {
      $webdoc["message"][]=database_get_message("error_edit");
      return false;
    }
  break;
  
  }
}

/**
 * meni uzivatelske heslo
 */ 
function database_change_userpass_auth($record)
{
  global $webdoc, $template, $message;
  
  $pass=sha1($record["pass"]);
  if (database_query("UPDATE person SET pass = '$pass' WHERE person_id = $record[person_id]"))
  {
    $_SESSION["$webdoc[main_table]_edit_auth"]=1;
    $url="./?subpage1=$_GET[subpage1]&subpage2=change_pass";
    header("location: $url");
  }
  else
  {
    $webdoc["message"][]=database_get_message("error_edit");
    return false;
  }
  
}

/**
 * maze uzivatele z databaze Person
 */ 
function database_delete_record_auth($record)
{
  global $webdoc, $template, $message;
  if (database_query("DELETE FROM person WHERE person_id = '$record'"))
  {
    $_SESSION["$webdoc[main_table]_delete_auth"]=1;
    $url="./?subpage1=$_GET[subpage1]&subpage2=list_auth";
    header("location: $url");
  }
  else
  {
    $webdoc["message"][]=database_get_message("error_delete");
    return false;
  }
}




/*** obecne funkce ***/

/**
 * ziskava pozadovanou hlasku na zaklade jejiho zadaneho name
 */ 
function database_get_message($name)
{
  $result=database_query("SELECT * FROM text WHERE name LIKE '$name'"); // ziskani chybove hlasky na zaklade jejiho pojmenovani
  if (database_num_rows($result)==1) //zaznam existuje v db
  {
    $result_db = database_fetch_array($result);
    return $result_db["text"];
  }
  else //porovnani se nazdarilo, dana hlaska neni v db, zobraz univerzalni
  {
    $no_message="There was an error.";
    return $no_message;
  }
}


/**
 * ziskava hodnoty z tabulky person_role
 */ 
function database_get_person_role()
{
  $result=database_query("SELECT * FROM person_role ORDER BY role_id"); // ziskani dat z DB
  if (database_num_rows($result)>0) //zaznam existuje v db
  {
    return $result;
  }
  else //porovnani se nazdarilo, dana hlaska neni v db, zobraz univerzalni
  {
    $webdoc["message"][]=database_get_message("error");
    return false;
  }
}

/**
 * autorizace, testuje, zda je nastavena session, pokud ne, odkazuje vzdy na login skript
 */ 
function auth($person_role)
{
  global $webdoc, $template, $message;
  if (!isset($webdoc["auth"])) // kontrola, zda je uživatel přihlášen
  {
    $url="./?subpage1=auth&subpage2=login";
    header("location: $url");
    $display_page=false;
  }
  else
  {
    $person_id = $webdoc["auth"];
    $role_id = $webdoc["role_id"];
    $webdoc["no_login"]=1;
    $template->template_assign("no_login",1);  
    $result=database_query("SELECT * FROM person WHERE person_id LIKE '$person_id'"); // ziskani promenne role_id
    $result_db = database_fetch_array($result);
    $active=$result_db["active"];
    
    if ($role_id<=$person_role && $active) $display_page=true; // testuje, jestli je uzivatel na urovni, nebo nad urovni zadanych prav, dale testuje, zda je uzivatel aktivni 
    else $display_page=false; 
  
  }
  return $display_page;
}

/**
 * zjistuje, zda je zadan spravny format mailove adreey
 */ 
function is_right_email($mail)
{
    return ereg("^.+@.+\..+$",$mail);
} 

/**
 * vytvoření spojení s databází
 * \return bool false, pokud se nepodařilo vytvořit spojení 
 */ 
function database_connect()
{
  if (!mysql_connect("localhost","root","heslo")) return false;
  if (!mysql_select_db("webdoc")) return false;
  return true;
}

/**
 * ukončení spojení s databází
 * \return bool false pokud se nepodařilo ukončit spojení 
 */ 
function database_close()
{
  return mysql_close();
}

/**
 * vykonání dotazu
 * \param string $query sql dotaz
 * \return int identifikátor spojení  
 */ 
function database_query($query)
{
  return mysql_query($query);
}

/**
 * zjistí id nově vloženého záznamu příkazem insert
 * \return int id nově vloženého záznamu
 */ 
function database_insert_id()
{
  return mysql_insert_id();
}

/**
 * zjistí počet vrácených záznamů příkazu select
 * \param int $result identifikátor spojení
 * \return int počet vrácených záznamů příkazu select   
 */ 
function database_num_rows($result)
{
  return mysql_num_rows($result);
}

/**
 * vrátí jeden záznam
 * \param int $result identifikátor spojení
 * \return array vrácený záznam  
 */ 
function database_fetch_array($result)
{
  return mysql_fetch_array($result);
}

/**
 * vrátí všechny vrácené záznamy v poli
 * \param int $result identifikátor spojení
 * \param int &$count počet vrácených záznamů  
 * \return array vrácené záznamy
 */ 
function database_fetch_result($result,&$count)
{
  if (!$result) return false;
  $count=database_num_rows($result);
  for ($i=0; $i<$count; $i++) $list[]=database_fetch_array($result);
  return $list;
}

?>
