<?php
QUnit_Global::includeClass('Affiliate_Scripts_Bl_ClickRegistrator');

class Affiliate_Scripts_Bl_ClickRegistratorCache extends Affiliate_Scripts_Bl_ClickRegistrator
{
    var $cache, $cacheParams;
    var $timeStarted, $maxTimeToRun;
    var $rotatorID;
    
    //--------------------------------------------------------------------------
    
    function setCache($cache) {
        $this->cache = $cache;
    }
    
    //--------------------------------------------------------------------------
    
    function process($params) {
        $this->settings['Aff_debug_clicks'] = $GLOBALS['Auth']->getSettingForScripts('Aff_debug_clicks');
        
        $affiliateID = $params['affiliateID'];
        $bannerID = $params['bannerID'];
        $data1 = $params['data1'];
        $data2 = $params['data2'];
        $data3 = $params['data3'];
        $destUrl = $params['destUrl'];
        $referrer = $params['referrer'];
        $dontRedirect = $params['dontRedirect'];
        
        $this->setExtraData($data1, $data2, $data3);
        
        // check if this affiliate and campaign exist
        if(!$this->checkUserExists($affiliateID)) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Affiliate with ID '".$affiliateID."' doesn't exist", __FILE__, __LINE__);
            return false;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that affiliate exists, OK", __FILE__, __LINE__);
        
        // check if domain is approved
        if($GLOBALS['Auth']->getSetting('Aff_force_aff_domains_approval') == '1') {
            if(!$this->checkInDomain()) {
                $this->registratorLog(WLOG_DEBUG, "Click registration: Banner with ID '$bannerID' for affiliate '$affiliateID' is placed in unallowed domain", __FILE__, __LINE__);
                return false;
            }
            
            $this->registratorLog(WLOG_DEBUG, "Click registration: After check that banner is in approved defined domain, OK", __FILE__, __LINE__);
        }
        
        if(!$this->checkBannerExists($bannerID, true)) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Banner '$bannerID' doesn't exist and cannot find any campaign for affiliate '$affiliateID'", __FILE__, __LINE__);
            return false;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that banner exists, OK", __FILE__, __LINE__);
        
        if(!$this->checkCampaignExists()) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Campaign '".$this->campaignID."' doesn't exist", __FILE__, __LINE__);
            return false;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that campaign exists", __FILE__, __LINE__);
        
        if(!$this->checkUserInCampaign()) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Affiliate '$affiliateID' doesn't belong to the campaign '".$this->campaignID."'", __FILE__, __LINE__);
            return false;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that affiliate is in this product category, OK", __FILE__, __LINE__);
        
        $header = $this->getP3PPolicy('0');   
        $cookie = $this->getCookie();
        $redirect = $this->getRedirect();
        
        if ($affiliateID != $this->UserID) {
            $this->cache['refid_userid']->replace($affiliateID, $this->UserID);
            $affiliateID = $this->UserID;
        }
        
        $data = $header.';'.
                $redirect['permredir'].';'.
                $redirect['desturl'].';'.
                $cookie['tosession'].';'.
                $cookie['value'].';'.
                $cookie['lifetime'];
        
        $this->cache['input']->replace($affiliateID.';'.$bannerID, $data);
        
        return $data;
    }
    
    //--------------------------------------------------------------------------
    
    function getCookie()
    {        
        $data = $this->decodeValue($_COOKIE[COOKIE_NAME]);
        
        $cookieUserID = $data[0];
        $cookieCampaignID = $data[1];

        if($this->UserID == '') {
            $this->registratorLog(WLOG_DEBUG, "Click registration: UserID is empty", __FILE__, __LINE__);
            return false;
        }

        if($this->CampaignID == '') {
            $this->registratorLog(WLOG_DEBUG, "Click registration: CampaignID is empty", __FILE__, __LINE__);
            return false;      
        }

        if($data != false && ($this->UserID != $cookieUserID || $this->CampaignID != $cookieCampaignID) && $this->settings['Aff_overwrite_cookie'] != '1') {
            $this->registratorLog(WLOG_DEBUG, "Click registration: cookie exists, not allowed to overwrite, cancelling saving to cookie", __FILE__, __LINE__);
            return true;
        }

        $ret = array();
        
        if($this->cookieLifetime == '')
            $this->cookieLifetime = 0;
            
        $value = $this->UserID.'_'.$this->CampaignID;
        
        $ret['value'] = $value;
        $ret['lifetime'] = $this->cookieLifetime;
        $ret['tosession'] = ($this->settings['Aff_track_by_session'] == 1) ? 1 : 0;

        return $ret;
    }
    
