<?php
/**
 * bin/tempus_project.php
 *
 * Using the .htaccess rerouting: all traffic should be directed to/through index.php.
 * In this file we initiate all models we will need, authenticate sessions, set
 * template objects, and call appload to initialize the appropriate controller/method.
 *
 * @version 3.0
 * @author  Joey Kimsey <Joey@thetempusproject.com>
 * @link    https://TheTempusProject.com
 * @license https://opensource.org/licenses/MIT [MIT LICENSE]
 */
namespace TheTempusProject;

use TheTempusProject\Bedrock\Bin\Bedrock;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Bedrock\Functions\Cookie;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Canary\Bin\Canary as Debug;

use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Hermes\Functions\Route as Routes;

use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Navigation;

use TheTempusProject\Classes\Installer;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\Models\Sessions;
use TheTempusProject\Models\User;
use TheTempusProject\Models\Group;
use TheTempusProject\Models\Routes as RoutesModel;

class TheTempusProject extends Bedrock {
    const MAIN_MENU_NAME = 'topNavLeft';
    const ADMIN_MENU_NAME = 'adminMenu';
    const CONTACT_FOOTER_MENU_NAME = 'contactFooterMenu';
    const INFO_FOOTER_MENU_NAME = 'infoFooterMenu';
    public static $plugins = [];
    public static $activeGroup;
    public static $activePerms;
    public static $activePrefs;
    public static $activeSession;
    public static $activeUser;
    public static $topNavRight = '';
    public static $topNavRightDropdown = '';
    public static $isLoggedIn = false;
    public static $isMember = false;
    public static $isAdmin = false;
    public static $isMod = false;
    private $initialized = false;
    public $contact_footer_links = [];
    public $info_footer_links = [
    ];
    public $admin_links = [
        [
            'text' => '<i class="fa fa-fw fa-home"></i> Dashboard',
            'url' => '{ROOT_URL}admin/index',
        ],
        [
            'text' => '<i class="fa fa-fw fa-gear"></i> Settings',
            'url' => '{ROOT_URL}admin/settings',
        ],
        [
            'text' => '<i class="fa fa-fw fa-user"></i> Users',
            'url' => '{ROOT_URL}admin/users',
        ],
        [
            'text' => '<i class="fa fa-fw fa-user-group"></i> Groups',
            'url' => '{ROOT_URL}admin/groups',
        ],
        [
            'text' => '<i class="fa fa-fw fa-phone"></i> Contact',
            'url' => '{ROOT_URL}admin/SendMail',
        ],
        [
            'text' => '<i class="fa fa-fw fa-shield-halved"></i> Tokens',
            'url' => '{ROOT_URL}admin/tokens',
        ],
        [
            'text' => '<i class="fa-solid fa-image"></i> Images',
            'url' => '{ROOT_URL}admin/images',
        ],
        [
            'text' => '<i class="fa fa-fw fa-arrow-down"></i> Modules',
            'url' => [
                [
                    'text' => '<i class="fa fa-fw fa-database"></i> Plugins',
                    'url' => '{ROOT_URL}admin/plugins',
                ],
                [
                    'text' => '<i class="fa fa-fw fa-database"></i> Composer',
                    'url' => '{ROOT_URL}admin/composer',
                ],
            ],
        ],
        [
            'text' => '<i class="fa fa-fw fa-arrow-down"></i> Logs',
            'url' => [
                [
                    'text' => '<i class="fa fa-fw fa-file"></i> Logs',
                    'url' => '{ROOT_URL}admin/logs',
                ],
                [
                    'text' => '<i class="fa fa-fw fa-lock"></i> Admin',
                    'url' => '{ROOT_URL}admin/admin',
                ],
                [
                    'text' => '<i class="fa fa-fw fa-warning"></i> Errors',
                    'url' => '{ROOT_URL}admin/errors',
                ],
                [
                    'text' => '<i class="fa fa-fw fa-history"></i> Logins',
                    'url' => '{ROOT_URL}admin/logins',
                ],
            ],
        ],
        [
            'text' => '<i class="fa fa-fw fa-external-link"></i> Redirects',
            'url' => '{ROOT_URL}admin/routes',
        ],
    ];
    public $main_links = [
        [
            'text' => 'Home',
            'url' => '{ROOT_URL}home/index',
        ],
        [
            'text' => 'About Me',
            'url' => '{ROOT_URL}home/about',
        ],
        [
            'text' => 'Blog',
            'url' => '{ROOT_URL}blog/index',
        ],
        [
            'text' => 'Hire Me',
            'url' => '{ROOT_URL}home/hire',
        ],
        [
            'text' => 'Admin',
            'url' => '{ROOT_URL}admin/index',
            'filter' => 'admin',
        ],
    ];
    public $filters = [
        [
            'name'    => 'bbCode.bold',
            'find'    => '#\[b\](.*?)\[/b\]#is',
            'replace' => '<b>$1</b>',
            'enabled' => true,
            'example' => '[b]Bold Text[/b]',
        ],
        [
            'name'    => 'bbCode.paragraph',
            'find'    => '#\[p\](.*?)\[/p\]#is',
            'replace' => '<p>$1</p>',
            'enabled' => true,
            'example' => '[p]Paragraph[/p]',
        ],
        [
            'name'    => 'bbCode.italic',
            'find'    => '#\[i\](.*?)\[/i\]#is',
            'replace' => '<i>$1</i>',
            'enabled' => true,
            'example' => '[i]Italic[/i]',
        ],
        [
            'name'    => 'bbCode.underline',
            'find'    => '#\[u\](.*?)\[/u\]#is',
            'replace' => '<u>$1</u>',
            'enabled' => true,
            'example' => '[u]Underline[/u]',
        ],
        [
            'name'    => 'bbCode.strike',
            'find'    => '#\[s\](.*?)\[/s\]#is',
            'replace' => '<del>$1</del>',
            'enabled' => true,
            'example' => '[s]Strike-through[/s]',
        ],
        [
            'name'    => 'bbCode.code',
            'find'    => '#\[code\](.*?)\[/code\]#is',
            'replace' => '<code>$1</code>',
            'enabled' => true,
            'example' => '[code]<p>Is it a paragraph though?</p>[/code]',
        ],
        [
            'name'    => 'bbCode.color',
            'find'    => '#\[color=(.*?)\](.*?)\[/color\]#is',
            'replace' => "<font color='$1'>$2</font>",
            'enabled' => true,
            'example' => '[color=red]This is an alert color![/color]',
        ],
        [
            'name'    => 'bbCode.image',
            'find'    => '#\[img\](.*?)\[/img\]#is',
            'replace' => "<img src='$1'>",
            'enabled' => true,
            'example' => '[img]/images/logo.png[/img]',
        ],
        [
            'name'    => 'bbCode.url',
            'find'    => '#\[url=(.*?)\](.*?)\[/url\]#is',
            'replace' => "<a href='$1'>$2</a>",
            'enabled' => true,
            'example' => '[url=https://google.com]Bing.com[/url]',
        ],
        [
            'name'    => 'bbCode.quote',
            'find'    => '#\[quote=(.*?)\](.*?)\[/quote\]#is',
            'replace' => "<blockquote cite='$1'>$2</blockquote>",
            'enabled' => true,
            'example' => '[quote=WhoSaidIt]What they said.[/quote]',
        ],
        [
            'name'    => 'bbCode.list',
            'find'    => '#\[list\](.*?)\[/list\]#is',
            'replace' => '<ul>$1</ul>',
            'enabled' => true,
            'example' => '[list][/list]',
        ],
        [
            'name'    => 'bbCode.listItem',
            'find'    => '#\(\.\)(.*)$#m',
            'replace' => '<li>$1</li>',
            'enabled' => true,
            'example' => '[list](.)Item1 (.)Item2[/list]',
        ],
        [
            'name'    => 'icons.check',
            'find'    => '#\(c\)#is',
            'replace' => '&#10004;',
            'enabled' => true,
            'example' => '(c)',
        ],
        [
            'name'    => 'icons.close',
            'find'    => '#\(x\)#is',
            'replace' => '&#10006;',
            'enabled' => true,
            'example' => '(x)',
        ],
        [
            'name'    => 'icons.exclaim',
            'find'    => '#\(!\)#is',
            'replace' => '&#10069;',
            'enabled' => true,
            'example' => '(!)',
        ],
        [
            'name'    => 'icons.question',
            'find'    => '#\(\?\)#is',
            'replace' => '&#10068;',
            'enabled' => true,
            'example' => '(?)',
        ],
    ];
    public static $configMatrix = [
        "main" => [
            "logo" => [
                "type" => "file",
                "pretty" => "Site Logo (Used mostly in emails)",
                "default" => "images/logo.png"
            ],
            "logoLarge" => [
                "type" => "file",
                "pretty" => "Large Site Logo (Used mostly when sharing images on social media)",
                "default" => "images/logoLarge.jpg"
            ],
            "name" => [
                "type" => "text",
                "pretty" => "Site Name",
                "default" => "TTP Example"
            ],
            "template" => [
                "type" => "text",
                "pretty" => "Default Site Template",
                "default" => "default"
            ],
            "tokenEnabled" => [
                "type" => "radio",
                "pretty" => "Enable CSRF Token for all forms.",
                "default" => true
            ],
            "registrationEnabled" => [
                "type" => "radio",
                "pretty" => "Allow new users to register an account.",
                "default" => true
            ],
            "loginLimit" => [
                "type" => "text",
                "pretty" => "Maximum Login Attempts per hour",
                "default" => 5
            ],
            "loginTimer" => [
                "type" => "text",
                "pretty" => "Maximum Login session length. (in seconds)",
                "default" => 604800 // 60 * 60 * 24 * 7
            ]
        ],
        "uploads" => [
            "images" => [
                "type" => "radio",
                "pretty" => "Upload Images Enabled",
                "default" => true,
                "value" => true,
            ],
            "maxImageSize"=> [
                "type" => "text",
                "pretty" => "Maximum size for image uploads",
                "default" => 500000,
                "value" => 500000,
            ]
        ],
        "database" => [
            "dbEnabled" => [
                "type" => "radio",
                "pretty" => "Database Enabled",
                "default" => true,
                "protected" => true
            ],
            "dbHost" => [
                "type" => "text",
                "pretty" => "Database Host (IE: http://localhost:3306)",
                "default" => "127.0.0.1",
                "protected" => true
            ],
            "dbMaxQuery" => [
                "type" => "text",
                "pretty" => "Maximum results per query",
                "default" => 100,
                "protected" => true
            ],
            "dbName" => [
                "type" => "text",
                "pretty" => "Database Name",
                "default" => "ttp-example",
                "protected" => true
            ],
            "dbPassword" => [
                "type" => "text",
                "pretty" => "Database Password",
                "default" => "",
                "protected" => true
            ],
            "dbPrefix" => [
                "type" => "text",
                "pretty" => "Database table Prefix",
                "default" => "TTP_",
                "protected" => true
            ],
            "dbUsername" => [
                "type" => "text",
                "pretty" => "Database Username",
                "default" => "root",
                "protected" => true
            ]
        ]
    ];

