<?php

require_once('database.php');

/**
 * Class API
 * Contains all the routes and their classes
 */
class API
{
   /**
    * Array contains all the routes for the rest API
    *
    * @var array
    */
   private $routes = array('GET'    => array(),
                           'POST'   => array(),
                           'PUT'    => array(),
                           'DELETE' => array());

   public function __construct()
   {

   }

   /**
    * Sends error to the screen
    *
    * @param string $message Error message to JSON encode and send to the browser
    */
   public function return_error($message)
   {
      echo json_encode(array('error' => $message));
      exit(1);
   }

   /**
    * Adds a route for requests
    *
    * @param string  $method  HTTP method in [GET, PUT, POST, DELETE]
    * @param string  $regexp  Regular expression to match URL
    * @param APIPage $apiView Object to handle displaying of data
    * @param boolean $auth    Checks for authentication if true
    */
   public function route($method, $regexp, $apiView, $auth)
   {
      // Appends a route to the $routes variable, checks the method is valid.
      switch(strtoupper($method)) {
         case 'GET':
            $this->routes['GET'][] = array('regex' => $regexp, 'page' => $apiView, 'auth' => $auth);
            break;
         case 'POST':
            $this->routes['POST'][] = array('regex' => $regexp, 'page' => $apiView, 'auth' => $auth);
            break;
         case 'PUT':
            $this->routes['PUT'][] = array('regex' => $regexp, 'page' => $apiView, 'auth' => $auth);
            break;
         case 'DELETE':
            $this->routes['DELETE'][] = array('regex' => $regexp, 'page' => $apiView, 'auth' => $auth);
            break;
         default:
            $this->return_error("Not valid route");
      }
   }

   /**
    * Look through URL Regex's for a match and if a match then render output.
    *
    * @param string $url URL to run regular expressions against.
    */
   public function process_route($url)
   {
      // Get the HTTP METHOD
      $http_method = $_SERVER['REQUEST_METHOD'];

      // Loop through the revelant routes to find a match
      foreach($this->routes[$http_method] as $route) {
         $regex = $route['regex'];

         /** @var APIPage $pageObj */
         $pageObj = $route['page'];

         $match_value = preg_match($regex, $url, $matches);

         if($match_value == 1) {
            // Render the response and exit from the loop

            // Check for authentication if needed
            if($route['auth'] && isset($_SESSION['user']) == false) {
               header('HTTP/1.0 401 Unauthorized');
               exit;
            }
            error_log("After Auth");

            $pageObj->output($matches);
            break;
         }
      }
   }
}

/**
 * Class APIPage
 * Abstract class that all api functions extend
 */
abstract class APIPage
{
   /**
    * Database object
    *
    * @var ArsfDatabase
    */
   protected $db;

   /**
    * Output array for JSON
    *
    * @var array
    */
   protected $output = array();

   /**
    * Init the page, specify if you need a database connection
    *
    * @param boolean $connect_to_db
    */
   public function __construct($connect_to_db)
   {
      if($connect_to_db) {
         $this->db = new ArsfDatabase();
         $this->db->connect();
      }
   }

   /**
    * Generates page content and prints.
    *
    * @param array $matches The matches array from preg_match.
    */
   public function output($matches)
   {
      $this->render($matches);
      $this->print_json(JSON_PRETTY_PRINT);
   }

   /**
    * Constructs the page.
    *
    * @param array $regex_matches The matches array from preg_match.
    */
   protected function render($regex_matches)
   {

   }

   /**
    * Prints the JSON to the browser
    *
    * @param int $flags
    */
   private function print_json($flags = 0)
   {
      echo json_encode($this->output, $flags);
   }

   /**
    * Sends error to the screen
    *
    * @param $message
    */
   public function error($message)
   {
      $this->output = array('error' => $message);
   }

   /**
    * Checks to see if the array contains the keys in the array keys.
    *
    * @param array $array Array
    * @param array $keys  Keys to be in Array
    *
    * @return boolean $result true if the array has all the keys, otherwise false.
    */
   protected function has_keys($array, $keys)
   {
      $result = true;

      foreach($keys as $key) {
         $result &= array_key_exists($key, $array);
      }

      return $result;
   }
}

