<?php #lib/30_pages.php

/********************************************************************************
 *	Content: Pages-Management                                                   *
 *	Author: Nils Otterpohl                                                      *
 *	Last modification: 24.06.2019                                               *
 *	Version: stable (complete, tested, uncommented)                             *
 ********************************************************************************/

/**************************************************/
/******************** BaseApp *********************/
/**************************************************/

abstract class BaseApp {
  protected $db;      // Database connection
  protected $kv;      // Redis connection
  protected $man;     // Manager link
  protected $output = []; // Output
  protected $meta = [];
  protected $useRight = null;
  protected $adminRight = null;
  protected $table = "";
  
  public function __construct($database, $keyvaluestore, $manager, $info) {
    $this->db =     $database;
    $this->kv =     $keyvaluestore;
    $this->man =    $manager;
    $this->useRight = $info["useRight"];
    $this->adminRight = $info["adminRight"];
    $this->table = $info["table"];
  }
  
  protected function canEdit() {
  	return $this->man->user->HasRight($this->adminRight);
  }
}

/**************************************************/
/******************** BaseLink ********************/
/**************************************************/

abstract class BaseLink extends BaseApp
{
  private $page;
  public function __construct($database, $keyvaluestore, $manager, $info, $page) {
    parent::__construct($database, $keyvaluestore, $manager, $info);
    $this->page = $page;
  }
  
  public function DoRequest($method, $ids) {
    switch ($method) {
      case "GET":
        return $this->get($ids);
      case "POST":
        return $this->canEdit() ? $this->insert($ids) : 403;
      case "PATCH":
        return $this->canEdit() ? $this->update($ids) : 403;
      case "DELETE":
        return $this->canEdit() ? $this->remove($ids) : 403;
      default:
        return 501;
  } }
  
  protected function insert($ids) {
  	return 501;
  }
  
  protected function get($ids) {
  	return 501;
  }
  
  protected function update($ids) {
  	return 501;
  }
  
  protected function remove($ids) {
  	return 501;
  }
}

/**************************************************/
/******************** BasePage ********************/
/**************************************************/

abstract class BasePage extends BaseApp
{
  protected $title;       // Title of Hyperlink
  protected $route;       // Module name, i.e. the route to open this page (/index.php/page/filter/%ROUTE%/filter)
  protected $path;        // Internal path to files (/pgs/PATH/)
  protected $links = [];  // List of existing submodules
  protected $output = []; // Output
  protected $groupIndex = [];
  protected $options = [];
  protected $optionsIndex = [];
  
  public function __construct($database, $keyvaluestore, $manager, $info) {
    parent::__construct($database, $keyvaluestore, $manager, $info);
    $this->title =  $info["title"];
    $this->route =  $info["route"];
    $this->path =   $info["path"];
    $this->links =	$info["links"];
    $this->options = $this->fillOptions($this->canEdit());
    foreach ($this->options as $field => $rows) {
    	foreach ($rows as $index => $row) {
    		$this->optionsIndex[$field][$row["ID"]] = &$this->options[$field][$index];
    	}
    }
  }
  
  public function GetLink($link) {
    if (isset($this->links[$link])) {
      return $this->links[$link];
    } else {
      return null;
  } }
  
  public function GetTemplate() {
    if (file_exists($this->FullPath()."template.html")) {
      return $this->FullPath()."template.html";
    } else {
      return "";
  } }
  
  public function FullPath() {
    return "pgs/".$this->path."/";
  }
  
  public function DoRequest($method) {
    $id = $this->man->Main();
    switch ($method) {
    	case "HEAD":
    		return $this->head();
      case "GET":
        return $this->get($id);
      case "OPTIONS":
      	return $this->info();
    	case "POST":
    		return $this->canEdit() ? $this->insert() : 403;
    	case "PATCH":
      case "DELETE":
      	if ($id===null) {
    			$this->man->AddMessage("Keine ID spezifiziert!");
    			return 400;
    		}
    		if (!$this->canEdit()) {
    			return 403;
    		}
    		return $method=="PATCH" ? $this->update($id) : $this->remove($id);
    }
    return 501;
  }
  
  protected function insert() {
  	return 501;
  }
  
  protected function head() {
  	return 501;
  }
  
  protected function get($id) {
  	return 501;
  }
  
  protected function info() {
  	$this->man->output["options"] = $this->options;
  	return 200;
  }
  
  protected function update($id) {
  	return 501;
  }
  
  protected function remove($id) {
    if ($stmt = $this->db->prepare("DELETE FROM ".$this->table." WHERE ID = ?")) {
      $stmt->bind_param("i", $id);
      if ($stmt->execute()) {
        if (1==$stmt->affected_rows) {
          $this->man->AddMessage("Erfolgreich entfernt!");
          return 200;
        } else if (0==$stmt->affected_rows) {
        	$this->man->AddMessage("Fehler: Es wurde nichts entfernt!");
        } else {
        	$this->man->AddMessage("Fehler: Es wurden mehrere Einträge entfernt!");
        }
      } else {
        $this->man->AddMessage("Mysql error: ".$this->db->error);
      }
    } else {
      $this->man->AddMessage("Mysql error: ".$this->db->error);
    }
    return 500;
  }
  
  public function GetResult() {
    return $this->output;
  }
  
  public function GetMeta() {
    return $this->meta;
  }
  
  public function GetOptions($admin = false) {
    return $this->options;
  }
  
  /******************** Protected functions ********************/
  
  protected function getFilterString($op, $allowedOps, $table, $field, $value) {
    $tblString = ""!=$table ? $table."." : "";
    if (in_array($op, $allowedOps)) {
      switch ($op) {
        case "=":
          return $value===null ? $tblString."`".$field."` IS NULL " : $tblString."`".$field."` = '".$value."' ";
        case "<>":
          return $value===null ? $tblString."`".$field."` IS NOT NULL " : $tblString."`".$field."` <> '".$value."' ";
        case "<":
          return $tblString."`".$field."` < '".$value."' ";
        case ">":
          return $tblString."`".$field."` > '".$value."' ";
        case "<=":
          return $tblString."`".$field."` <= '".$value."' ";
        case ">=":
          return $tblString."`".$field."` >= '".$value."' ";
        case "like":
          return $tblString."`".$field."` LIKE '%".$value."%' ";
        case "not like":
          return $tblString."`".$field."` NOT LIKE '%".$value."%' ";
        case "in":
          return "'".$value."' IN ".$tblString.$field."' ";
        case "not in":
          return "'".$value."' NOT IN ".$tblString.$field."' ";
    } }
    return "1 ";
  }
  
  protected function registerGroup($group) {
    if (!array_key_exists($group, $this->groupIndex)) {
      $len = array_push($this->output, ["ID" => $group, "ENTRIES" => []]);
      $this->groupIndex[$group] = &$this->output[$len-1];
  } }
  
  protected function addEntryToOutput($group, $entry, $single) {
    if ($single) {
      $entry["GROUP"] = $group;
      $this->output = $entry;
    } else {
      $this->registerGroup($group);
      $this->groupIndex[$group]["ENTRIES"][] = $entry;
  } }
  
  protected function fillOptions($admin = false) {
  	return [];
  }
  
  protected function getSub($field, $string) {
    $ret = [];
    $entries = explode(",", $string ?? "");
    foreach ($entries as $entry) {
      if (""!=$entry && isset($this->optionsIndex[$field][$entry])) {
        $ret[] = $this->optionsIndex[$field][$entry];
    } }
    return $ret;
  }
}