    public static $userCPlinks = [];

    /**
     * The constructor takes care of everything that we will need before
     * finally calling appload to instantiate the appropriate controller/method.
     */
    public function __construct() {
        // Initialize the parent app
        parent::__construct();
        Debug::info( 'Requested URL: ' . $this->getCurrentUrl() );

        // load our own config
        self::$activeConfig->load( CONFIG_JSON );

        // instead of htaccess it should check which server type and use that method
        if ( ! Check::isNginx() && ! file_exists( HTACCESS_LOCATION ) && ! file_exists( INSTALLER_LOCATION ) ) {
            echo file_get_contents( ERRORS_DIRECTORY . '533.html' );
            exit();
        }

        // Authenticate our session
        $this->authenticate();

        // Load any filter we need
        $this->loadFilters();

        // Notify admins if the installer is still around
        if ( self::$isAdmin ) {
            if ( file_exists( INSTALLER_LOCATION ) ) {
                if ( Debug::status() ) {
                    Debug::warn( 'You have not removed the installer yet.' );
                } else {
                    Issues::add( 'error', 'You have not removed the installer. This is a security risk that should be corrected immediately.' );
                }
            }
        }

        // Load nav links
        $this->loadLinks();

        // Load active plugins
        $plugins = Plugin::getActivePlugins();
        foreach ( $plugins as $plugin ) {
            foreach ($plugin as $name => $class) {
                self::$plugins[ $name ] = new $class( true );
            }
        }

        // load the damn usercp menu n a retarded fashion
        self::$userCPlinks[] = (object) [
            "url" => "{ROOT_URL}usercp",
            "name" => "Profile"
        ];
        self::$userCPlinks[] = (object) [
            "url" => "{ROOT_URL}usercp/settings",
            "name" => "Settings"
        ];
        self::$userCPlinks[] = (object) [
            "url" => "{ROOT_URL}usercp/email",
            "name" => "Change Email"
        ];
        self::$userCPlinks[] = (object) [
            "url" => "{ROOT_URL}usercp/password",
            "name" => "Change Password"
        ];
        Components::set( 'SITE_URL', Routes::getAddress() );
        Components::set( 'DEBUG_EMAIL', DEBUG_EMAIL );
        Debug::gend();
    }

