<?php
/**
 * app/classes/forms.php
 *
 * This class is used in conjunction with TheTempusProject\Bedrock\Classes\Check
 * to house complete form verification. You can utilize the
 * error reporting to easily define exactly what feedback you
 * would like to give.
 *
 * @version 3.0
 * @author  Joey Kimsey <Joey@thetempusproject.com>
 * @link    https://TheTempusProject.com
 * @license https://opensource.org/licenses/MIT [MIT LICENSE]
 */
namespace TheTempusProject\Classes;

use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Models\User;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Bedrock\Classes\Database;

class Forms extends Check {
    private static $formHandlers = [];
    private static $initialized = false;

    public static function check( $formName ) {
        if ( self::$initialized !== true ) {
            self::initHandlers();
        }
        if ( empty( self::$formHandlers[ $formName ] ) ) {
            Debug::error( "Form not found: $formName" );
            return false;
        }
        $handler = self::$formHandlers[ $formName ];
        return call_user_func_array( [ $handler['class'], $handler['method'] ], $handler['params'] );
    }

    public static function addHandler( $formName, $class, $method, $params = [] ) {
        if ( !empty( self::$formHandlers[ $formName ] ) ) {
            return false;
        }
        self::$formHandlers[$formName] = [
            'class' => $class,
            'method' => $method,
            'params' => $params,
        ];
    }

    /**
     * Checks username formatting.
     *
     * Requirements:
     * - 4 - 16 characters long
     * - must only contain numbers and letters: [A - Z] , [a - z], [0 - 9]
     *
     * @param string $data - The string being tested.
     *
     * @return boolean
     */
    public static function checkUsername( $data ) {
        if ( strlen( $data ) > 16 ) {
            self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
            return false;
        }
        if ( strlen( $data ) < 4 ) {
            self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
            return false;
        }
        if ( !ctype_alnum( $data ) ) {
            self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
            return false;
        }
        return true;
    }

    public static function date( $data ) {
        if ( strtotime( $data ) == false ) {
            self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
            return false;
        }
        return true;
    }

    /**
    * Adds these functions to the form list.
    */
    public function __construct() {
        if ( self::$initialized === true ) {
            return;
        }
        self::initHandlers();
    }

    private static function initHandlers() {
        self::addHandler( 'passwordResetCode',   __CLASS__, 'passwordResetCode' );
        self::addHandler( 'createRoute',         __CLASS__, 'createRoute' );
        self::addHandler( 'editRoute',           __CLASS__, 'editRoute' );
        self::addHandler( 'register',            __CLASS__, 'register' );
        self::addHandler( 'createUser',          __CLASS__, 'createUser' );
        self::addHandler( 'editUser',            __CLASS__, 'editUser' );
        self::addHandler( 'login',               __CLASS__, 'login' );
        self::addHandler( 'changeEmail',         __CLASS__, 'changeEmail' );
        self::addHandler( 'changePassword',      __CLASS__, 'changePassword' );
        self::addHandler( 'passwordReset',       __CLASS__, 'passwordReset' );
        self::addHandler( 'emailConfirmation',   __CLASS__, 'emailConfirmation' );
        self::addHandler( 'confirmationResend',  __CLASS__, 'confirmationResend' );
        self::addHandler( 'replyMessage',        __CLASS__, 'replyMessage' );
        self::addHandler( 'newMessage',          __CLASS__, 'newMessage' );
        self::addHandler( 'userPrefs',           __CLASS__, 'userPrefs' );
        self::addHandler( 'newGroup',            __CLASS__, 'newGroup' );
        self::addHandler( 'editGroup',           __CLASS__, 'editGroup' );
        self::addHandler( 'install',             __CLASS__, 'install' );
        self::addHandler( 'adminCreateToken',    __CLASS__, 'adminCreateToken' );
        self::addHandler( 'apiLogin',            __CLASS__, 'apiLogin' );
        self::addHandler( 'updatePreference',    __CLASS__, 'updatePreference' );
        self::addHandler( 'installStart',        __CLASS__, 'install', [ 'start' ] );
        self::addHandler( 'installAgreement',    __CLASS__, 'install', [ 'agreement' ] );
        self::addHandler( 'installCheck',        __CLASS__, 'install', [ 'check' ] );
        self::addHandler( 'installConfigure',    __CLASS__, 'install', [ 'configure' ] );
        self::addHandler( 'installRouting',      __CLASS__, 'install', [ 'routing' ] );
        self::addHandler( 'installModels',       __CLASS__, 'install', [ 'models' ] );
        self::addHandler( 'installPlugins',      __CLASS__, 'install', [ 'plugins' ] );
        self::addHandler( 'installResources',    __CLASS__, 'install', [ 'resources' ] );
        self::addHandler( 'installAdminUser',    __CLASS__, 'install', [ 'adminUser' ] );
        self::$initialized = true;
    }

