<?php

/*
+---------------------------------------------------------------------------+
| Revive Adserver                                                           |
| http://www.revive-adserver.com                                            |
|                                                                           |
| Copyright: See the COPYRIGHT.txt file.                                    |
| License: GPLv2 or later, see the LICENSE.txt file.                        |
+---------------------------------------------------------------------------+
*/

require_once(MAX_PATH . '/lib/OA/Upgrade/Migration.php');
require_once(MAX_PATH . '/etc/changes/tools/DeliveryLimitationsMigration_128_324.php');

class Migration_128 extends Migration
{
    public function __construct()
    {
        //$this->__construct();

        $this->aTaskList_constructive[] = 'beforeAlterField__banners__transparent';
        $this->aTaskList_constructive[] = 'afterAlterField__banners__transparent';
        $this->aTaskList_constructive[] = 'beforeAddField__banners__parameters';
        $this->aTaskList_constructive[] = 'afterAddField__banners__parameters';
        $this->aTaskList_constructive[] = 'beforeAddField__banners__acls_updated';
        $this->aTaskList_constructive[] = 'afterAddField__banners__acls_updated';


        $this->aObjectMap['banners']['parameters'] = ['fromTable' => 'banners', 'fromField' => 'parameters'];
        $this->aObjectMap['banners']['acls_updated'] = ['fromTable' => 'banners', 'fromField' => 'acls_updated'];
    }



    public function beforeAlterField__banners__transparent()
    {
        if ($this->oDBH->dbsyntax == 'pgsql') {
            $table = $this->oDBH->quoteIdentifier($this->getPrefix() . 'banners', true);

            $sql = "ALTER TABLE {$table} ALTER transparent DROP DEFAULT";
            $this->oDBH->exec($sql);
            $sql = "ALTER TABLE {$table} ALTER transparent TYPE SMALLINT USING (CASE WHEN transparent = 't' THEN 1 ELSE 0 END)";
            $this->oDBH->exec($sql);
            $sql = "ALTER TABLE {$table} ALTER transparent SET DEFAULT 0";
            $this->oDBH->exec($sql);
        }
        return $this->beforeAlterField('banners', 'transparent');
    }

    public function afterAlterField__banners__transparent()
    {
        return $this->afterAlterField('banners', 'transparent');
    }

    public function beforeAddField__banners__parameters()
    {
        return $this->beforeAddField('banners', 'parameters');
    }

    public function afterAddField__banners__parameters()
    {
        return $this->afterAddField('banners', 'parameters');
    }

    public function beforeAddField__banners__acls_updated()
    {
        return $this->beforeAddField('banners', 'acls_updated');
    }

    public function afterAddField__banners__acls_updated()
    {
        return $this->afterAddField('banners', 'acls_updated') && $this->migrateData();
    }

    public function migrateData()
    {
        if ($this->oDBH->dbsyntax == 'pgsql') {
            $this->oDBH->exec("SET bytea_output = 'escape'");
        }

        return $this->migrateSwfProperties() && $this->migrateAcls() && $this->migrateGoogleAdSense();
    }

    public function migrateSwfProperties()
    {
        $table = $this->oDBH->quoteIdentifier($this->getPrefix() . 'banners', true);

        if ($this->oDBH->dbsyntax == 'mysql' || $this->oDBH->dbsyntax == 'mysqli') {
            $sql = "
    	       UPDATE {$table}
    	       SET transparent = 0
    	       WHERE transparent = 2";
            $result = $this->oDBH->exec($sql);
            if (PEAR::isError($result)) {
                return $this->_logErrorAndReturnFalse('Error migrating SWF properties during migration 128: ' . $result->getUserInfo());
            }
        }

        $sql = "
	       SELECT
	           bannerid,
	           htmlcache
	       FROM
	           {$table}
	       WHERE
	           contenttype = 'swf'
	    ";
        $aBanners = $this->oDBH->getAssoc($sql);
        if (PEAR::isError($aBanners)) {
            return $this->_logErrorAndReturnFalse('Error migrating SWF properties during migration 128: ' . $aBanners->getUserInfo());
        }
        foreach ($aBanners as $bannerId => $code) {
            $code = preg_replace('/^.*(<object.*<\/object>).*$/s', '$1', $code);
            preg_match_all('/alink(\d+).*?dest=(.*?)(?:&amp;atar\d+=(.*?))?(?:&amp;|\')/', $code, $m);

            if (count($m[0])) {
                $params = ['swf' => []];
                foreach ($m[1] as $k => $v) {
                    $params['swf'][$v] = [
                        'link' => urldecode($m[2][$k]),
                        'tar' => isset($m[3][$k]) ? urldecode($m[3][$k]) : '',
                    ];
                }
                $params = serialize($params);
                $sql = "
        	       UPDATE {$table}
        	       SET parameters = '" . $this->oDBH->escape($params) . "'
        	       WHERE bannerid = '{$bannerId}'
                ";
                $result = $this->oDBH->exec($sql);
                if (PEAR::isError($result)) {
                    return $this->_logErrorAndReturnFalse('Error migrating SWF properties during migration 128: ' . $result->getUserInfo());
                }
            }
        }
        return true;
    }