    /**
     * Handles the permissions, preferences, login, and group setup for any active user.
     *
     * @return (bool)
     */
    public function authenticate() {
        $user = new User;
        $group = new Group;
        $sessions = new Sessions;
        // Set defaults
        self::$activePerms = $group->getDefaultPermissions(); // PERMISSIONS_JSON
        self::$activePrefs = $user->getDefaultPreferences(); // PREFERENCES_JSON
        if (
            !$sessions->checkSession( Session::get( 'SessionID' ) ) &&
            !$sessions->checkCookie( Cookie::get( 'RememberToken' ), true )
        ) {
            Debug::info( 'Sessions->authenticate - Could not authenticate cookie or session' );
            return false;
        }
        self::$isLoggedIn = true;
        self::$activeSession = $sessions::$activeSession;
        self::$activeUser = $user->get( self::$activeSession->userID );
        self::$activePrefs = self::$activeUser->prefs;
        self::$activeGroup = $group->findById( self::$activeUser->userGroup );
        if ( !empty( self::$activeGroup ) ) {
            self::$activePerms = self::$activeGroup->perms;
            self::$isAdmin = !empty(self::$activeGroup->perms['adminAccess']);
        } else {
            self::$isAdmin = false;
        }
        return true;
    }

    public static function dateTimeCallback( $data ) {
        if ( empty( $data[2] ) ) {
            return '';
        }
        return Date::formatTimestamp( $data[1], $data[2] );
    }