    //--------------------------------------------------------------------------
    
    function getP3PPolicy($load_settings = '1')
    {
        if($load_settings)
            $this->settings = QCore_Settings::getAccountSettings(SETTINGTYPE_ACCOUNT, $this->AccountID);
        
        $policyRef = '';
        $cp = '';
        
        if($this->settings['Aff_p3p_xml'] != '')
            $policyRef = $this->settings['Aff_p3p_xml'];
        
        if($this->settings['Aff_p3p_compact'] != '')
            $cp = $this->settings['Aff_p3p_compact'];
        
        if($cp != '' || $policyRef != '')
        {
            $p3pPolicy = 'P3P: '.($policyRef == '' ? '' : 'policyref="'.$policyRef.'"').
                                ($cp != '' && $policyRef != '' ? ', ' : '').
                                ($cp == '' ? '' : 'CP="'.$cp.'"');
            
            $this->registratorLog(WLOG_DEBUG, "Registrator: P3P policy set to '$p3pPolicy'", __FILE__, __LINE__);
            
            return $p3pPolicy;
        }
        return '';
    }
    
    //--------------------------------------------------------------------------
    
    function getRedirect($destUrl = '')
    {
        $ret = array();
        
        // if no POST variables are set, then only redirect
        $ret['permredir'] = ($this->settings['Aff_permanent_redirect'] == 1) ? 1 : 0;
        $ret['desturl'] = ($destUrl == '') ? $this->destinationURL : $destUrl;
        
        return $ret;
    }
    
    //--------------------------------------------------------------------------
    
    function getUnprocessedFile() {
        $files = array();
        if ($dir = @opendir(CACHE_PATH)) {
            while (($file = readdir($dir)) !== false) {
                if((strstr($file, T_OUTPUT_CACHE_FILENAME) !== false) && ($file !== T_OUTPUT_CACHE_FILENAME)) {
                    $files[] = $file;
                }
            } 
            closedir($dir);
        }
        if (count($files) != 0) {
            sort($files);
            reset($files);
            if ($files[0] != '') {
               return $files[0];
            }
        }
        return false;
    }
    
    //--------------------------------------------------------------------------
    
    function processFile($file) {
        $cache = new Cache(CACHE_PATH.$file);
        if($cache->open() === false) {
            $this->writeHistory(WLOG_ERROR, 'Error opening sb output cache file '.CACHE_PATH.$file, __FILE__, __LINE__);
            return false;
        }
        
        $cache->reset();
        while ($data = $cache->getNextValueAndDelete()) {
            $data = explode(';', $data);
            $params = array();
            $params['affiliateID'] =     $data[0];
            $params['bannerID'] =        $data[1];
            $params['subBannerID'] =     $data[2];
            $params['data1'] =           $data[3];
            $params['data2'] =           $data[4];
            $params['data3'] =           $data[5];
            $params['destUrl'] =         $data[6];
            $params['referrer'] =        $data[7];
            $params['dontRedirect'] =    $data[8];
            $params['browserHash'] =     $data[9];
            $params['cookieSetReturn'] = $data[10];
            $params['time'] =            $data[11];
            $params['HTTP_REFERER'] =    $data[12];
            $params['REMOTE_ADDR'] =     $data[13];

            $this->processClick($params);
            
            // check if we have enough time  
            if (microtime_diff($this->timeStarted, microtime()) > $this->maxTimeToRun) {
                return false;
            }
        }
        $cache->clearAndClose();
    }
    
    //--------------------------------------------------------------------------
    
    function createCopy() {
        if(!file_exists(CACHE_PATH.T_OUTPUT_CACHE_FILENAME)) {
            return false;
        }
        $filename = 'unpr_'.time().'_'.rand(1, 100).'_'.T_OUTPUT_CACHE_FILENAME;
        @rename(CACHE_PATH.T_OUTPUT_CACHE_FILENAME, CACHE_PATH.$filename);
        return true;
        
    }
    
    //--------------------------------------------------------------------------
    
