<?php

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

require __DIR__ . '/required.php';
require __DIR__ . '/apiconfig.php';
require __DIR__ . '/authenticator.php';
require __DIR__ . '/functions.php';

/*
 * Gather request data in a variety of ways for maximum client flexibility
 */

// URL parameters and POST fields
$VARS = $_GET;
if ($_SERVER['REQUEST_METHOD'] != "GET") {
    $VARS = array_merge($VARS, $_POST);
}

// Parse JSON request body
$requestbody = file_get_contents('php://input');
$requestjson = json_decode($requestbody, TRUE);
if (json_last_error() == JSON_ERROR_NONE) {
    $VARS = array_merge($VARS, $requestjson);
}

// Get requested API endpoint
// Strip out urlbase
$pos = strpos($_SERVER['REQUEST_URI'], env("urlbase", "/"));
if ($pos !== false) {
    $routestr = substr_replace($_SERVER['REQUEST_URI'], "", $pos, strlen(env("urlbase", "/")));
}
$route = explode("/", $routestr);
if ($route[0] == "") {
    // The urlbase didn't have a trailing slash, so there's an empty zeroth element
    array_shift($route);
}

$ENDPOINT = $VARS["endpoint"] ?? "";
if (count($route) >= 1) {
    $ep = $route[0];
    // Ignore URL parameters if present,
    // otherwise requests like /endpoint?abc=123 will have the endpoint "endpoint?abc=123"
    $ep = explode("?", $ep, 2)[0];
    // Don't allow = in endpoint ID because it's confusing
    if (strpos($ep, "=") === FALSE) {
        $ENDPOINT = $ep;
    }
}
$urlkeyvaluepairs = [];
if (count($route) >= 2 && strpos($route[1], "?") !== 0) {
    for ($i = 1; $i < count($route); $i++) {
        if (empty($route[$i])) {
            continue;
        }
        if (strpos($route[$i], "=") === false) {
            // Allow slashes in endpoint as long as no key/value pairs have
            // been found yet
            if (empty($urlkeyvaluepairs)) {
                $ENDPOINT .= "/" . $route[$i];
            }
            continue;
        }
        $key = explode("=", $route[$i], 2)[0];
        $val = explode("=", $route[$i], 2)[1];
        $urlkeyvaluepairs[$key] = $val;
    }
}
$VARS += $urlkeyvaluepairs;

// Make sure /endpoint/?key=val&key2=val2 works
if (count($route) > 0 && strpos($route[count($route) - 1], "?") === 0) {
    $morevars = explode("&", substr($route[count($route) - 1], 1));
    foreach ($morevars as $var) {
        if (strpos($var, "=") === false) {
            continue;
        }
        $key = explode("=", $var, 2)[0];
        $val = explode("=", $var, 2)[1];
        $VARS[$key] = $val;
    }
}

if (empty($ENDPOINT)) {
    if (file_exists(__DIR__ . "/publicsite/index.html")) {
        http_response_code(200);
        header("Content-Type: text/html");
        exit(file_get_contents(__DIR__ . "/publicsite/index.html"));
    } else {
        http_response_code(404);
        die("404 No endpoint specified.");
    }
}

if (!isset($APIS[$ENDPOINT])) {
    if (preg_match("/[a-zA-Z0-9_\-]+/", $ENDPOINT) === 1 && file_exists(__DIR__ . "/publicsite/$ENDPOINT.html")) {
        http_response_code(200);
        header("Content-Type: text/html");
        exit(file_get_contents(__DIR__ . "/publicsite/$ENDPOINT.html"));
    } else {
        http_response_code(404);
        die("404 Requested endpoint (" . htmlentities($ENDPOINT) . ") not known.");
    }
}

// Deny access if authenticator returns false (add your logic to authenticator.php)
if (!authenticaterequest()) {
    http_response_code(401);
    die("401 Unauthorized: You need to supply valid credentials.");
}

$APIENDPOINTCONFIG = $APIS[$ENDPOINT];

if (!file_exists(__DIR__ . "/endpoints/" . $APIENDPOINTCONFIG["load"])) {
    http_response_code(404);
    die("404 Requested endpoint known but not found.");
}

// Check and validate arguments/data passed from client based on configured patterns
// This makes sure that all required variables are present and not malformed, reducing
// the amount of validation code in each endpoint
if (!empty($APIENDPOINTCONFIG["vars"])) {
    checkVars($APIENDPOINTCONFIG["vars"]);
}

// cleanup variables that won't be needed in endpoints
unset($route, $ep, $key, $val, $urlkeyvaluepairs, $pos, $requestjson, $requestbody, $i, $routestr);

require_once __DIR__ . "/endpoints/" . $APIENDPOINTCONFIG["load"];