    public function loadFilters() {
        // These Filter have to be loaded here because they have calculated values
        $this->filters[] = [
            'name'    => 'mentions',
            'find'    => '#(^|\s)@([a-zA-Z_]+\w*)#',
            'replace' => '$1<a href="' . Routes::getRoot() . 'home/profile/$2">@$2</a>$3',
            'enabled' => true,
            'example' => '@username',
        ];
        $this->filters[] = [
            'name'    => 'hashtags',
            'find'    => '#(^|\s)\#([a-zA-Z\_\-]+\w*)#',
            'replace' => '$1<a href="' . Routes::getRoot() . 'home/hashtag/$2">#$2</a>$3',
            'enabled' => true,
            'example' => '#hash-tag',
        ];
        $this->filters[] = [
            'name'    => 'admin',
            'find'    => '#{ADMIN}(.*?){/ADMIN}#is',
            'replace' => ( self::$isAdmin ? '$1' : '' ),
            'enabled' => true,
            'example' => '{ADMIN}Only visible to users who are an admin.{ADMIN}',
        ];
        $this->filters[] = [
            'name'    => 'loggedin',
            'find'    => '#{LOGGEDIN}(.*?){/LOGGEDIN}#is',
            'replace' => ( self::$isLoggedIn ? '$1' : '' ),
            'enabled' => true,
            'example' => '{LOGGEDIN}Only visible to users who are logged-in{LOGGEDIN}',
        ];
        $this->filters[] = [
            'name'    => 'notloggedin',
            'find'    => '#{NOTLOGGEDIN}(.*?){/NOTLOGGEDIN}#is',
            'replace' => ( self::$isLoggedIn ? '' : '$1' ),
            'enabled' => true,
            'example' => '{NOTLOGGEDIN}Only visible to users who are logged-in{NOTLOGGEDIN}',
        ];
        $this->filters[] = [
            'name'    => 'dtc',
            'find'    => '#{DTC(.*?)}(.*?){/DTC}#is',
            'replace' => [ __CLASS__, 'dateTimeCallback' ],
            'enabled' => true,
            'callback' => true,
            'example' => '{DTC=date}000000000{DTC}',
        ];
        if ( ! empty( $this->filters ) ) {
            foreach( $this->filters as $filter ) {
                Filters::add( $filter['name'], $filter['find'], $filter['replace'], $filter['enabled'], ( $filter['callback'] ?? false ) );
            }
        }
    }