    function processFromCache() {
        $this->timeStarted = microtime();
        $this->maxTimeToRun = (ini_get('max_execution_time') == '') ? 20 : ini_get('max_execution_time') - 10; 
        
        while (microtime_diff($this->timeStarted, microtime()) < $this->maxTimeToRun) {
                if(($file = $this->getUnprocessedFile()) !== false) {
                if($this->processFile($file) == false) {
                    return;
                }
            } else {
                $this->createCopy();
            }
        }
    }
    
    //--------------------------------------------------------------------------
    
    function processClick($params) {
        $this->settings['Aff_debug_clicks'] = $GLOBALS['Auth']->getSettingForScripts('Aff_debug_clicks');
        
        $affiliateID = $params['affiliateID'];
        $bannerID = $params['bannerID'];
        $data1 = $params['data1'];
        $data2 = $params['data2'];
        $data3 = $params['data3'];
        $destUrl = $params['destUrl'];
        $referrer = $params['referrer'];
        $dontRedirect = $params['dontRedirect'];
        $GLOBALS['HTTP_REFERER'] = $params['HTTP_REFERER'];
        $this->cacheParams = $params;
        
        $this->setExtraData($data1, $data2, $data3);
        
        // check if this affiliate and campaign exist
        if(!$this->checkUserExists($affiliateID)) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Affiliate with ID '".$affiliateID."' doesn't exist", __FILE__, __LINE__);
            return;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that affiliate exists, OK", __FILE__, __LINE__);
        
        // check if domain is approved
        if($GLOBALS['Auth']->getSetting('Aff_force_aff_domains_approval') == '1') {
            if(!$this->checkInDomain()) {
                $this->registratorLog(WLOG_DEBUG, "Click registration: Banner with ID '$bannerID' for affiliate '$affiliateID' is placed in unallowed domain", __FILE__, __LINE__);
                return;
            }
            
            $this->registratorLog(WLOG_DEBUG, "Click registration: After check that banner is in approved defined domain, OK", __FILE__, __LINE__);
        }
        
        if(!$this->checkBannerExists($bannerID, true)) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Banner '$bannerID' doesn't exist and cannot find any campaign for affiliate '$affiliateID'", __FILE__, __LINE__);
            return;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that banner exists, OK", __FILE__, __LINE__);
        
        if(!$this->checkCampaignExists()) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Campaign '".$this->campaignID."' doesn't exist", __FILE__, __LINE__);
            return;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that campaign exists", __FILE__, __LINE__);
        
        if(!$this->checkUserInCampaign()) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Affiliate '$affiliateID' doesn't belong to the campaign '".$this->campaignID."'", __FILE__, __LINE__);
            return;
        }
        $this->registratorLog(WLOG_DEBUG, "Click registration: After check that affiliate is in this product category, OK", __FILE__, __LINE__);
        
        // geo-targetting check
        $this->setCountryData('__');
        $isAllowedCountry = true;
        
        if($this->settings['Glob_acct_geo_allowed'] == '1') {
            $ip = $params['REMOTE_ADDR'];
            $blIpCountry = QUnit_Global::newObj('QCore_Bl_IpCountry');
            $country = $blIpCountry->getCountryForIp($ip);
            $this->setCountryData($country['countrycode']);
            if(!$blIpCountry->isAllowedCountry($country, $this->settings) && $this->settings['Glob_acct_geo_dont_register_click'] == '1') {
                $this->registratorLog(WLOG_DEBUG, "Click registration: Country from IP '$ip' is not in list of allowed countries", __FILE__, __LINE__);
                $isAllowedCountry = false;
            }
        }
        