    /**
     * Validates the installer forms.
     *
     * @return {bool}
     */
    public static function install( $page = '' ) {
        // if ( !self::token() ) {
        //     return false;
        // }
        switch ( $page ) {
            case 'configure':
                if ( ! Input::exists( 'submit' ) ) {
                    return false;
                }
                if ( !Database::check( Input::post( 'dbHost' ), Input::post( 'dbName' ), Input::post( 'dbUsername' ), Input::post( 'dbPassword' ) ) ) {
                    self::addUserError( 'DB connection error.' );
                    return false;
                }
                return true;
            case 'adminUser':
                if ( !self::checkUsername( Input::post( 'newUsername' ) ) ) {
                    self::addUserError( 'Invalid username.' );
                    return false;
                }
                if ( !self::password( Input::post( 'userPassword' ) ) ) {
                    self::addUserError( 'Invalid password.' );
                    return false;
                }
                if ( Input::post( 'userPassword' ) !== Input::post( 'userPassword2' ) ) {
                    self::addUserError( 'Passwords do not match.' );
                    return false;
                }
                if ( Input::post( 'userEmail' ) !== Input::post( 'userEmail2' ) ) {
                    self::addUserError( 'Emails do not match.' );
                    return false;
                }
                return true;
            case 'check':
                if ( !self::uploads() ) {
                    self::addUserError( 'Uploads are disabled.' );
                    return false;
                }
                if ( !self::php() ) {
                    self::addUserError( 'PHP version is too old.' );
                    return false;
                }
                if ( !self::phpExtensions() ) {
                    self::addUserError( 'PHP extensions are missing.' );
                    return false;
                }
                if ( !self::sessions() ) {
                    self::addUserError( 'There is an error with Sessions.' );
                    return false;
                }
                if ( !self::mail() ) {
                    self::addUserError( 'PHP mail is not enabled.' );
                    return false;
                }
                if ( !self::safe() ) {
                    self::addUserError( 'Safe mode is enabled.' );
                    return false;
                }
                if ( ! Input::exists( 'submit' ) ) {
                    return false;
                }
                return true;
            case 'start':
            case 'agreement':
            case 'routing':
            case 'models':
            case 'plugins':
            case 'resources':
                if ( ! Input::exists( 'submit' ) ) {
                    return false;
                }
                return true;
            default:
                return false;
        }
        return false;
    }