    public function loadLinks() {
        foreach ( $this->contact_footer_links as $key => $link ) {
            Navigation::addLink( self::CONTACT_FOOTER_MENU_NAME, $link );
        }
        foreach ( $this->info_footer_links as $key => $link ) {
            Navigation::addLink( self::INFO_FOOTER_MENU_NAME, $link );
        }
        foreach ( $this->main_links as $key => $link ) {
            Navigation::addLink( self::MAIN_MENU_NAME, $link );
        }
        foreach ( $this->admin_links as $key => $link ) {
            Navigation::addLink( self::ADMIN_MENU_NAME, $link );
        }
    }
    
    public function load( $url = '' ) {
        $routes = new RoutesModel;
        if ( empty( $url ) ) {
            $url = trim( Input::get( 'url' ), '/' );
            $url = str_ireplace( '.php', '', $url );
        }
        $route = $routes->findByOriginalUrl($url);
        if (false !== $route) {
            $route = $route;
            if ('internal' === $route->redirect_type) {
                $this->setUrl($route->forwarded_url);
            } else {
                Redirect::external($route->forwarded_url);
            }
        }
        parent::load();
    }

    public static function handle_shutdown() {
        if ( ! Debug::status( 'console' ) ) {
            return;
        }
        echo '<div class="container">';
            echo '<div class="col-centered">';
                echo '<div class="row" style="margin-bottom: 275px; padding-bottom: 25px; background: #eee;">';
                    echo '<h2 style="text-align: center; padding-top: 15px; padding-bottom: 15px;">';
                        echo 'Running the shutdown handler';
                    echo '</h2>';
                    Components::set( 'DEBUGGING_LOG', Debug::dump() );
                    $error = error_get_last();
                    echo '<p style="text-align: center;">';
                    if ( !empty( $error ) ) {
                        echo 'Looks like there was an error: <pre>' . print_r( $error, true ) . '</pre>';
                        // log_error( $error["type"], $error["message"], $error["file"], $error["line"] );
                    } else {
                        echo 'Shutting down without error.';
                    }
                    echo '</p>';
                    echo Views::simpleView( 'debug' );
                echo '</div>';
            echo '</div>';
        echo '</div>';
    }

