<?php

/**
 * This software is intended for use with Oxwall Free Community Software http://www.oxwall.org/ and is
 * licensed under The BSD license.

 * ---
 * Copyright (c) 2013, Oxwall Foundation
 * All rights reserved.

 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice, this list of conditions and
 *  the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *  the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 *  - Neither the name of the Oxwall Foundation nor the names of its contributors may be used to endorse or promote products
 *  derived from this software without specific prior written permission.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * @author Podyachev Evgeny <joker.OW2@gmail.com>
 * @since 1.0
 */

require_once(OW::getPluginManager()->getPlugin('recaptcha')->getRootDir() . DS . 'lib' . DS . 'recaptchalib.php');

final class RECAPTCHA_BOL_Service extends OW_Entity
{
    private $supportLanguages = array(	'ar',
                                        'bg',
                                        'ca',
                                        'zh-CN',
                                        'zh-TW',
                                        'hr',
                                        'cs',
                                        'da',
                                        'nl',
                                        'en-GB',
                                        'en',
                                        'fil',
                                        'fi',
                                        'fr',
                                        'fr-CA',
                                        'de',
                                        'de-AT',
                                        'de-CH',
                                        'el',
                                        'iw',
                                        'hi',
                                        'hu',
                                        'id',
                                        'it',
                                        'ja',
                                        'ko',
                                        'lv',
                                        'lt',
                                        'no',
                                        'fa',
                                        'pl',
                                        'pt',
                                        'pt-BR',
                                        'pt-PT',
                                        'ro',
                                        'ru',
                                        'sr',
                                        'sk',
                                        'sl',
                                        'es',
                                        'es-419',
                                        'sv',
                                        'th',
                                        'tr',
                                        'uk',
                                        'vi'
        );

    const RECAPTCHA_SESSION_VAR = 'is_valid_recatpcha';

    private static $classInstance;

    /**
     * Class constructor
     */
    private function __construct()
    {
        
    }

    /**
     * Returns class instance
     *
     * @return RECAPTCHA_BOL_Service
     */
    public static function getInstance()
    {
        if ( self::$classInstance === null )
        {
            self::$classInstance = new self();
        }

        return self::$classInstance;
    }

    public function getPrivateKey()
    {
        return OW::getConfig()->getValue('recaptcha', 'private_key');
    }

    public function getPublicKey()
    {
        return OW::getConfig()->getValue('recaptcha', 'public_key');
    }

    public function getTheme()
    {
        $theme = OW::getConfig()->getValue('recaptcha', 'theme');
        return empty($theme) ? 'light' : $theme;
    }
    
    public function checkCaptchaValue($presponse, $remoteIp = null)
    {
        if ( empty($remoteIp) )
        {
            $remoteIp = $this->getRemoteIp();
        }

        $privateKey = RECAPTCHA_BOL_Service::getInstance()->getPrivateKey();

        if ( empty($remoteIp) )
        {
            $remoteIp = $this->getRemoteIp();
        }
        
        $timeout = (int)OW::getSession()->get(self::RECAPTCHA_SESSION_VAR . $presponse . $remoteIp);
        $error = '';
        
        if ( $timeout > time() )
        {
            return array( 'error' => $error, 'result' => true  );
        }
        
        $lib = new ReCaptcha($privateKey);
        $resp = $lib->verifyResponse($remoteIp, $presponse);
        $result = true;
        $error = '';
        
        if ( !$resp->success )
        {            
            $result = false;
            
            if ( !empty($resp->errorCodes) )
            {
                if (is_array($resp->errorCodes) )
                {
                    foreach ( $resp->errorCodes as $errorKey )
                    {
                        $error .= (!empty($error) ? "<br>": "") . OW::getLanguage()->text('recaptcha', $errorKey);
                    }
                }
                else 
                {
                    $error = OW::getLanguage()->text('recaptcha', $errorKey);
                }
            }
            
            OW::getSession()->delete(self::RECAPTCHA_SESSION_VAR . $presponse. $remoteIp);
        }
        else {
            OW::getSession()->set(self::RECAPTCHA_SESSION_VAR . $presponse. $remoteIp, time() + 60);
        }
        
        return array( 'error' => $error, 'result' => $result  );
    }

    public function getRemoteIp()
    {
        return !empty($_SERVER['HTTP_X_REAL_IP']) ? $_SERVER['HTTP_X_REAL_IP'] : $_SERVER['REMOTE_ADDR'];
    }

    public function drawCaptcha( $formElementId, $jsObjectName )
    {
        if ( empty($formElementId) || empty($jsObjectName) )
        {
            return false;
        }
        
        $userIp = $this->getRemoteIp();

        $publickey = RECAPTCHA_BOL_Service::getInstance()->getPublicKey();

        $string = ' 
                window.' . $jsObjectName . ' = new OW_ReCaptcha( ' . json_encode(array(
                'publickey' => $publickey,
                'userIp' => $userIp,
                'captchaId' => $formElementId,
                'theme' => RECAPTCHA_BOL_Service::getInstance()->getTheme(),
                'responderUrl' => OW::getRouter()->urlForRoute('recaptcha_verify'),
                'language' => $this->getLanguageTagForRecaptcha()
            )) . ');

            window.' . $jsObjectName . '.init();
                
            var tag = document.createElement("script");
            tag.src = "https://www.google.com/recaptcha/api.js?onload=onReacptchaLoadCallback&render=explicit&hl='.$this->getLanguageTagForRecaptcha().'";
            var firstScriptTag = document.getElementsByTagName("script")[0]; 
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

        ';
        
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        
        OW::getDocument()->addScript(OW::getPluginManager()->getPlugin('recaptcha')->getStaticJsUrl() . 'captcha.js');
        OW::getDocument()->addStyleSheet(OW::getPluginManager()->getPlugin('recaptcha')->getStaticCssUrl() . 'style.css');
        OW::getDocument()->addOnloadScript($string);

        return true;
    }

    public function getLanguageTagForRecaptcha()
    {
        $tag = BOL_LanguageService::getInstance()->getCurrent()->getTag();

        $matches = array();
        preg_match("/^([a-zA-Z]{2})-[a-zA-Z]{2}.*$/", $tag, $matches);

        $language = 'en';

        if ( !empty($matches[1]) )
        {
            $tmpLanguage = mb_strtolower($matches[1]);

            if ( in_array($tmpLanguage, $this->supportLanguages) )
            {
                $language = $tmpLanguage;
            }
        }

        return $language;
    }
    
}