    /**
     * Validates the password re-send form.
     *
     * @return {bool}
     */
    public static function passwordResetCode() {
        if ( !Input::exists( 'resetCode' ) ) {
            self::addUserError( 'Invalid resetCode.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the route creation form.
     *
     * @return {bool}
     */
    public static function createRoute() {
        if ( !Input::exists( 'redirect_type' ) ) {
            return false;
        }
        if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the route edit form.
     *
     * @return {bool}
     */
    public static function editRoute() {
        if ( !Input::exists( 'redirect_type' ) ) {
            return false;
        }
        if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the user creation form.
     *
     * @return {bool}
     */
    public static function createUser() {
        $user = new User;
        if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
            self::addUserError( 'Invalid username.' );
            return false;
        }
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        if ( !self::email( Input::post( 'email' ) ) ) {
            self::addUserError( 'Invalid Email.' );
            return false;
        }
        if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
            self::addUserError( 'A user with that email is already registered.' );
            return false;
        }
        if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
            self::addUserError( 'Passwords do not match.' );
            return false;
        }
        if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
            self::addUserError( 'Emails do not match.' );
            return false;
        }
        if ( !Input::post( 'groupSelect' ) ) {
            self::addUserError( 'You must select a group for the new user.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the user edit form.
     *
     * @return {bool}
     */
    public static function editUser() {
        $user = new User;
        if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
            self::addUserError( 'Invalid username.' );
            return false;
        }
        if ( Input::exists( 'password' ) ) {
            if ( !self::password( Input::post( 'password' ) ) ) {
                self::addUserError( 'Invalid password.' );
                return false;
            }
            if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
                self::addUserError( 'Passwords do not match.' );
                return false;
            }
        }
        if ( !self::email( Input::post( 'email' ) ) ) {
            self::addUserError( 'Invalid Email.' );
            return false;
        }
        if ( !Input::post( 'groupSelect' ) ) {
            self::addUserError( 'You must select a group for the new user.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the user registration form.
     *
     * @return {bool}
     */
    public static function register() {
        $user = new User;
        if ( !self::checkUsername( Input::post( 'username' ) ) ) {
            self::addUserError( 'Invalid username.' );
            return false;
        }
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        if ( !self::email( Input::post( 'email' ) ) ) {
            self::addUserError( 'Invalid Email.' );
            return false;
        }
        if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
            self::addUserError( 'A user with that email is already registered.' );
            return false;
        }
        if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
            self::addUserError( 'Passwords do not match.' );
            return false;
        }
        if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
            self::addUserError( 'Emails do not match.' );
            return false;
        }
        if ( Input::post( 'terms' ) != '1' ) {
            self::addUserError( 'You must agree to the terms of service.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the user login form.
     *
     * @return {bool}
     */
    public static function login() {
        if ( !self::checkUsername( Input::post( 'username' ) ) ) {
            self::addUserError( 'Invalid username.' );
            return false;
        }
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the email change form.
     *
     * @return {bool}
     */
    public static function changeEmail() {
        if ( !self::email( Input::post( 'email' ) ) ) {
            self::addUserError( 'Invalid Email.' );
            return false;
        }
        if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
            self::addUserError( 'Emails do not match.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }

        return true;
    }

    /**
     * Validates the password change form.
     *
     * @return {bool}
     */
    public static function changePassword() {
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
            self::addUserError( 'Passwords do not match.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }

        return true;
    }

    /**
     * Validates the password reset form.
     *
     * @return {bool}
     */
    public static function passwordReset() {
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
            self::addUserError( 'Passwords do not match.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the email confirmation re-send form.
     *
     * @return {bool}
     */
    public static function emailConfirmation() {
        if ( !Input::exists( 'confirmationCode' ) ) {
            self::addUserError( 'No confirmation code provided.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the email confirmation re-send form.
     *
     * @return {bool}
     */
    public static function confirmationResend() {
        if ( !Input::exists( 'resendConfirmation' ) ) {
            self::addUserError( 'Confirmation not provided.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the reply message form.
     *
     * @return {bool}
     */
    public static function replyMessage() {
        if ( !Input::exists( 'message' ) ) {
            self::addUserError( 'Reply cannot be empty.' );
            return false;
        }
        if ( !Input::exists( 'messageID' ) ) {
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the new message form.
     *
     * @return {bool}
     */
    public static function newMessage() {
        if ( !Input::exists( 'toUser' ) ) {
            self::addUserError( 'You must specify a user to send the message to.' );
            return false;
        }
        if ( !Input::exists( 'subject' ) ) {
            self::addUserError( 'You must have a subject for your message.' );
            return false;
        }
        if ( !Input::exists( 'message' ) ) {
            self::addUserError( 'No message entered.' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the user preferences form.
     *
     * @return {bool}
     */
    public static function userPrefs() {
        // @todo make this a real check
        if ( !Input::exists( 'timeFormat' ) ) {
            self::addUserError( 'You must specify timeFormat' );
            return false;
        }
        if ( !Input::exists( 'pageLimit' ) ) {
            self::addUserError( 'You must specify pageLimit' );
            return false;
        }
        if ( !Input::exists( 'gender' ) ) {
            self::addUserError( 'You must specify gender' );
            return false;
        }
        if ( !Input::exists( 'dateFormat' ) ) {
            self::addUserError( 'You must specify dateFormat' );
            return false;
        }
        if ( !Input::exists( 'timezone' ) ) {
            self::addUserError( 'You must specify timezone' );
            return false;
        }
        if ( !Input::exists( 'updates' ) ) {
            self::addUserError( 'You must specify updates' );
            return false;
        }
        if ( !Input::exists( 'newsletter' ) ) {
            self::addUserError( 'You must specify newsletter' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the group creation form.
     *
     * @return {bool}
     */
    public static function newGroup() {
        if ( !Input::exists( 'name' ) ) {
            self::addUserError( 'You must specify a name' );
            return false;
        }
        if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
            self::addUserError( 'invalid group name' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    /**
     * Validates the group edit form.
     *
     * @return {bool}
     */
    public static function editGroup() {
        if ( !Input::exists( 'name' ) ) {
            self::addUserError( 'You must specify a name' );
            return false;
        }
        if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
            self::addUserError( 'invalid group name' );
            return false;
        }
        if ( !self::token() ) {
            return false;
        }
        return true;
    }

    public static function adminCreateToken() {
        if ( !Input::exists( 'name' ) ) {
            self::addUserError( 'You must specify a name' );
            return false;
        }
        if ( !Input::exists( 'token_type' ) ) {
            self::addUserError( 'You must specify a token_type' );
            return false;
        }
        return true;
    }

    public static function adminEditToken() {
        if ( !Input::exists( 'name' ) ) {
            self::addUserError( 'You must specify a name' );
            return false;
        }
        if ( !Input::exists( 'token_type' ) ) {
            self::addUserError( 'You must specify a token_type' );
            return false;
        }
        return true;
    }
    
    public static function apiLogin() {
        if ( !self::checkUsername( Input::post( 'username' ) ) ) {
            self::addUserError( 'Invalid username.' );
            return false;
        }
        if ( !self::password( Input::post( 'password' ) ) ) {
            self::addUserError( 'Invalid password.' );
            return false;
        }
        return true;
    }

    public static function updatePreference() {
        if ( !Input::exists( 'prefName' ) ) {
            self::addUserError( 'You must specify a name' );
            return false;
        }
        if ( !Input::exists( 'prefValue' ) ) {
            self::addUserError( 'You must specify a value' );
            return false;
        }
        return true;
    }
}