    /**
     * Echos useful information about the installation.
     *
     * @return (null)
     */
    public function printDebug() {
        $autoload = '<tr><td>Vendor Autoloaded: </td><td><code>';
        $autoload .= var_export( VENDOR_AUTOLOADED, true );
        $autoload .= '</code></td></tr>';
        if ( VENDOR_AUTOLOADED === false ) {
            $autoload .= '<tr><td>Core Autoloaded: </td><td><code>';
            $autoload .= var_export( defined( 'BEDROCK_AUTOLOADED' ), true );
            $autoload .= '</code></td></tr>';
            $autoload .= '<tr><td>Project Autoloaded: </td><td><code>';
            $autoload .= var_export( defined( 'TEMPUS_PROJECT_AUTOLOADED' ), true );
            $autoload .= '</code></td></tr>';
            $autoload .= '<tr><td>Debugger Autoloaded: </td><td><code>';
            $autoload .= var_export( defined( 'CANARY_AUTOLOADED' ), true );
            $autoload .= '</code></td></tr>';
        }
        $autoload .= '<tr><td>Core Constants Loaded: </td><td><code>';
        $autoload .= var_export( BEDROCK_CONSTANTS_LOADED, true );
        $autoload .= '</code></td></tr>';
        $autoload .= '<tr><td>Project Constants Loaded: </td><td><code>';
        $autoload .= var_export( TEMPUS_PROJECT_CONSTANTS_LOADED, true );
        $autoload .= '</code></td></tr>';
        $autoload .= '<tr><td>Debugger Constants Loaded: </td><td><code>';
        $autoload .= var_export( CANARY_CONSTANTS_LOADED, true );
        $autoload .= '</code></td></tr>';
        echo '<div style="margin: 0 auto; padding-bottom: 25px; background: #eee; width: 1000px;">';
        echo '<h1 style="text-align: center;">Tempus Project Debugging Info</h1>';
        echo '<table style="margin: 0 auto; padding-bottom: 25px; background: #eee; width: 950px;">';
        echo '<tr><td style="text-align: center; padding-top: 25px; padding-bottom: 10px;" colspan="2"><h2>App Data</h2></td></tr>';
        echo '<tr><td>Controller: </td><td><code>';
        echo var_export( self::$controllerName, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>Method: </td><td><code>';
        echo var_export( self::$methodName, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>GET: </td><td><code>';
        echo var_export( $_GET, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>POST: </td><td><code>';
        echo var_export( $_POST, true );
        echo '</code><br></td></tr>';
        echo '<tr><td style="text-align: center; padding-top: 25px; padding-bottom: 10px;" colspan="2"><h2>Authentication</h2></td></tr>';
        echo '<tr><td>isLoggedIn: </td><td><code>';
        echo var_export( self::$isLoggedIn, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>isAdmin: </td><td><code>';
        echo var_export( self::$isAdmin, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>isMod: </td><td><code>';
        echo var_export( self::$isMod, true );
        echo '</code><br></td></tr>';
        echo '<tr><td>isMember: </td><td><code>';
        echo var_export( self::$isMember, true );
        echo '</code><br></td></tr>';
        echo '<tr><td style="text-align: center; padding-top: 25px; padding-bottom: 10px;" colspan="2"><h2>User Data</h2></td></tr>';
        echo '<tr><td>activeUser: </td><td><pre>';
        echo var_export( self::$activeUser, true );
        echo '</pre></td></tr>';
        echo '<tr><td>activeGroup: </td><td><pre>';
        echo var_export( self::$activeGroup, true );
        echo '</pre></td></tr>';
        echo '<tr><td>activePerms: </td><td><pre>';
        echo var_export( self::$activePerms, true );
        echo '</pre></td></tr>';
        echo '<tr><td>activePrefs: </td><td><pre>';
        echo var_export( self::$activePrefs, true );
        echo '</pre></td></tr>';
        echo '<tr><td style="text-align: center; padding-top: 25px; padding-bottom: 10px;" colspan="2"><h2>Autoload</h2></td></tr>';
        echo $autoload;
        echo '</table></div>';
        parent::printDebug();
    }
}