        if($isAllowedCountry) {
            $this->saveClick($referrer);
            $this->registratorLog(WLOG_DEBUG, "Click registration: End registering click", __FILE__, __LINE__);
        }
    }
    //--------------------------------------------------------------------------
    
    function checkBeforeSaveClick($referrer = '')
    {
        if($this->CampaignCategoryID == '') {
            $this->registratorLog(WLOG_DEBUG, "Click registration: CampaignCategoryID is empty", __FILE__, __LINE__);
            return false;      
        }

        if($this->BannerID == '') {
            $this->registratorLog(WLOG_DEBUG, "Click registration: BannerID is empty", __FILE__, __LINE__);
            return false;      
        }

        if($this->cookieSetReturn == '')
            $this->cookieSetReturn = 99;
        
        if($referrer != '')
            $remoteAddr = $referrer;
        else
            $remoteAddr = $this->cacheParams['HTTP_REFERER'];
        
        $ip = $this->cacheParams['REMOTE_ADDR'];
        
        if($this->ClickTransactionApproval == APPROVE_MANUAL)
            $status = AFFSTATUS_NOTAPPROVED;
        else
            $status = AFFSTATUS_APPROVED;
        
        // check fraud protection
        if($this->DeclineFrequentClicks == 1) {
            if(!$this->applyFraudProtection($ip, $status, $this->cacheParams['time']))
                return false;
        }
        
        $this->registratorLog(WLOG_DEBUG, "Click registration: After fraud protection, OK", __FILE__, __LINE__);

        return array('status' => $status, 'ip' => $ip, 'remoteAddr' => $remoteAddr);
    }
    
    //--------------------------------------------------------------------------
    
    function applyFraudProtection($ip, &$status, $time)
    {
        // find initial click (first non-declined within this day)
        $sql = "select dateinserted as aa from wd_pa_transactions ".
            "where transtype=".TRANSTYPE_CLICK.
            "  and transkind=".TRANSKIND_NORMAL." and ip="._q($ip).
            "  and rstatus<>".AFFSTATUS_SUPPRESSED.
            "  and accountid="._q($this->AccountID).
            "  and (".sqlTimeToSec(date("Y-m-d H:i:s", $time))." - ".sqlTimeToSec('dateinserted')."<".$this->ClickFrequency.")";
        $ret = QCore_Sql_DBUnit::execute($sql, __FILE__, __LINE__);
        if(!$ret) {
            $this->registratorLog(WLOG_ERROR, "Click registration: (fraud protection) Error saving click", __FILE__, __LINE__);
            return false;
        }

        if(!$ret->EOF)
        {
            if($this->FrequentClicks == 2)
            {
                return false;
            }

            // decline the transaction 
            $status = AFFSTATUS_SUPPRESSED;
        }

        return true;
    }
    
    //--------------------------------------------------------------------------
    
    function saveClick($referrer = '')
    {
        if($this->settings['Aff_support_click_commissions'] != 1 && $this->settings['Aff_dont_save_click_transaction'] == 1) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: click not saved - disabled in Settings", __FILE__, __LINE__);
            return true;
        }

        $params = $this->checkBeforeSaveClick($referrer);
        if($params == false) return false;
        
        $status = $params['status'];
        $ip = $params['ip'];
        $remoteAddr = $params['remoteAddr'];
        
        if ($this->cacheParams['subBannerID'] != '') {
            $this->rotatorID = $this->BannerID;
            $this->BannerID  = $this->cacheParams['subBannerID'];
        }
        
        if ($this->updateTransactionLimit(TRANSTYPE_CLICK))
            return false;

        //------------------------------------------
        // register normal commission
        if( ($commission = $this->getCommission()) === false) return false;

        $TransID = QCore_Sql_DBUnit::createUniqueID('wd_pa_transactions', 'transid');
        $sql = "insert into wd_pa_transactions ".
            "(transid, accountid, affiliateid, campcategoryid, bannerid, rotatorid, ".
            " cookiestatus, dateinserted, transtype, transkind, refererurl,".
            " ip, countrycode, rstatus, commission, data1, data2, data3, browser)".
            "values("._q($TransID).","._q($this->AccountID).
            ","._q($this->UserID).","._q($this->CampaignCategoryID).
            ","._q($this->BannerID).","._q($this->rotatorID).","._q($this->cacheParams['cookieSetReturn']).","._q(date("Y-m-d H:i:s", $this->cacheParams['time'])).
            ",".TRANSTYPE_CLICK.",".TRANSKIND_NORMAL.","._q($remoteAddr).
            ","._q($ip).","._q($this->countryCode).","._q($status).","._q($commission).
            ","._q($this->extraData1).","._q($this->extraData2).","._q($this->extraData3).
            ","._q($this->cacheParams['browserHash']).")";

        $ret = QCore_Sql_DBUnit::execute($sql, __FILE__, __LINE__);
        if (!$ret) {
            $this->registratorLog(WLOG_ERROR, "Click registration: Error saving click", __FILE__, __LINE__);
            return false;
        }

        $this->registratorLog(WLOG_DEBUG, "Click registration: After saving click, Start registering multi tier commissions", __FILE__, __LINE__);

        //------------------------------------------
        // register multi tier commissions
        $this->registerMultiTierClickCommission($TransID, $remoteAddr, $ip, $status, $this->UserID, 2);

        $this->registratorLog(WLOG_DEBUG, "Click registration: After registering multi tier commissions", __FILE__, __LINE__);
        
        return true;
    }
    
    //--------------------------------------------------------------------------
    
    function registerMultiTierClickCommission($parentTransID, $remoteAddr, $ip, $status, $parentUserID, $tier, $maxRecursion = 50)
    {
        if($maxRecursion <= 0) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Maximum recursion reached", __FILE__, __LINE__);
            return true;
        }

        if($tier > $this->maxCommissionLevels) {
            $this->registratorLog(WLOG_DEBUG, "Click registration: Maximum tier levels reached", __FILE__, __LINE__);
            return true;
        }
        
        //----------------------------------------
        // get parent user for this child
        $params = array('parentUserID' => $parentUserID, 'status' => $status);

        if(($params = $this->getParentUser($params)) === false) return false;

        $userID = $params['userID'];
        $status = $params['status'];

        $params = array('userID' => $userID, 'tier' => $tier);

        if($this->checkSpecialCommission($params) === false) return false;

        $commission = $this->getCommissionMultiTier(array('tier' => $tier));

        if($commission === false) return false;

        if($commission != 0)
        {
            if ($this->updateTransactionLimit(TRANSTYPE_CLICK))
                return false;
                
            //----------------------------------------
            // register commission
            $TransID = QCore_Sql_DBUnit::createUniqueID('wd_pa_transactions', 'transid');
            $sql = "insert into wd_pa_transactions ".
                "(transid,parenttransid,affiliateid,campcategoryid,bannerid,rotatorid".
                "cookiestatus,dateinserted,transtype,transkind,refererurl,ip,".
                "rstatus,commission,accountid, data1, data2, data3)".
                "values("._q($TransID).","._qOrNull($parentTransID).
                ","._q($userID).","._q($this->CampaignCategoryID).
                ","._q($this->BannerID).","._q($this->rotatorID).","._q($this->cacheParams['cookieSetReturn']).
                ","._q(date("Y-m-d H:i:s", $this->cacheParams['time'])).",".TRANSTYPE_CLICK.",".(TRANSKIND_SECONDTIER+$tier).
                ","._q($remoteAddr).","._q($ip).", "._q($status).
                ","._q($commission).","._q($this->AccountID).","._q($this->extraData1).
                ","._q($this->extraData2).","._q($this->extraData3).")";
                
            $ret = QCore_Sql_DBUnit::execute($sql, __FILE__, __LINE__);
            if (!$ret) {
                $this->registratorLog(WLOG_ERROR, "Click registration: Error saving $tier - tier click commission", __FILE__, __LINE__);
                return false;
            }
            
            $this->multiTierCommissionsCounter++;
            
            $this->registratorLog(WLOG_DEBUG, "Click registration: Saved multi tied commission to transaction ID '$TransID'", __FILE__, __LINE__);
        }
        
        //----------------------------------------
        // go recursively to the next tier
        if($tier < $this->maxCommissionLevels)
        {
            $this->registerMultiTierClickCommission($TransID, $remoteAddr, $ip, $status, $userID, $tier + 1, $maxRecursion -1);          
        }
        
        return true;
    }
    
    //--------------------------------------------------------------------------
    function registratorLog($type, $text, $file, $line) {
        $historyid = QCore_Sql_DBUnit::createUniqueID('wd_g_history', 'historyid');
        $sql = "insert into wd_g_history set ".
                "historyid = '".addslashes($historyid)."',".
                "rtype = '".addslashes($type)."',".
                "accountid = '".$this->AccountID."',".
                "value = '".addslashes($text)."',".
                "dateinserted = '".sqlNow()."',".
                "hfile = '".addslashes($file)."',".
                "line = '".addslashes($line)."',".
                "ip = '".addslashes($_SERVER['REMOTE_ADDR'])."'";                          
        $ret =& QCore_Sql_DBUnit::execute($sql, __FILE__, __LINE__);
    }
}
    
?>
