<?php
/**
* @package XenCentral Ad Server
* @author Skydevelop EU
* @copyright Drnoyan & Nalyan LDA, Portugal, EU
* @license http://www.dnf.pt/eula.html
* @link http://www.skydevelop.com
* @revision 97
* @version 2.0.0 beta 3 rev. 3
*/

class XenCentral_AdServer_Zone implements ArrayAccess
{
    protected $zoneInfo;

    protected $prepared=false;

    public function __construct($zoneInfo)
    {
        $this->zoneInfo=$zoneInfo;
    }

    public function addBanner($banner)
    {
        if(empty($this->zoneInfo['banners'])) {
            $this->zoneInfo['banners']=array();
        }

        $this->zoneInfo['banners'][$banner['bannerId']]=$banner;
    }

    public function prepareZoneInformation()
    {
        if($this->prepared) {
            return;
        }

        $this->prepared=true;
        // set defaults
        $this->zoneInfo['first_expire_date'] = new XenForo_Phrase('n_a');
        $this->zoneInfo['free_slots']= new XenForo_Phrase('n_a');
        if($this->isUserZone()) {
            $banners=$this->getRunningUserBanners();
            $this->zoneInfo['free_slots']=max(0, $this->zoneInfo['slot_count']-count($banners));
            if($this->zoneInfo['free_slots']==0 AND $this->zoneInfo['slot_count']) {
                // all slots are busy, show next expiration date
                $expirationDate=0;
                foreach($banners AS $banner) {
                    if($banner['active_to']) {
                        if(!$expirationDate) {
                            $expirationDate=$banner['active_to'];
                        } else {
                            $expirationDate=min($expirationDate, $banner['active_to']);
                        }
                    }
                }
                if($expirationDate) {
                    $this->zoneInfo['first_expire_date']=XenForo_Locale::dateTime($expirationDate, 'absolute');
                }
            }
        } else {
            $this->zoneInfo['slot_count'] = new XenForo_Phrase('n_a');
        }
        if($this->zoneInfo['running_time']) {
            $this->zoneInfo['average_impressions']= round($this->zoneInfo['impressions']*86400/ $this->zoneInfo['running_time'], 1);
        } else {
            $this->zoneInfo['average_impressions']=new XenForo_Phrase('n_a');
        }
        if($this->zoneInfo['impressions']) {
            $this->zoneInfo['ctr_number'] =round(100*$this->zoneInfo['clicks']/ $this->zoneInfo['impressions'], 4);
            $this->zoneInfo['ctr'] = $this->zoneInfo['impressions'].'%';
        } else {
            $this->zoneInfo['ctr']=new XenForo_Phrase('n_a');
            $this->zoneInfo['ctr_number']=0;
        }
    }

    public function getRunningUserBanners()
    {
        $activeBanners=$this->getActiveUserBanners();
        foreach($activeBanners AS $bannerId=>$banner) {
            if($banner['status']!='active') {
                unset($activeBanners[$bannerId]);
            }
        }
        return $activeBanners;
    }

    public function getFreeSlots()
    {
        $this->prepareZoneInformation();
        return $this->zoneInfo['free_slots'];
    }

    public function getFirstExpirationDate()
    {
        $this->prepareZoneInformation();
        return $this->zoneInfo['first_expire_date'];
    }

    public function getActiveBanners()
    {
        $banners = $this->getBannerModel()->getZoneBanners($this->getZoneId());

        return $banners;
    }

    public function getSafeModeBanners()
    {
        $banners=$this->getActiveBanners();

        foreach($banners AS $bannerId=>$banner) {
            if(!$banner['safe_mode']) {
                unset($banners[$bannerId]);
            }
        }

        return $banners;
    }

    public function getActiveUserBanners()
    {
        $banners = $this->getActiveBanners();

        foreach($banners AS $bannerId=>$banner) {
            if(!$banner['user_id']) {
                unset($banners[$bannerId]);
            }
        }

        return $banners;
    }

    public function getCostPerClick()
    {
        // per zone configuration disabled, return XenForo option
        return XenForo_Application::getOptions()->get('xcas_default_price_per_click');
    }

    public function getZoneOwners()
    {
        static $users=array();

        $foundUsers = $notFoundUsers = array();

        foreach(explode(',', $this->get('owners')) AS $user_id) {
            if(!$user_id) {
                continue;
            }

            if(isset($users[$user_id])) {
                $foundUsers[$user_id]=$users[$user_id];
            } else {
                $notFoundUsers[]=$user_id;
            }
        }

        if(!empty($notFoundUsers)) {
            $notFoundUsers=$this->getUserModel()->getAdServerUsers($notFoundUsers);
            $users+=$notFoundUsers;
            $foundUsers+=$notFoundUsers;
        }

        return $foundUsers;
    }

    public function isServerDomain($referer)
    {
        return self::refererMatchesWebsite($referer, XenForo_Application::getOptions()->get('boardUrl'));
    }

