<?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_Model_Banner extends XenCentral_AdServer_Model_Abstract
{
    public function getUploadConstraints($zone, $finalUpload=false)
    {
        $constraints = array(
                'extensions' => array('png', 'jpg', 'gif'),
                'width'=>0,
                'height'=>0,
                'count'=>3,
                'size'=>0
        );

        if($finalUpload) {
            if ($zone['width']) {
                $constraints['width'] = $zone['width'];
            }

            if ($zone['height']) {
                $constraints['height'] = $zone['height'];
            }
        }


        return $constraints;
    }

    public function deleteAttachmentFile($attachment)
    {
        if(file_exists($file= XenForo_Application::getInstance()->getRootDir() . '/banners/' . $this->_getBannerAttachmentCachedImagePath($attachment))) {
            unlink($file);
            rmdir(dirname($file));
        }
    }

    public function prepareBannerAttachments($attachments)
    {
        return array_map(array($this, 'prepareBannerAttachment'), $attachments);
    }

    public function prepareBannerAttachment($attachment)
    {
        $attachment['thumbnailUrl']=$this->getBannerImageFullUrl(
            $this->_getBannerAttachmentCachedImagePath($attachment)
        );

        $attachment['viewUrl']= $attachment['thumbnailUrl'];

        return $attachment;
    }

    protected function _getBannerAttachmentCachedImagePath($attachment)
    {
        return $attachment['attachment_id'] . '/' . $attachment['filename'];
    }

    public function updateBannerImages($bannerId)
    {
        $attachments=$this->_getAttachmentModel()->getAttachmentsByContentId('banner', $bannerId);

        $images=array();

        foreach ($attachments as $attachment) {
            $filePath = $this->_getAttachmentModel()->getAttachmentDataFilePath($attachment);
            if (file_exists($filePath) && is_readable($filePath)) {
                if(!is_dir($dir=XenForo_Application::getInstance()->getRootDir() . '/banners/' . $attachment['attachment_id'])) {
                    mkdir($dir);
                    chmod($dir, 0777);
                }
                file_put_contents($dir.'/'.$attachment['filename'], file_get_contents($filePath));

                $images[]=$attachment['attachment_id'].'/'.$attachment['filename'];
            }
        }

        if($images) {
            $dw = XenForo_DataWriter::create('XenCentral_AdServer_DataWriter_Banner');
            $dw->setExistingData($bannerId);
            $dw->set('image', serialize($images));
            $dw->save();
        }
    }

    public function prepareForListing($banner)
    {
        if ($banner['active_to']) {
            $banner['active_to_string'] = XenForo_Locale::dateTime($banner['active_to'], 'absolute');
        } else {
            $banner['active_to_string'] = new XenForo_Phrase('n_a');
        }
        if ($banner['active_from']) {
            $banner['active_from_string'] = XenForo_Locale::dateTime($banner['active_from'], 'absolute');
        } else {
            $banner['active_from_string'] = new XenForo_Phrase('n_a');
        }
        if ($banner['status'] == 'active') {
            $banner['status_string'] = new XenForo_Phrase('xcas_active');
        } else if ($banner['status'] == 'moderated') {
            $banner['status_string'] = new XenForo_Phrase('xcas_moderated');
        } else if ($banner['status'] == 'paused') {
            $banner['status_string'] = new XenForo_Phrase('xcas_paused');
        } else {
            if ($banner['active_from'] && $banner['active_from'] > time()) {
                $banner['status'] = 'scheduled';
                $banner['status_string'] = new XenForo_Phrase('xcas_scheduled');
            } else {
                $banner['status_string'] = new XenForo_Phrase('xcas_inactive');
            }
        }

        if ($banner['impressions_left'] > -1) {
            $banner['impressions_left_string'] = $banner['impressions_left'];
        } else {
            $banner['impressions_left_string'] = new XenForo_Phrase('n_a');
        }

        return $banner;
    }

    public function calculateBannerCost(array $banner, XenCentral_AdServer_Zone $zone)
    {
        if ($zone->isCustomZone()) {
            $totalCost = $this->_getPurchaseLogModel()->getTotalPaidCredit($banner['bannerId']);
        } else {
            $totalCost = $this->_getPurchaseLogModel()->getTotalPaid($banner['bannerId'], 'banner');
        }
        $banner['totalCost'] = $totalCost;
        return $banner;
    }

    /**
     * @param $banner
     * @return array
     * Adds CPM/CPC for paid banners
     */
    public function prepareGeneralStats($banner)
    {
        $banner['cpm'] = array(new XenForo_Phrase('n_a'));
        $banner['cpc'] = array(new XenForo_Phrase('n_a'));
        if ($banner['impressions'] OR $banner['clicks']) {
            if (!empty($banner['totalCost'])) {
                $totalCost = $banner['totalCost'];
                if ($banner['impressions'] && !empty($totalCost)) {
                    $banner['cpm'] = array();
                    foreach ($totalCost AS $currency => $amount) {
                        $cpm = round(1000 * $amount / $banner['impressions'], 3);
                        $banner['cpm'][] = $cpm . ' ' . $currency;
                    }
                }

                if ($banner['clicks'] && !empty($totalCost)) {
                    $banner['cpc'] = array();
                    foreach ($totalCost AS $currency => $amount) {
                        $cpm = round($amount / $banner['clicks'], 3);
                        $banner['cpc'][] = $cpm . ' ' . $currency;
                    }
                }
            }
            $banner = $this->prepareBannerCtr($banner);
        }

        return $banner;
    }

    public function sortBannersByCtr($banners)
    {
        $banners = array_map(array($this, 'prepareBannerCtr'), $banners);

        uasort($banners, array($this, '_compareBannerCtr'));

        return $banners;
    }

    protected function _compareBannerCtr($banner1, $banner2)
    {
        return $banner1['ctr_number'] < $banner2['ctr_number'];
    }

    public function prepareBannerCtr($banner)
    {
        if ($banner['impressions']) {
            $banner['ctr_number'] = round(100 * $banner['clicks'] / $banner['impressions'], 4);
            $banner['ctr'] = $banner['ctr_number'] . '%';
        } else {
            $banner['ctr_number'] = 0;
            $banner['ctr'] = new XenForo_Phrase('n_a');
        }

        return $banner;
    }

    /**
     * @param $zoneId
     * @return array
     * Only this method should be used in front-end
     */
    public function getZoneBanners($zoneId)
    {
        $banners = $this->_getCacheModel()->load('xcas_banner_cache_active_grouped');

        if ($banners === false) {
            $this->_updateBannerCache();
            $banners = $this->_getCacheModel()->load('xcas_banner_cache_active_grouped');
        }

        if (isset($banners[$zoneId])) {
            return $banners[$zoneId];
        }

        return array();
    }

    public function getActiveBanners()
    {
        $banners = $this->_getCacheModel()->load('xcas_banner_cache_active');

        if ($banners === false) {
            $this->_updateBannerCache();
            $banners = $this->_getCacheModel()->load('xcas_banner_cache_active');
        }

        return $banners;
    }

    public function getAllBannersFromCache()
    {
        return $this->_getBannerCache();
    }

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

        if(!$banners) {
            return array();
        }

        foreach ($banners AS $bannerId => $banner) {
            $users = explode(',', $banner['user_id']);
            if (!$banner['user_id'] OR !(in_array($userId, $users))) {
                unset($banners[$bannerId]);
            }
        }

        return $banners;
    }

    public function getAllBanners()
    {
        return $this->fetchAllKeyed("
            SELECT banner.*, user.username, stats.*
            FROM xcas_banner AS banner
            INNER JOIN xcas_zone AS zone USING(zoneId)
            LEFT JOIN xf_user AS user USING(user_id)
            LEFT JOIN xcas_stats_summary AS stats ON stats.content_type='banner' AND stats.content_id=banner.bannerId
            ORDER BY zone.title ASC, banner.active DESC, banner.display_order ASC
        ", 'bannerId');
    }

    /**
     * @param $bannerId
     * @return array
     * Method should be used by admin manager only
     */
    public function getBannerById($bannerId)
    {
        return $this->_getDb()->fetchRow("
            SELECT banner.*
            FROM xcas_banner AS banner
            LEFT JOIN xcas_zone AS zone USING(zoneId)
            WHERE bannerId=?
        ", array($bannerId));
    }

    /**
     * @return array
     * Method should be used by admin manager only
     */
    public function getDefaultBanner()
    {
        return array(
                'title' => '',
                'display_order' => 10,
                'tags' => '',
                'status' => 'active',
                'code' => $this->getDefaultCode('image'),
                'mobile_view_code' => $this->getDefaultMobileCode('image'),
                'tablet_view_code' => $this->getDefaultTabletCode('image'),
                'impressions_left' => -1,
                'active' => 1
        );
    }

    public function getDefaultCode($type)
    {
        switch ($type) {
            case 'image':
                return new XenForo_Phrase('xcas_default_banner_code');
                break;
            case 'text':
                return new XenForo_Phrase('xcas_default_text_banner_code');
                break;
        }
        return '';
    }

    public function getDefaultMobileCode($type)
    {
        switch ($type) {
            case 'image':
                return new XenForo_Phrase('xcas_default_banner_mobile_code');
                break;
            case 'text':
                return new XenForo_Phrase('xcas_default_text_banner_mobile_code');
                break;
        }
        return '';
    }

    public function getDefaultTabletCode($type)
    {
        switch ($type) {
            case 'image':
                return new XenForo_Phrase('xcas_default_banner_tablet_code');
                break;
            case 'text':
                return new XenForo_Phrase('xcas_default_text_banner_tablet_code');
                break;
        }
        return '';
    }

    public function updateCache()
    {
        $this->_updateBannerCache();
    }

    public function saveImage(XenForo_Upload $image)
    {
        $path = $this->_getImagePath();

        if (!is_writable(XenForo_Application::getInstance()->getRootDir() . '/' . $path)) {
            throw new XenForo_Exception("Directory $path is not writable. Please make it writable and try again.");
        }

        $uniqueId = uniqid();
        $path = XenForo_Application::getInstance()->getRootDir() . '/' . $path . '/' . $uniqueId;

        mkdir($path, 0777);
        chmod($path, 0777);

        if (file_exists($path . '/' . $image->getFileName())) {
            @unlink($path . '/' . $image->getFileName());
        }

        copy($image->getTempFile(), $path . '/' . $image->getFileName());

        return $uniqueId . '/' . $image->getFileName();
    }

    public function deleteBannerImage($imagePath)
    {
        $path = $this->_getImagePath();
        $path = XenForo_Application::getInstance()->getRootDir() . '/' . $path . '/' . $imagePath;
        if (is_file($path)) {
            @unlink($path);
        }
        // try to delete unused directory as well
        if(is_dir(dirname($path))) {
            @rmdir(dirname($path));
        }

        return;
    }

    public function getScriptHtml($banner, $varName, $skipZone = false)
    {
        $banner=$this->prepareBanner($banner);
        $bannerHtml = $this->getBannerHtml($banner, $skipZone);

        if (!$bannerHtml) {
            return false;
        }

        $bannerHtml = explode("\n", $bannerHtml);
        $bannerHtml = array_map('trim', $bannerHtml);

        $script = '';
        foreach ($bannerHtml AS $line) {
            $line = str_replace('\'', '\\\'', $line);
            $script .= "$varName+='$line';";
        }
        return $script;
    }

    public function  getBannerHtmlCode($banner, $html)
    {
        static $tablet, $mobile;
        if (is_null($tablet)) {
            require_once XenForo_Application::getInstance()->getRootDir() . '/library/XenCentral/Framework/Resources/MobileDetect.php';

            $mobile = XenForo_Visitor::isBrowsingWith('mobile');
            $tabletDetect = new Mobile_Detect();
            $tablet = $tabletDetect->isTablet();
        }

        if ($tablet AND $banner['tablet_view_code']) {
            $html = $banner['tablet_view_code'];
        } elseif ($mobile AND $banner['mobile_view_code']) {
            $html = $banner['mobile_view_code'];
        }
        return $html;
    }

    public function prepareBannerForDelivery($banner, $skipZone=false, $args=array())
    {
        if ($banner['url'] && empty($banner['url_prepared'])) {
            $banner['url'] = XenForo_Link::buildPublicLink('full:ads/redirect', null, array('bannerId' => $banner['bannerId'], 'url' => $banner['url'], 'skipZone' => $skipZone)+$args);
            $banner['url_prepared'] = true;
        }

        return $banner;
    }

    public function getBannerHtml($banner, $skipZone = false)
    {
        $skipZone = $skipZone ? 1 : 0;
        $html = $banner['code'];
        $html = $this->getBannerHtmlCode($banner, $html);
        if (!empty($banner['randomImage'])) {
            $html = str_replace('{image}', $banner['randomImage'], $html);
        }

        if ($banner['url']) {
            $banner=$this->prepareBannerForDelivery($banner, $skipZone);
            $html = str_replace('{url}', $banner['url'], $html);
        }

        if ($banner['text']) {
            $html = str_replace('{text}', htmlspecialchars($banner['text']), $html);
        }

        return $html;
    }

    protected function _getImagePath()
    {
        return 'banners';
    }

    protected function _getBannerCache()
    {
        static $cache;

        if (is_array($cache)) {
            return $cache;
        }

        $cache = $this->_getCacheModel()->load('xcas_banner_cache');

        if ($cache === false) {
            $this->_updateBannerCache();
            $cache = $this->_getCacheModel()->load('xcas_banner_cache');
        }

        return $cache;
    }

    protected function _updateBannerCache()
    {
        $banners = $this->getAllBanners();

        $banners = array_map(array($this, 'prepareBanner'), $banners);

        $this->_getCacheModel()->save($banners, 'xcas_banner_cache', array(), 999999);

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

        $this->_getCacheModel()->save($banners, 'xcas_banner_cache_active', array(), 999999);

        $zoneGrouped = array();

        foreach ($banners as $bannerId => $banner) {
            $zoneGrouped[$banner['zoneId']][$bannerId] = $banner;
        }

        $this->_getCacheModel()->save($zoneGrouped, 'xcas_banner_cache_active_grouped', array(), 999999);
    }

    public function prepareBanners($banners)
    {
        return array_map(array($this, 'prepareBanner'), $banners);
    }

    public function getBannerImageFullUrl($imagePath)
    {
        $cdn = XenForo_Application::getOptions()->get('xcas_cdn_url');

        if (!$cdn) {
            $cdn = XenForo_Application::getOptions()->get('boardUrl');
        }

        return $cdn.'/banners/'.$imagePath;
    }
    
    public function prepareBanner($banner)
    {
        if (!empty($banner['prepared'])) {
            return $banner;
        }

        $banner['randomImage']='';
        $banner['oldImageArray']=array();

        if ($banner['image']) {
            try {
                $image = @unserialize($banner['image']);
                if(is_array($image)) {
                    shuffle($image);
                    $banner['randomImage'] = array_shift($image);
                } else {
                    $image = explode('>%+=+$>', $banner['image']);
                    $image = array_diff($image, array(''));
                    $banner['oldImageArray'] = $image;
                    shuffle($image);
                    $banner['randomImage'] = array_shift($image);
                }

            } catch(Exception $ex) {
                $image=explode('>%+=+$>', $banner['image']);
                $image=array_diff($image, array(''));
                $banner['oldImageArray'] = $image;
                shuffle($image);
                $banner['randomImage'] = array_shift($image);
            }


            $banner['randomImage']=$this->getBannerImageFullUrl($banner['randomImage']);
        }

        if (!empty($banner['tags'])) {
            try {
                $banner['tagData'] = @unserialize($banner['tags']);
            } catch(Exception $ex) {
                $banner['tagData']=array();
            }

            $tags = array();

            foreach ($banner['tagData'] AS $tag) {
                $tags[] = $tag['tag'];
            }
            $banner['tagList'] = implode(',', $tags);
        } else {
            $banner['tagData'] = array();
            $banner['tagList'] = '';
        }


        $banner['bannerHtml']=$this->getBannerHtml($banner);

        return $banner;
    }

    public function canEditTags(array $banner = null, array $viewingUser = null)
    {
        if (!XenForo_Application::getOptions()->enableTagging) {
            return false;
        }

        $this->standardizeViewingUserReference($viewingUser);

        if (empty($banner['bannerId'])) {
            return true;
        }

        return true;
    }

    public function getAllBannerTags()
    {
        return $this->fetchAllKeyed('
            SELECT tag.tag_id, tag.tag, tag.tag_url, COUNT(banner.bannerId) AS bannerCount
            FROM xf_tag AS tag
            INNER JOIN xf_tag_content AS tag_content ON tag_content.tag_id=tag.tag_id AND tag_content.content_type=?
            INNER JOIN xcas_banner AS banner ON banner.bannerId=tag_content.content_id
            INNER JOIN xcas_zone AS zone ON zone.zoneId=banner.zoneId
            WHERE banner.active=1
            AND banner.status=?
            AND zone.owners!=\'\'
            GROUP BY tag.tag_id
            ORDER BY tag.tag ASC
        ',
                'tag_id',
                array('banner', 'active')
        );
    }

    /**
     * @return XenCentral_Framework_Model_Cache
     */
    protected function _getCacheModel()
    {
        return $this->getModelFromCache('XenCentral_Framework_Model_Cache');
    }

    /**
     * @return XenForo_Model_Attachment
     */
    protected function _getAttachmentModel()
    {
        return $this->getModelFromCache('XenForo_Model_Attachment');
    }


}