<?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_Zone extends XenCentral_AdServer_Model_Abstract
{
    public static $zoneCache;

    protected static $placeHolders = array();

    protected static $safeModePlaceholders = array();

    public function getAttachmentParams($zone, array $contentData, $tempHash = null)
    {
        $existing = is_string($tempHash) && strlen($tempHash) == 32;
        $output = array(
                'hash' => $existing ? $tempHash : md5(uniqid('', true)),
                'content_type' => 'banner',
                'content_data' => $contentData
        );

        if ($existing) {
            $attachmentModel = $this->getModelFromCache('XenForo_Model_Attachment');
            $output['attachments'] = $attachmentModel->prepareAttachments(
                    $attachmentModel->getAttachmentsByTempHash($tempHash)
            );
        }

        return $output;
    }

    public static function getZonePlaceholder($zoneData, $safeMode = false)
    {
        $randomId = $zoneData['randomId'];
        $placeholder = '<!-- zp-' . $randomId . '-zp -->';
        self::$placeHolders[$placeholder] = $zoneData;

        if ($safeMode) {
            self::$safeModePlaceholders[$placeholder] = true;
        }

        return $placeholder;
    }

    public function processPlaceholders(XenForo_Template_Abstract $template, &$content)
    {
        static $requestId;
        if (is_null($requestId)) {
            $requestId = uniqid();
        }

        if (empty(self::$placeHolders)) {
            return;
        }

        $bannerImpressions = array();
        $zoneImpressions = array();
        $find = $replace = array();
        $zones = $this->getActiveZones();

        $bR = array();

        foreach (self::$placeHolders AS $placeholder => $zoneData) {
            $safeModeBanners = array();
            $minWidth = 0;
            $minHeight = 0;
            $usePlaceholder = true;
            foreach ($zoneData['zones'] AS $index => $zoneId) {
                if (empty(self::$zoneCache[$zoneId])) {
                    unset($zoneData['zones'][$index]);
                    continue;
                }
                if (empty(self::$safeModePlaceholders[$placeholder])) {
                    $zoneSafeModeBanners = $zones[$zoneId]->getSafeModeBanners();
                } else {
                    $zoneSafeModeBanners = $zones[$zoneId]->getActiveBanners();
                }

                $minWidth = max($minWidth, $zones[$zoneId]->getZoneWidth());
                $minHeight = max($minHeight, $zones[$zoneId]->getZoneHeight());

                if ($zones[$zoneId]['use_placeholder'] == false) {
                    $usePlaceholder = false;
                }

                foreach ($zoneSafeModeBanners AS $bannerId => $banner) {
                    if (!$this->_getCappingModel()->displayBanner($banner['bannerId'])) {
                        unset($zoneSafeModeBanners[$bannerId]);
                    }
                }

                if ($zones[$zoneId]->rotateBanners() AND $zoneSafeModeBanners) {
                    $allBanners = $zones[$zoneId]->getActiveBanners();
                    $randomBanner = $allBanners[array_rand($allBanners)];
                    if ($randomBanner['safe_mode'] OR !empty(self::$safeModePlaceholders[$placeholder])) {
                        $zoneSafeModeBanners = array(
                                $zoneSafeModeBanners[array_rand($zoneSafeModeBanners)]
                        );
                    } else {
                        $zoneSafeModeBanners = array();
                    }
                }
                $safeModeBanners = array_merge($safeModeBanners, $zoneSafeModeBanners);
            }
            if (empty($zoneData['zones']) OR XenCentral_AdServer_Permissions::isExcludedUsergroup()) {
                // no zone passed criteria
                $replacement = '';
            } else {
                $zoneData['linkParams']['zones'] = implode(',', $zoneData['zones']);
                $safeModeLoaded = array();
                $bannerContent = "";
                foreach ($safeModeBanners AS $banner) {
                    $bannerImpressions[] = $banner['bannerId'];
                    $zoneImpressions[] = $banner['zoneId'];
                    $this->_getCappingModel()->saveBannerImpression($banner['bannerId']);
                    $bannerContent .= $this->_getBannerModel()->getBannerHtml($banner);
                    $safeModeLoaded[] = $banner['bannerId'];
                }

                $zoneData['linkParams']['safeModeLoaded'] = implode(',', $safeModeLoaded);
                $zoneData['linkParams']['requestId'] = $requestId;

                $reloadSrc = XenForo_Link::buildPublicLink(
                        'ads/delivery', null, $zoneData['linkParams']
                );

                unset($zoneData['linkParams']['requestId']);

                $bR[$zoneData['randomId']] = $zoneData['linkParams'];

                $replacement = $template->create('xcas_zone_code', array(
                                'randomId' => $zoneData['randomId'],
                                'src' => '',
                                'reloadSrc' => $reloadSrc,
                                'includeScript' => false,
                                'bannerContent' => $bannerContent,
                                'width' => $minWidth,
                                'height' => $minHeight,
                                'usePlaceholder' => $usePlaceholder
                        )
                );

                foreach ($zoneData['wrappers'] AS $wrapperName) {
                    $replacement = $template->create($wrapperName, array('zoneContent' => $replacement));
                }
            }
            $find[] = $placeholder;
            $replace[] = $replacement;
        }

        if (!empty($find)) {
            $content = str_replace($find, $replace, $content);
        }

        if (!empty($bR)) {
            $scriptHtml = $template->create('xcas_request_script_code', array(
                    'src' => XenForo_Link::buildPublicLink(
                            'ads/delivery', null, array('requestId' => $requestId, 'bR' => $bR)
                    )
            ));

            if (strpos($content, '</body>') !== false) {
                $content = str_replace('</body>', $scriptHtml . '</body>', $content);
            } else {
                $content .= $scriptHtml;
            }
        }

        self::$placeHolders = array();

        $this->_getStatsModel()->storeImpressionLogs($bannerImpressions, $zoneImpressions);
    }

    /**
     * @param $userId
     * @return XenCentral_AdServer_Zone[] Returns prepared zone objects including website zones only
     * Returns prepared zone objects including website zones only
     */
    public function getAvailableCustomZones($userId = false)
    {
        /** @var XenCentral_AdServer_Zone[] $zones */
        $zones = $this->getCache();

        foreach ($zones AS $zoneId => $zone) {
            $zone = $this->createZoneObject($zone);
            if (
                    $zone->isCustomZone() == false
                    OR (
                            $userId
                            AND
                            $zone->isZoneOwner($userId) == false
                    )
            ) {
                unset($zones[$zoneId]);
                continue;
            }

            $zone->prepareZoneInformation();

            $zones[$zoneId] = $zone;
        }

        return $zones;
    }

    protected function _prepareLocalZoneCache()
    {
        if (is_null(self::$zoneCache)) {
            $zones = $this->getActiveZones();
            self::$zoneCache = &$zones;
        }
    }


    public function applyPageFilters($params, $containerData)
    {
        $this->_prepareLocalZoneCache();

        static $filtersApplied;
        if (!is_null($filtersApplied)) {
            return;
        }

        $zoneKeys = array_keys(self::$zoneCache);

        foreach ($zoneKeys AS $zoneId) {
            if (!XenForo_Helper_Criteria::pageMatchesCriteria(self::$zoneCache[$zoneId]['page_criteria'], true, $params, $containerData)) {
                unset(self::$zoneCache[$zoneId]);
            } else if (!empty(self::$zoneCache[$zoneId]['page_criteria_not']) AND XenForo_Helper_Criteria::pageMatchesCriteria(self::$zoneCache[$zoneId]['page_criteria_not'], true,
                            $params, $containerData)
            ) {
                unset(self::$zoneCache[$zoneId]);
            }
        }
    }

    public function applyUserFilters($user)
    {
        static $filtersApplied;
        if (!is_null($filtersApplied)) {
            return;
        }

        $this->_prepareLocalZoneCache();

        $filtersApplied = true;

        $zoneKeys = array_keys(self::$zoneCache);

        foreach ($zoneKeys AS $zoneId) {
            if (!XenForo_Helper_Criteria::userMatchesCriteria(self::$zoneCache[$zoneId]['user_criteria'], true, $user)) {
                unset(self::$zoneCache[$zoneId]);
            } else if (self::$zoneCache[$zoneId]['user_criteria_not'] AND XenForo_Helper_Criteria::userMatchesCriteria(self::$zoneCache[$zoneId]['user_criteria_not'], true,
                            $user)
            ) {
                unset(self::$zoneCache[$zoneId]);
            }
        }
    }

    public function getZoneOptions($zones = null)
    {
        if (is_null($zones)) {
            $zones = $this->getAllActiveZones();
        }

        $options = array();

        foreach ($zones AS $zone) {
            if ($zone['width'] AND $zone['height']) {
                $zone['title'] .= ' (' . $zone['width'] . 'x' . $zone['height'] . ')';
            }
            if ($zone->isUserZone()) {
                if (isset($zone['free_slots'])) {
                    $zone['title'] = new XenForo_Phrase('xcas_zone_title_x_slots', array(
                            'title' => $zone['title'],
                            'x' => $zone['free_slots']
                    ));
                }
                if (isset($zone['first_expire_date'])) {
                    $zone['title'] = new XenForo_Phrase('xcas_zone_title_x_expire_date', array(
                            'title' => $zone['title'],
                            'x' => $zone['first_expire_date']
                    ));
                }
            }

            $options[$zone['zoneId']] = $zone['title'];
        }

        return $options;
    }

    public function updateCache()
    {
        $zones = $this->getAllZones(false);

        /** @var XenCentral_AdServer_Zone[] $zoneObjects */
        $zoneObjects = array();

        foreach ($zones AS $zone) {
            $zoneObject = $this->createZoneObject($zone);
            $zoneObjects[$zoneObject->getZoneId()] = $zoneObject;
            $zoneObjectsAll[$zoneObject->getZoneId()] = $zoneObject;
        }

        $this->_getCacheModel()->save($zones, 'xcas_zone_cache', array(), 999999);

        $hookCache = array();

        $customHookLocation = XenCentral_AdServer_LocationList::getInstance()->getCustomHookLocation();
        $customHookLocationId = $customHookLocation->getLocationId();

        $allActiveZones = array();

        foreach ($zoneObjects AS $index => $zone) {
            $zoneObject = $zoneObjects[$index];
            if (!$zoneObject->isActive()) {
                unset($zones[$index]);
                continue;
            }

            $allActiveZones[$index] = $zones[$index];

            $zoneBanners = $zoneObject->getActiveBanners();
            if (empty($zoneBanners)) {
                unset($zones[$index]);
                continue;
            }

            if (is_array($zoneObject['locations'])) {
                foreach ($zoneObject['locations'] as $locationId => $locationInfo) {
                    if ($locationId == $customHookLocationId) {
                        foreach ($locationInfo AS $locationHookInfo) {
                            foreach ($locationHookInfo AS $ii => $v) {
                                if ($v['hook_name']) {
                                    $hookCache[$v['hook_name']][$zoneObject->getZoneId()] = $zoneObject->getZoneId();
                                }
                            }
                        }
                    } else {
                        $locationObject = XenCentral_AdServer_LocationList::getInstance()->getLocationById($locationId);
                        if ($locationObject AND $locationObject instanceof XenCentral_AdServer_Locations_Hooks_Abstract) {
                            $locationId = $locationObject->getHookName();
                            if (!isset($hookCache[$locationId])) {
                                $hookCache[$locationId] = array();
                            }

                            if (!in_array($zoneObject->getZoneId(), $hookCache[$locationId])) {
                                $hookCache[$locationId][] = $zoneObject->getZoneId();
                            }
                        }
                    }
                }
            }
        }

        $this->_getCacheModel()->save($zones, 'xcas_zone_cache_active', array(), 999999);
        $this->_getCacheModel()->save($allActiveZones, 'xcas_zone_cache_active_all', array(), 999999);

        $this->_getCacheModel()->save($hookCache, 'xcas_zone_cache_hook', array(), 999999);
    }

    public function getCache()
    {
        static $cache;

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

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

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

        return $cache;
    }

    protected function getActiveCache()
    {
        static $cache;

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

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

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

        return $cache;
    }

    protected function getAllActiveCache()
    {
        static $cache;

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

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

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

        return $cache;
    }

    public function getHookRelatedZones($hook_name)
    {
        $cache = $this->_getCacheModel()->load('xcas_zone_cache_hook');

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

        if (empty($cache[$hook_name])) {
            return array();
        }

        return $cache[$hook_name];
    }

    /**
     * @param bool $prepare
     * @return XenCentral_AdServer_Zone[]
     * Does not return zones not having any banners
     */
    public function getActiveZones($prepare = false)
    {
        $zoneCache = $this->getActiveCache();

        $zoneCache = array_map(array($this, 'createZoneObject'), $zoneCache);

        if ($prepare) {
            foreach ($zoneCache AS $index => $zone) {
                $zone->prepareZoneInformation();
            }
        }

        return $zoneCache;
    }

    /**
     * @param bool $prepare
     * @return XenCentral_AdServer_Zone[]
     * Returns all active zones, including the ones not having banners, which is not the case with @getActiveZones method
     */
    public function getAllActiveZones($prepare = false)
    {
        $zoneCache = $this->getAllActiveCache();

        $zoneCache = array_map(array($this, 'createZoneObject'), $zoneCache);

        if ($prepare) {
            foreach ($zoneCache AS $index => $zone) {
                $zone->prepareZoneInformation();
            }
        }

        return $zoneCache;
    }

    /**
     * @param $zoneArray
     * @return XenCentral_AdServer_Zone
     * @throws Exception
     */
    public function createZoneObject($zoneArray)
    {
        $zoneArray = $this->prepareZone($zoneArray);
        $class = 'XenCentral_AdServer_Zone';
        $class = XenForo_Application::resolveDynamicClass($class);
        return new $class($zoneArray);
    }

    /**
     * @return XenCentral_AdServer_Zone[]
     */
    public function getUserZones()
    {
        $zones = $this->getAllActiveZones();

        foreach ($zones AS $index => $zone) {
            if (!$zone->isUserZone()) {
                unset($zones[$index]);
            }
            $zone->prepareZoneInformation();
        }

        return $zones;
    }

    /**
     * @param $user_id
     * @return XenCentral_AdServer_Zone[]
     */
    public function getCustomZones($user_id)
    {
        $zones = $this->getAllActiveZones();

        foreach ($zones AS $index => $zone) {
            if (!$zone->isCustomZone()
                    OR $zone->isZoneOwner($user_id) == false
            ) {
                unset($zones[$index]);
                continue;
            }

            $zone->prepareZoneInformation();
        }

        return $zones;
    }

    /**
     * @param XenForo_Upload $image
     * @param $zoneId
     * @return array
     * @deprecated
     */
    public function validateImage($image, $zoneId)
    {
        throw new Exception("Method should not be called");
    }

    public function preparePackages($packages)
    {
        foreach ($packages AS &$package) {
            $cost = $package['price'] . ' ' . $package['currency'];
            $postfix = $package['length'] != 1 ? 's' : '';
            $name = new XenForo_Phrase('xcas_x_for_y_z', array(
                    'x' => $cost,
                    'y' => $package['length'],
                    'z' => new XenForo_Phrase('xcas_' . $package['unit'] . $postfix)
            ));
            $package['fullName'] = $name;
            $package['unit_string'] = new XenForo_Phrase('xcas_' . $package['unit'] . $postfix);
        }

        return $packages;
    }

    public function getAvailableHooks($query)
    {
        $allHooks = $this->_getCacheModel()->load('xcas_all_hooks');
        if ($allHooks === false) {
            $templates = $this->_getDb()->fetchAll("
                SELECT title, template_parsed
                FROM xf_template
                WHERE style_id=0
                AND template LIKE '%xen:hook%'
            ");
            $allHooks = array();
            foreach ($templates AS $template) {
                $templateParsed = unserialize($template['template_parsed']);
                foreach ($templateParsed AS $index => $tag) {
                    if (
                            is_array($tag)
                            AND $tag['name'] == 'hook'
                    ) {
                        if (isset($allHooks[$tag['attributes']['name'][0]])) {
                            $allHooks[$tag['attributes']['name'][0]] = (new XenForo_Phrase('xcas_x_hook_in_y_template', array(
                                            'hookName' => $tag['attributes']['name'][0],
                                            'templateName' => new XenForo_Phrase('xcas_multiple_templates')
                                    ))) . '';
                        } else {
                            $allHooks[$tag['attributes']['name'][0]] = (new XenForo_Phrase('xcas_x_hook_in_y_template', array(
                                            'hookName' => $tag['attributes']['name'][0],
                                            'templateName' => $template['title']
                                    ))) . '';
                        }
                    }
                }
            }
            $this->_getCacheModel()->save($allHooks, 'xcas_all_hooks', array(), 120);
        }

        foreach ($allHooks AS $hookName => $title) {
            if (stripos($hookName, $query) === false) {
                unset($allHooks[$hookName]);
            }
        }

        return $allHooks;
    }

    /**
     * @return XenCentral_AdServer_Zone[]
     */
    protected function _getAllZones()
    {
        return $this->getCache();
    }

    public function getDefaultZone()
    {
        return array(
                'zoneId' => 0,
                'title' => '',
                'locations' => array(),
                'active' => 1,
                'width' => '',
                'height' => '',
                'slot_count' => 0,
                'user_zone' => 0,
                'force_dimensions' => 0,
                'use_placeholder' => 0,
                'rotate' => 1,
                'rotate_zone' => 1,
                'packages' => array($this->_getDefaultPackage()),
                'auto_rotate' => 0,
                'display_order' => 10,
                'page_criteria' => array(),
                'user_criteria' => array(),
                'page_criteria_not' => array(),
                'user_criteria_not' => array(),

        );
    }

    public function getZoneById($zoneId)
    {
        return $this->prepareZone($this->_getDb()->fetchRow('
			SELECT zone.*
			FROM xcas_zone AS zone
			WHERE zone.zoneId = ?
		', $zoneId));
    }

    public function getZoneObjectById($zoneId)
    {
        $zone = $this->getZoneById($zoneId);
        if (!$zone) {
            return false;
        }

        return $this->createZoneObject($zone);
    }

    /**
     * @param $zoneId
     * @return XenCentral_AdServer_Zone
     */
    public function getZoneByIdFromCache($zoneId)
    {
        $zones = $this->_getAllZones();
        return $this->createZoneObject($zones[$zoneId]);
    }

    public function getAllZones($prepare = true)
    {
        $zones = $this->_getDb()->fetchAssoc("
			SELECT zone.zoneId, zone.*, stats.*
			FROM xcas_zone AS zone
			LEFT JOIN xcas_stats_summary AS stats ON stats.content_type='zone' AND stats.content_id=zone.zoneId
			ORDER BY zone.active DESC, zone.display_order ASC, zone.title ASC
		");

        if ($prepare) {
            return array_map(array($this, 'prepareZone'), $zones);
        }

        return $zones;
    }

    /*public function canManageCustomZone(XenCentral_AdServer_Zone $zone, $visitor = array())
    {
        if (empty(($visitor))) {
            $visitor = XenForo_Visitor::getInstance();
        }

        if (!$zone->isCustomZone()) {
            return false;
        }

        if (XenCentral_AdServer_Permissions::isAdmin()) {
            return true;
        }

        $owners = $zone->get('owners');

        if (!$owners) {
            return false;
        }

        $owners = explode(',', $owners);

        return in_array($visitor['user_id'], $owners);
    }*/

    public function prepareZone($zone)
    {
        if (!empty($zone['prepared'])) {
            return $zone;
        }

        if ($zone == false) {
            return false;
        }

        if (!empty($zone['locations'])) {
            $zone['locations'] = unserialize($zone['locations']);
        } else {
            $zone['locations'] = array();
        }

        if (!empty($zone['packages'])) {
            $zone['packages'] = unserialize($zone['packages']);
        } else {
            $zone['packages'] = array();
        }

        $zone['packages'][9999999] = $this->_getDefaultPackage();

        if (!empty($zone['user_criteria'])) {
            $zone['user_criteria'] = XenForo_Helper_Criteria::unserializeCriteria($zone['user_criteria']);
        } else {
            $zone['user_criteria'] = array();
        }

        if (!empty($zone['user_criteria_not'])) {
            $zone['user_criteria_not'] = XenForo_Helper_Criteria::unserializeCriteria($zone['user_criteria_not']);
        } else {
            $zone['user_criteria_not'] = array();
        }


        if (!empty($zone['page_criteria'])) {
            $zone['page_criteria'] = XenForo_Helper_Criteria::unserializeCriteria($zone['page_criteria']);
        } else {
            $zone['page_criteria'] = array();
        }

        if (!empty($zone['page_criteria_not'])) {
            $zone['page_criteria_not'] = XenForo_Helper_Criteria::unserializeCriteria($zone['page_criteria_not']);
        } else {
            $zone['page_criteria_not'] = array();
        }


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

        $zone['prepared'] = true;

        return $zone;
    }

    public function resizeAttachment(XenCentral_AdServer_Zone $zone, $attachment, &$errors)
    {
        if (
                ($width = $zone->getZoneWidth())
                &&
                ($height = $zone->getZoneHeight())
        ) {
            if ($attachment['width'] > $width OR $attachment['height'] > $height) {
                $attachmentPath = $this->_getAttachmentModel()->getAttachmentDataFilePath($attachment);

                if (!file_exists($attachmentPath)) {
                    $errors[] = new XenForo_Phrase('xcas_attachemnt_file_not_found');
                    return false;
                }

                $src = $attachmentPath;
                $imageInfo = @getimagesize($src);

                $imageInfo['width'] = $imageInfo[0];
                $imageInfo['height'] = $imageInfo[1];
                $imageInfo['type'] = $imageInfo[2];

                $image = XenForo_Image_Abstract::createFromFile($src, $imageInfo['type']);

                $image->thumbnail($width, $height);
                $success = $image->output($imageInfo['type'], $src);

                if (!$success) {
                    $errors[] = new XenForo_Phrase('xcas_unable_to_crop_image');
                    return false;
                }

                $dw = XenForo_DataWriter::create('XenForo_DataWriter_AttachmentData');
                $dw->setExistingData($attachment);
                $dw->set('width', $width);
                $dw->set('height', $height);
                $dw->set('file_size', filesize($src));
                $dw->save();

                $attachment = XenForo_Application::mapMerge($attachment, $dw->getMergedData());
            }
        }

        return $attachment;
    }

    public function cropAttachment($zone_id, $attachment, $x1, $y1, $w, $h, &$errors)
    {
        $errors = array();

        $zone = $this->getZoneObjectById($zone_id);
        $width = $zone->getZoneWidth();
        $height = $zone->getZoneHeight();

        if(!$w OR !$h) {
            return $attachment;
        }

        if (
                $zone->get('force_dimensions')
                && $width
                && $height
                && $w
                && $h
        ) {
            if (round($width / $height, 3) != round($w / $h, 3)) {
                $errors[] = new XenForo_Phrase('xcas_please_cut_in_appropriate_dimensions');
                return $attachment;
            }

            if ($w < $width OR $h < $height) {
                $errors[] = new XenForo_Phrase('xcas_selection_is_too_small');
                return $attachment;
            }
        }

        $attachmentPath = $this->_getAttachmentModel()->getAttachmentDataFilePath($attachment);

        if (!file_exists($attachmentPath)) {
            $errors[] = new XenForo_Phrase('xcas_attachemnt_file_not_found');
            return $attachment;
        }

        $src = $attachmentPath;

        $imageInfo = @getimagesize($src);

        $imageInfo['width'] = $imageInfo[0];
        $imageInfo['height'] = $imageInfo[1];
        $imageInfo['type'] = $imageInfo[2];

        $image = XenForo_Image_Abstract::createFromFile($src, $imageInfo['type']);
        if ($image) {
            $image->crop($x1, $y1, $w, $h);
            $success = $image->output($imageInfo['type'], $src);
            if (!$success) {
                $errors[] = new XenForo_Phrase('xcas_unable_to_crop_image');
                return $attachment;
            }

            $dw = XenForo_DataWriter::create('XenForo_DataWriter_AttachmentData');
            $dw->setExistingData($attachment);
            $dw->set('width', $w);
            $dw->set('height', $h);
            $dw->set('file_size', filesize($src));
            $dw->save();

            $attachment=XenForo_Application::mapMerge($attachment, $dw->getMergedData());

            $attachment['width'] = $w;
            $attachment['height'] = $h;

            $attachment['viewUrl'] = XenForo_Link::buildPublicLink('attachments', $attachment, array('r' => time()));
        } else {
            $errors[] = new XenForo_Phrase('xcas_image_file_is_invalid');
            return $attachment;
        }

        return $attachment;
    }

    protected function _getDefaultPackage()
    {
        return array(
                'length' => '',
                'unit' => 'day',
                'price' => '',
                'currency' => ''
        );
    }

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

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

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