    public function migrateGoogleAdSense()
    {
        $table = $this->oDBH->quoteIdentifier($this->getPrefix() . 'banners', true);

        $sql = "
	       SELECT
	           bannerid,
	           htmltemplate
	       FROM
	           {$table}
	       WHERE
	           storagetype = 'html' AND
	           autohtml = 't'
	    ";
        $aBanners = $this->oDBH->getAssoc($sql);
        if (PEAR::isError($aBanners)) {
            return $this->_logErrorAndReturnFalse('Error migrating GoogleAdSense during migration 128: ' . $aBanners->getUserInfo());
        }

        foreach ($aBanners as $bannerId => $code) {
            if (preg_match('/<script.*?src=".*?googlesyndication\.com/is', $code)) {
                $buffer = "<span>" .
                          "<script type='text/javascript'><!--// <![CDATA[\n" .
                          "/* openads={url_prefix} bannerid={bannerid} zoneid={zoneid} source={source} */\n" .
                          "// ]]> --></script>" .
                          $code .
                          "<script type='text/javascript' src='{url_prefix}/ag.php'></script>" .
                          "</span>";
                $sql = "
        	       UPDATE {$table}
        	       SET adserver = 'google', htmlcache = '" . $this->oDBH->escape($buffer) . "'
        	       WHERE bannerid = '{$bannerId}'
                ";
                $result = $this->oDBH->exec($sql);
                if (PEAR::isError($result)) {
                    return $this->_logErrorAndReturnFalse('Error migrating GoogleAdSense during migration 128: ' . $result->getUserInfo());
                }
            }
        }
        return true;
    }

    public $aAclsTypes = [
        'clientip' => 'Client:Ip',
        'browser' => 'Client:Useragent',
        'os' => 'Client:Useragent',
        'useragent' => 'Client:Useragent',
        'language' => 'Client:Language',
        'continent' => 'Geo:Continent',
        'country' => 'Geo:Country',
        'fips_code' => 'Geo:Region',
        'region' => 'Geo:Region',
        'city' => 'Geo:City',
        'postal_code' => 'Geo:Postalcode',
        'dma_code' => 'Geo:Dma',
        'area_code' => 'Geo:Areacode',
        'org_isp' => 'Geo:Organisation',
        'netspeed' => 'Geo:Netspeed',
        'weekday' => 'Time:Day',
        'domain' => 'Client:Domain',
        'source' => 'Site:Source',
        'time' => 'Time:Hour',
        'date' => 'Time:Date',
        'referer' => 'Site:Referingpage',
        'url' => 'Site:Pageurl',
    ];

    public $aPlugins = [];


    public function migrateAcls()
    {
        $tableAcls = $this->oDBH->quoteIdentifier($this->getPrefix() . "acls", true);
        $sql = "SELECT * FROM $tableAcls ORDER BY bannerid, executionorder";
        $rsAcls = DBC::NewRecordSet($sql);
        if (!$rsAcls->find()) {
            return false;
        }
        $aInserts = [];
        $aOffsets = [];
        $aUpdates = [];
        while ($rsAcls->fetch()) {
            $bannerid = $rsAcls->get('bannerid');
            $executionorder = $rsAcls->get('executionorder');
            $oldType = $rsAcls->get('type');
            if (!isset($this->aAclsTypes[$oldType])) {
                $this->_logError("Unknown acls type: $oldType");
                return false;
            }
            $type = $this->aAclsTypes[$oldType];
            $oldComparison = $rsAcls->get('comparison');
            $oldData = $rsAcls->get('data');

            $oPlugin = &$this->_getDeliveryLimitationPlugin($type);
            if (!$oPlugin) {
                $this->_logError("Can't find code for delivery limitation plugin: $type.");
                return false;
            }

            $aNewAclsData = $oPlugin->getUpgradeFromEarly($oldComparison, $oldData);

            $comparison = $aNewAclsData['op'];
            $data = $aNewAclsData['data'];
            $aUpdates [] = "UPDATE $tableAcls SET type = '$type', comparison = '$comparison', data = '$data'
	        WHERE bannerid = $bannerid
	        AND executionorder = $executionorder";

            $aOffsets[$bannerid] = $executionorder;

            if (isset($aNewAclsData['add'])) {
                if (!isset($aInserts[$bannerid])) {
                    $aInserts[$bannerid] = [];
                }
                $aInserts[$bannerid] = array_merge($aInserts[$bannerid], $aNewAclsData['add']);
            }
        }

        foreach ($aUpdates as $update) {
            $result = $this->oDBH->exec($update);
            if (PEAR::isError($result)) {
                return $this->_logErrorAndReturnFalse("Couldn't execute update: $update");
            }
        }

        foreach ($aInserts as $bannerid => $aLimitations) {
            $this->_log("WARNING! Found region geotargeting limitations that are NOT COMPATIBLE with new targeting format!");
            $this->_log("WARNING! Upgrade will proceed, but delivery limitations may NOT be preserved...");
            foreach ($aLimitations as $aValues) {
                $aValues['bannerid'] = $bannerid;
                $aValues['executionorder'] = ++$aOffsets[$bannerid];
                $insert = OA_DB_Sql::sqlForInsert('acls', $aValues);
                $result = $this->oDBH->exec($insert);
                if (PEAR::isError($result)) {
                    return $this->_logErrorAndReturnFalse("Couldn't execute insert: $insert");
                }
                $this->_log("WARNING! Upgraded incompatible region geotargeting limitation. After upgrade, you should check limitations for Banner ID: $bannerid.");
            }
            $this->_log("WARNING! Upgrade of non-compatible region geotargeting limitations is complete.");
        }
        return true;
    }

    /**
     * A private method to instantiate a delivery limitation plugin object.
     *
     * @param string $sType The delivery limitation plugin package and name,
     *                      separated with a colon ":". For example, "Geo:Country".
     * @return
     */
    public function _getDeliveryLimitationPlugin($sType)
    {
        if (isset($this->aPlugins[$sType])) {
            return $this->aPlugins[$sType];
        }

        list($package, $name) = explode(':', $sType);
        $className = 'Upgrade_DeliveryLimitations_' . ucfirst($package) . '_' . ucfirst($name);
        $this->aPlugins[$sType] = new $className();
        return $this->aPlugins[$sType];
    }
}