    public function isValidHttpReferer($referer)
    {
        if(!$referer) {
            return false;
        }

        if($this->isServerDomain($referer)) {
            return true;
        }

        $owners=$this->getZoneOwners();

        $itemFound=false;

        foreach($owners AS $owner) {
            foreach ($owner['excluded_campaign_domains'] as $disabledSite) {
                if(trim($disabledSite)) {
                    if (XenCentral_AdServer_Zone::refererMatchesWebsite($referer, $disabledSite)) {
                        return false;
                    }
                }
            }
        }

        // no websites excluded
        return true;
    }

    public static function refererMatchesWebsite($referer, $website)
    {
        $refererDomain = parse_url($referer, PHP_URL_HOST);
        $refererPath = trim(parse_url($referer, PHP_URL_PATH), '/');

        $enabledSiteDomain = parse_url($website, PHP_URL_HOST);
        $enabledSitePath = trim(parse_url($website, PHP_URL_PATH), '/');

        if (strtolower($refererDomain) == strtolower($enabledSiteDomain)) {
            if ($refererPath AND $enabledSitePath) {
                if (stripos($refererPath, $enabledSitePath) === 0) {
                    return true;
                }
            } else {
                return true;
            }
        }

        return false;
    }

    public function getActiveOwnerUserInfo($minCredit=null)
    {
        static $activeOwners=array();
        if(!isset($activeOwners[$this->getZoneId()])) {
            $activeOwners[$this->getZoneId()]= $this->getUserModel()->getActiveCampaignOwner($this->get('owners'), $minCredit);
        }

        return $activeOwners[$this->getZoneId()];
    }

    public function getZoneInfo()
    {
        return $this->zoneInfo;
    }

    public function getZoneId()
    {
        return $this->zoneInfo['zoneId'];
    }

    public function isUserZone()
    {
        return $this->zoneInfo['user_zone'];
    }

    public function isCustomZone()
    {
        return !empty($this->zoneInfo['owners']);
    }

    public function isZoneOwner($user_id)
    {
        return in_array($user_id, explode(',', $this->zoneInfo['owners']));
    }

    public function isActive()
    {
        return $this->zoneInfo['active'];
    }

    public function rotateBanners()
    {
        return $this->zoneInfo['rotate'];
    }

    public function randomizeBanners()
    {
        return $this->zoneInfo['randomize_banners'];
    }


    public function rotateZone()
    {
        return $this->zoneInfo['rotate_zone'];
    }

    public function getAutoRotateInterval()
    {
        return $this->zoneInfo['auto_rotate'];
    }

    public function getZoneWidth()
    {
        return $this->zoneInfo['width'];
    }

    public function getZoneHeight()
    {
        return $this->zoneInfo['height'];
    }



    /**
     * @param $locationId
     * @return bool
     * Returns if particular location is activated for given zone
     */
    public function hasLocation($locationId)
    {
        return !empty($this->zoneInfo['locations'][$locationId]['active']);
    }

    /**
     * @param $locationId
     * @return array
     * Returns location information saved for this zone particularly in Admin form
     */
    public function getLocationData($locationId)
    {
        return $this->zoneInfo['locations'][$locationId];
    }

    public static function getRandomId()
    {
        static $cached=array();

        $randomId='';

        while(true) {
            $randomId = 'z_' . intval(rand(1, 100));
            if(!in_array($randomId, $cached)) {
                $cached[]=$randomId;
                break;
            }
        }

        return $randomId;
    }

    /**
     * @return XenCentral_AdServer_Model_Banner
     */
    protected function getBannerModel()
    {
        static $bannerModel;
        if(is_null($bannerModel)) {
            $bannerModel=XenForo_Model::create('XenCentral_AdServer_Model_Banner');
        }

        return $bannerModel;
    }

    /**
     * @return XenCentral_AdServer_Model_XenForo_User
     */
    protected function getUserModel()
    {
        static $userModel;
        if(is_null($userModel)) {
            $userModel=XenForo_Model::create('XenForo_Model_User');
        }

        return $userModel;
    }



    public function get($offset)
    {
        if(isset($this->zoneInfo[$offset])) {
            return $this->zoneInfo[$offset];
        }
        return false;
    }
    

    /**
     * For ArrayAccess.
     *
     * @param string $offset
     */
    public function offsetExists($offset)
    {
        return isset($this->zoneInfo[$offset]);
    }

    /**
     * For ArrayAccess.
     *
     * @param string $offset
     */
    public function offsetGet($offset)
    {
        return $this->zoneInfo[$offset];
    }

    /**
     * For ArrayAccess.
     *
     * @param string $offset
     * @param mixed $value
     */
    public function offsetSet($offset, $value)
    {
        $this->zoneInfo[$offset] = $value;
    }

    /**
     * For ArrayAccess.
     *
     * @param string $offset
     */
    public function offsetUnset($offset)
    {
        unset($this->zoneInfo[$offset]);
    }

    /**
     * Magic method for array access
     */
    public function __get($name)
    {
        return $this->get($name);
    }
}