<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

// Require composer dependecies if necessary
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once(__DIR__ . '/vendor/autoload.php');
}

if (!class_exists('ViisonCommon_Plugin_BootstrapV14')) {
    require_once('ViisonCommon/PluginBootstrapV14.php');
}

include_once(__DIR__ . '/ViisonShippingCommon/ShippingProviderInterfaceLoader.php');

use Shopware\Plugins\ViisonCommon\Classes\Exceptions\InstallationException;
use Shopware\Plugins\ViisonCommon\Classes\Installation\BackendSessionLocaleClassMigration;
use Shopware\Plugins\ViisonCommon\Classes\Installation\Menu;
use Shopware\Plugins\ViisonCommon\Classes\Installation\SQLHelper;
use Shopware\Plugins\ViisonCommon\Classes\Subscribers as ViisonCommonSubscribers;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as ViisonCommonUtil;
use Shopware\Plugins\ViisonShippingCommon\Classes\Mail\ReturnLabelMailContextHelper;
use Shopware\Plugins\ViisonShippingCommon\Installation\ShippingCommonInstaller;
use Shopware\Plugins\ViisonShippingCommon\Subscriber as ViisonShippingCommonSubscribers;
use Shopware\Plugins\ViisonUPS\Classes\PluginInfo;
use Shopware\Plugins\ViisonUPS\Subscribers;
use Shopware\Plugins\ViisonShippingCommon\Migration\Encryption;

/*
 * "Declare" some methods that are not required in our bootstrap, but whose existence is checked during Shopware's
 * code review:
 *
 * public function getVersion() {}
 */

final class Shopware_Plugins_Backend_ViisonUPS_Bootstrap extends ViisonCommon_Plugin_BootstrapV14
{
    /**
     * @inheritdoc
     */
    protected $codeVersion = '2.16.0.55';

    /**
     * @inheritdoc
     */
    protected $minRequiredShopwareVersion = '5.5.0';

    /**
     * @inheritdoc
     */
    protected function runUpdate($oldVersion)
    {
        // Check license
        $this->checkLicenseInternal();

        // Prepare some helpers
        $database = $this->get('db');
        $sqlHelper = new SQLHelper($database);
        $modelManager = $this->get('models');
        $me = $this;
        $menuInstallationHelper = new Menu\InstallationHelper($modelManager, ViisonCommonUtil::getPlugin($this->getName()), function (array $options) use ($me) {
            // See Shopware_Components_Plugin_Bootstrap::createMenuItem for possible 'options' fields
            return $me->createMenuItem($options);
        });

        $container = $this->get('service_container');
        $shippingCommonInstaller = new ShippingCommonInstaller($modelManager, $sqlHelper, $database, $container);
        $shippingCommonInstaller->installViisonShippingCommon();

        $oldInstallVersion = ViisonCommonUtil::convertBinaryVersionToInstallVersion($oldVersion);

        switch ($oldInstallVersion) {
            case 'install':
                // Create custom table for generated labels
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_order_viison_ups (
                    id int(11) unsigned NOT NULL AUTO_INCREMENT,
                    orderId int(11) unsigned NOT NULL,
                    trackingCode varchar(255) NOT NULL,
                    url varchar(1023) NOT NULL,
                    exportDocumentUrl varchar(1023),
                    returnShipment tinyint(1) not null default 0,
                    created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    PRIMARY KEY (id),
                    KEY orderId (orderId)
                    ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );

                // Create custom table for storing plugin configurations for each shop
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_core_shops_viison_ups (
                    id int(11) unsigned NOT NULL AUTO_INCREMENT,
                    shopId int(11) unsigned NOT NULL,
                    senderName varchar(35),
                    streetName varchar(40),
                    streetNumber varchar(7),
                    zipCode varchar(10),
                    city varchar(30),
                    contactPerson varchar(30),
                    phoneNumber varchar(20),
                    userId varchar(255),
                    password varchar(255),
                    accessKey varchar(255),
                    accountNumber varchar(6),
                    defaultPackagingType int(11),
                    defaultShipmentWeight decimal(10,3) unsigned default 1.0,
                    calculateWeight int(1) unsigned default 0,
                    fillerSurcharge decimal(10,3) unsigned default 5.0,
                    packagingSurcharge decimal(10,3) unsigned default 0.5,
                    sendDispatchNotification tinyint(1) NOT NULL DEFAULT 0,
                    dispatchNotificationText mediumtext,
                    sendDeliveryNotification tinyint(1) NOT NULL DEFAULT 0,
                    email varchar(255) default null,
                    PRIMARY KEY (id),
                    UNIQUE KEY shopId (shopId)
                    ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );
                // Create a plugin configuration for each existing sub shop
                $this->createSubShopConfigurations();
                // Add a new email template for sending return labels
                $database->query(
                    'INSERT INTO s_core_config_mails (name, frommail, fromname, subject, content, ishtml, mailtype, context)
                     VALUES (?, ?, ?, ?, CONCAT_WS(CHAR(10 using utf8), ?, ?, ?, ?, ?, ?, ?, ?), 0, 1, ?)
                     ON DUPLICATE KEY UPDATE
                        name = VALUES(name), frommail = VALUES(frommail), fromname = VALUES(fromname),
                        subject = VALUES(subject), content = VALUES(content), ishtml = VALUES(ishtml),
                        mailtype = VALUES(mailtype), context = VALUES(context)',
                    array(
                        'ViisonUPSReturnLabelEmail',
                        '{config name=mail}',
                        '{config name=shopName}',
                        'Rücksendung der Bestellung {$orderNumber}',
                        'Sehr geehrte{if $userSalutation eq "mr"}r Herr{elseif $userSalutation eq "ms"} Frau{/if} {$userFirstName} {$userLastName},',
                        ' ',
                        'im Anhang dieser E-Mail finden Sie ein Versandetikett von UPS zur Rücksendung ihrer Bestellung mit der Nummer {$orderNumber}.',
                        'Bitte drucken Sie es aus und nutzen Sie es, um die kostenfreie Rücksendung in Anspruch zu nehmen.',
                        'Wir wünschen Ihnen noch einen schönen Tag.',
                        ' ',
                        'Ihr Team von {config name=shopName}.',
                        ' ',
                        'a:4:{s:11:"orderNumber";i:20000;s:14:"userSalutation";s:2:"mr";s:13:"userFirstName";s:3:"Max";s:12:"userLastName";s:10:"Mustermann";}'
                    )
                );
                // Create custom table for storing UPS products
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_viison_ups_products (
                        id int(11) unsigned NOT NULL AUTO_INCREMENT,
                        name varchar(255) NOT NULL,
                        code varchar(3) NOT NULL,
                        packageDimensionsRequired tinyint(1) NOT NULL,
                        PRIMARY KEY (id)
                        ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );
                $sqlHelper->insertIfNotExists('s_viison_ups_products', array('name', 'code', 'packageDimensionsRequired'), array(
                    array('Next Day Air', '01', 0),
                    array('2nd Day Air', '02', 0),
                    array('Ground', '03', 0),
                    array('Express', '07', 0),
                    array('Expedited', '08', 0),
                    array('UPS Standard', '11', 0),
                    array('3 Day Select', '12', 0),
                    array('Next Day Air Saver', '13', 0),
                    array('Next Day Air Early AM', '14', 0),
                    array('Express Plus', '54', 0),
                    array('2nd Day Air A.M.', '59', 0),
                    array('UPS Saver', '65', 0),
                    array('First Class Mail', 'M2', 0),
                    array('Priority Mail', 'M3', 0),
                    array('Expedited Mail Innovations', 'M4', 0),
                    array('Priority Mail Innovations', 'M5', 0),
                    array('Economy Mail Innovations', 'M6', 0),
                    array('UPS Today Standard', '82', 0),
                    array('UPS Today Dedicated Courier', '83', 0),
                    array('UPS Today Intercity', '84', 0),
                    array('UPS Today Express', '85', 0),
                    array('UPS Today Express Saver', '86', 0),
                    array('UPS Worldwide Express Freight', '96', 0)
                ));
                // Create custom table for storing UPS packaging codes
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_viison_ups_packaging_codes (
                        id int(11) unsigned NOT NULL AUTO_INCREMENT,
                        name varchar(255) NOT NULL,
                        code varchar(3) NOT NULL,
                        PRIMARY KEY (id)
                        ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );
                $sqlHelper->insertIfNotExists('s_viison_ups_packaging_codes', array('name', 'code'), array(
                    array('UPS Letter', '01'),
                    array('Customer Supplied Package', '02'),
                    array('Tube', '03'),
                    array('PAK', '04'),
                    array('UPS Express Box', '21'),
                    array('UPS 25KG Box', '24'),
                    array('UPS 10KG Box', '25'),
                    array('Pallet', '30'),
                    array('Small Express Box', '2a'),
                    array('Medium Express Box', '2b'),
                    array('Large Express Box', '2c'),
                    array('Flats', '56'),
                    array('Parcels', '57'),
                    array('BPM', '58'),
                    array('First Class', '59'),
                    array('Priority', '60'),
                    array('Machinables', '61'),
                    array('Irregulars', '62'),
                    array('Parcel Post', '63'),
                    array('BPM Parcel', '64'),
                    array('Media Mail', '65'),
                    array('BPM Flat', '66'),
                    array('Standard Flat', '67')
                ));
                // Create custom table for storing UPS return service codes
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_viison_ups_return_service_codes (
                        id int(11) unsigned NOT NULL AUTO_INCREMENT,
                        name varchar(255) NOT NULL,
                        code varchar(3) NOT NULL,
                        PRIMARY KEY (id)
                        ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );
                $sqlHelper->insertIfNotExists('s_viison_ups_return_service_codes', array('name', 'code'), array(
                    array('UPS Print and Mail (PNM)', '2'),
                    array('UPS Return Service 1-Attempt (RS1)', '3'),
                    array('UPS Return Service 3-Attempt (RS3)', '5'),
                    array('UPS Electronic Return Label (ERL)', '8'),
                    array('UPS Print Return Label (PRL)', '9'),
                    array('UPS Exchange Print Return Label', '10'),
                    array('UPS Pack & Collect Service 1-Attempt Box 1', '11'),
                    array('UPS Pack & Collect Service 1-Attempt Box 2', '12'),
                    array('UPS Pack & Collect Service 1-Attempt Box 3', '13'),
                    array('UPS Pack & Collect Service 1-Attempt Box 4', '14'),
                    array('UPS Pack & Collect Service 1-Attempt Box 5', '15'),
                    array('UPS Pack & Collect Service 3-Attempt Box 1', '16'),
                    array('UPS Pack & Collect Service 3-Attempt Box 2', '17'),
                    array('UPS Pack & Collect Service 3-Attempt Box 3', '18'),
                    array('UPS Pack & Collect Service 3-Attempt Box 4', '19'),
                    array('UPS Pack & Collect Service 3-Attempt Box 5', '20')
                ));
                // Create custom table for associations between UPS products and dispatch methods
                $database->query(
                    'CREATE TABLE IF NOT EXISTS s_premium_dispatch_viison_ups (
                        id int(11) unsigned NOT NULL AUTO_INCREMENT,
                        productId int(11) unsigned NOT NULL,
                        dispatchId int(11) unsigned NOT NULL,
                        exportDocumentRequired tinyint(1) NOT NULL DEFAULT 0,
                        PRIMARY KEY (id),
                        KEY productId (productId),
                        KEY dispatchId (dispatchId)
                        ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
                );
                // Register an early event for our event subscribers
                $this->subscribeEvent(
                    'Enlight_Controller_Front_DispatchLoopStartup',
                    'onStartDispatch'
                );
            case '1.0.0':
                // Nothing to do, bugfix release
            case '1.0.1':
                $menuInstallationHelper->ensureMenuItemInDatabaseIs(array(
                    'label' => 'UPS-Etiketten ohne Bestellung',
                    'class' => 'sprite-report-paper',
                    'controller' => 'ViisonUPSFreeFormLabels',
                    'action' => 'Index',
                    'active' => 1,
                    'parent' => $this->Menu()->findOneBy(array('label' => 'Kunden'))
                ));

                // Make orderId nullable to allow for free form labels that do not have an associated order
                $sqlHelper->alterColumnIfExists('s_order_viison_ups', 'orderId', 'orderId', 'int(11) unsigned');

                // Adapt the return label email to be also suitable for free form labels (that have no associated order)
                $database->query(
                    'UPDATE s_core_config_mails
                         SET subject = REPLACE(
                            subject,
                            \'Rücksendung der Bestellung {$orderNumber}\',
                            \'Rücksendung der Bestellung{if isset($orderNumber)} {$orderNumber}{/if}\'
                         ),
                         content = REPLACE(
                            content,
                            \'im Anhang dieser E-Mail finden Sie ein Versandetikett von UPS zur Rücksendung ihrer Bestellung mit der Nummer {$orderNumber}.\',
                            \'im Anhang dieser E-Mail finden Sie ein Versandetikett von UPS zur Rücksendung ihrer Bestellung{if isset($orderNumber)} mit der Nummer {$orderNumber}{/if}.\'
                         )'
                );

                // Add column to config for the product that is to be used for return shipments
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'returnProduct', 'int(11) DEFAULT 6'); // make 'UPS Standard' the default return product

                // Add a column indicating the customer address (used for free form labels)
                $sqlHelper->addColumnIfNotExists('s_order_viison_ups', 'customerAddress', 'varchar(1023) default 0');
            case '1.1.0':
                // Nothing to do
            case '1.1.1':
                // Add column to the config for the pdf size
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'pdfSize', 'varchar(255) NOT NULL DEFAULT \'A5\'');
            case '1.1.2':
                // Add column to the config for negotiated rates
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'negotiatedRates', 'tinyint(1) NOT NULL DEFAULT 0');
            case '1.1.3':
                // New subscribes to support ShippingCommon version handling
                $this->subscribeEvent(
                    'Shopware_ViisonShippingCommon_GetNewestVersion',
                    'onGetNewestViisonShippingCommonVersion'
                );
            case '1.1.4':
                // Nothing to do, bugfix release
            case '1.1.5':
                // Nothing to do, bugfix release
            case '1.1.6':
                $modelManager->flush();
                // Remove previously created UPS free form label menu-entry
                $query = 'DELETE FROM Shopware\Models\Menu\Menu m WHERE m.pluginId = ?0';
                $query = $modelManager->createQuery($query);
                $query->execute(array($this->getId()));

                // The label given here is only a fall back value and is not meant to get used. It must be different from the value of
                // other plugins to make sure that a new menu item is created. The real text that is displayed in the menu is taken from
                // the 'ViisonUPS' snippet (the controller name) in the backend/index/view/main namespace.
                // Notice: ViisonUPS is not a real controller and we also don't want to react to clicks on the UPS parent menu entry.
                // We can prevent Shopware from trying to open a sub-application when clicking on the parent UPS entry by setting the action to null.
                $upsItem = $menuInstallationHelper->ensureMenuItemInDatabaseIs(array(
                    'label' => 'UPS (Viison)',
                    'class' => 'sprite-report-paper',
                    'controller' => 'ViisonUPS',
                    'action' => null,
                    'active' => 1,
                    'parent' => $this->Menu()->findOneBy(array('label' => 'Kunden'))
                ));

                $menuInstallationHelper->ensureMenuItemInDatabaseIs(array(
                    'label' => 'Etiketten ohne Bestellung',
                    'class' => 'sprite-report-paper',
                    'controller' => 'ViisonUPSFreeFormLabels',
                    'action' => 'Index',
                    'active' => 1,
                    'parent' => $upsItem
                ));

                $menuInstallationHelper->ensureMenuItemInDatabaseIs(array(
                    'label' => 'Konfiguration',
                    'class' => 'sprite-wrench-screwdriver',
                    'controller' => 'ViisonUPSConfig',
                    'action' => 'Index',
                    'active' => 1,
                    'parent' => $upsItem
                ));
            case '1.2.0':
                // Nothing to do
            case '1.2.1':
                // Nothing to do, bugfix release
            case '1.2.2':
                // Nothing to do
            case '1.2.3':
                // Nothing to do
            case '1.2.4':
                // Nothing to do, bugfix release
            case '1.2.5':
                $sqlHelper->addColumnIfNotExists('s_order_viison_ups', 'productId', 'int(11) default null');
            case '1.2.6':
                // Nothing to do, bugfix release
            case '1.2.7':
                // Nothing to do, bugfix release
            case '1.2.8':
                // Nothing to do, bugfix release
            case '1.2.9':
                // Nothing to do, bugfix release
            case '1.2.10':
                // Add column to the config for the country of the sender
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'countryId', 'int(1)');
            case '1.3.0':
                // Nothing to do, bugfix release
            case '1.3.1':
                // Use plugin icon in menu item
                // Make sure that the UPS menu entry has been written to the database
                $modelManager->flush();
                /** @var Shopware\Models\Menu\Menu $upsItem */
                $upsItem = $this->Menu()->findOneBy(array('controller' => 'ViisonUPS'));
                $upsItem->setClass('c-sprite-ups-icon');
                $modelManager->persist($upsItem);
                $modelManager->flush($upsItem);
                // Add a database column for the shipment weight for each created label
                $sqlHelper->addColumnIfNotExists('s_order_viison_ups', 'weight', 'float default null');
            case '1.3.2':
                // Nothing to do
            case '1.4.0':
                // Nothing to do, bugfix release
            case '1.4.1':
                // Nothing to do
            case '1.4.2':
                // Add new columns to the dispatch product mappings for visual age check and personal handover configuration
                $sqlHelper->addColumnIfNotExists('s_premium_dispatch_viison_ups', 'higherInsurance', 'tinyint(1) not null default 0');
            case '1.4.3':
                // Nothing to do, bugfix release
            case '1.4.4':
                // Add new columns to the dispatch product mappings for the additional handling required option
                $sqlHelper->addColumnIfNotExists('s_premium_dispatch_viison_ups', 'additionalHandlingRequired', 'tinyint(1) not null default 0');

                // Make the dispatchId index unique
                $database->query(
                    'ALTER TABLE s_premium_dispatch_viison_ups
                        DROP KEY dispatchId'
                );
                $database->query(
                    'ALTER TABLE s_premium_dispatch_viison_ups
                        ADD UNIQUE KEY dispatchId (dispatchId)'
                );

                /** Shopware\Models\Dispatch\Dispatch[] $dispatchTypes */
                $dispatchTypes = $modelManager->getRepository('Shopware\Models\Dispatch\Dispatch')->findAll();
                foreach ($dispatchTypes as $dispatchType) {
                    $database->query(
                        'INSERT INTO s_premium_dispatch_viison_ups
                             (dispatchId, additionalHandlingRequired)
                             VALUES (?, ?)
                             ON DUPLICATE KEY UPDATE additionalHandlingRequired = ?',
                        array(
                            $dispatchType->getID(),
                            false,
                            false
                        )
                    );
                }
            case '1.4.5':
                // Nothing to do, bugfix release
            case '1.4.6':
                // Nothing to do
            case '2.0.0':
                // Nothing to do
            case '2.0.1':
                // Nothing to do, bugfix release
            case '2.0.2':
                // Nothing to do
            case '2.0.3':
                $sqlHelper->alterColumnIfExists('s_order_viison_ups', 'customerAddress', 'customerAddress', 'varchar(1023) DEFAULT NULL');
                $database->query('UPDATE s_order_viison_ups SET customerAddress = NULL WHERE customerAddress = \'0\'');
            case '2.0.4':
                // Nothing to do
            case '2.0.5':
                // Nothing to do
            case '2.0.6':
                // Include support for feature 'Salutation Toggle' from ShippingCommon
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'isSalutationRequired', 'tinyint(1) not null default 1');

            case '2.1.0':
                // Nothing to do
            case '2.1.1':
                /** Include support for payment means for cash on delivery service */
                $sqlHelper->addColumnIfNotExists('s_core_shops_viison_ups', 'cashOnDeliveryPaymentMeansIds', 'VARCHAR(255) DEFAULT \'3\'');
            case '2.2.0':
                // Nothing to do
            case '2.2.1':
                // Nothing to do
            case '2.2.2':
                // Nothing to do
            case '2.2.3':
                // Add a database column for the page size of each created label
                $sqlHelper->addColumnIfNotExists('s_order_viison_ups', 'pageSize', 'VARCHAR(255) DEFAULT NULL');
                // Initialise the page size of old labels with the size currently configured for the respective shop
                $database->query(
                    'UPDATE s_order_viison_ups oap
                        LEFT JOIN s_order o
                            ON o.id = oap.orderId
                        LEFT JOIN s_core_shops_viison_ups sap
                            ON sap.shopId = o.subshopID
                        SET oap.pageSize = IFNULL(sap.pdfSize, \'A5\')
                        WHERE oap.pageSize IS NULL'
                );
            case '2.2.4':
                // Nothing to do
            case '2.2.5':
                // Nothing to do
            case '2.2.6':
                // Nothing to do
            case '2.2.7':
                // Nothing to do
            case '2.2.8':
                // Nothing to do
            case '2.2.9':
                // Nothing to do
            case '2.2.10':
                // We need to update the mail context so the mail variables will be visible before the first mail creation
                ReturnLabelMailContextHelper::updateTemplateToDefaultContextValue(
                    'ViisonUPSReturnLabelEmail',
                    $database
                );
            case '2.2.11':
                // Nothing to do
            case '2.3.0':
                $sqlHelper->insertOrUpdateUniqueRow(
                    's_viison_ups_products',
                    array(
                        'code' => '74'
                    ),
                    array(
                        'name' => 'UPS Express 12:00',
                        'packageDimensionsRequired' => 0
                    )
                );
            case '2.3.1':
                $sqlHelper->addIndexIfNotExists(
                    's_order_viison_ups',
                    $sqlHelper->getConstraintIdentifier('s_order_viison_ups', 'trackingCode', 'idx'),
                    ['trackingCode']
                );
            case '2.3.2':
                // Nothing to do
            case '2.3.3':
                // Nothing to do
            case '2.3.4':
                // Since we renamed isCustomerContactDataTransferAllowed into gdprConfiguration into gdprMailConfiguration
                // we need to double check the column names fo prevent idempotency bugs.
                if (!$sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'gdprConfiguration') &&
                    !$sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'gdprMailConfiguration')) {
                    // Column gets renamed in update step for v2.4.11, so we have to check for both column names
                    $sqlHelper->addColumnIfNotExists(
                        's_core_shops_viison_ups',
                        'isCustomerContactDataTransferAllowed',
                        'TINYINT(1) DEFAULT 0'
                    );
                }
            case '2.4.0':
                // Nothing to do
            case '2.4.1':
                // Nothing to do
            case '2.4.2':
                // Nothing to do
            case '2.4.3':
                // Nothing to do
            case '2.4.4':
                // Nothing to do
            case '2.4.5':
                // The former page format 'A5' has been renamed to 'borderless'. Migrate this setting for the
                // customers who are doing an update but not for the ones doing an install.
                if ($oldInstallVersion !== 'install') {
                    $database->query('UPDATE s_core_shops_viison_ups SET pdfSize = "borderless" WHERE pdfSize = "A5"');
                }
            case '2.4.6':
                // Nothing to do
            case '2.4.7':
                // Nothing to do
            case '2.4.8':
                // Nothing to do
            case '2.4.9':
                // Nothing to do
            case '2.4.10':
                // Nothing to do
            case '2.4.11':
                $sqlHelper->alterColumnIfExists(
                    's_core_shops_viison_ups',
                    'isCustomerContactDataTransferAllowed',
                    'gdprConfiguration',
                    'VARCHAR(255) default \'never\''
                );
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'gdprConfiguration')) {
                    $database->query('UPDATE s_core_shops_viison_ups SET gdprConfiguration = \'never\' WHERE gdprConfiguration = \'0\'');
                    $database->query('UPDATE s_core_shops_viison_ups SET gdprConfiguration = \'customerChoice\' WHERE gdprConfiguration = \'1\'');
                }
            case '2.5.0':
                // Nothing to do
            case '2.5.1':
                $backendSessionMigration = new BackendSessionLocaleClassMigration(
                    $this->get('models'),
                    $this->get('db'),
                    $this->get('pluginlogger'),
                    $this->get('application')->Container()
                );
                $backendSessionMigration->fixSessions();

                // Add test web service checkbox
                $sqlHelper->addColumnIfNotExists(
                    's_core_shops_viison_ups',
                    'useTestingWebservice',
                    'TINYINT(1) NOT NULL DEFAULT 0'
                );

                // Migration from encrypted password to decrypted if possible
                $removeEncryptionMigration = new Encryption\RemoveEncryptionMigration(
                    $database,
                    $this->getLogger(),
                    $this->get('models')
                );

                $isMigrationSuccessful = $removeEncryptionMigration->migrate(
                    's_core_shops_viison_ups',
                    ['password', 'accessKey']
                );
                if (!$isMigrationSuccessful) {
                    // Decryption didn't work, just show a hint message
                    $this->addLocalizedGrowlMessage(
                        'bootstrap/viison_ups/main',
                        'update/hint/password_encryption'
                    );
                }
                // Update config field name in database
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'gdprConfiguration')) {
                    $database->query('ALTER TABLE s_core_shops_viison_ups CHANGE gdprConfiguration gdprMailConfiguration VARCHAR(255) DEFAULT \'never\'');
                }
                // Add configuration field to toggle sending the customers phone number to the shipping provider
                $sqlHelper->addColumnIfNotExists(
                    's_core_shops_viison_ups',
                    'gdprPhoneConfiguration',
                    'VARCHAR(255) DEFAULT \'never\''
                );
            case '2.6.0':
                // Nothing to do
            case '2.7.0':
                // The former page format 'borderless' has been renamed to '4x7-inch'.
                $database->query('UPDATE s_core_shops_viison_ups SET pdfSize = "4x7-inch" WHERE pdfSize = "borderless"');
                // Also update the page formats for already created labels
                $database->query('UPDATE s_order_viison_ups SET pageSize = "4x7-inch" WHERE pageSize = "borderless"');
            case '2.8.0':
                // Nothing to do
            case '2.9.0':
                // Nothing to do
            case '2.10.0':
                // Nothing to do
            case '2.11.0':
                // Nothing to do
            case '2.11.1':
                // Nothing to do
            case '2.11.2':
                // Nothing to do
            case '2.12.0':
                // Nothing to do
            case '2.13.0':
                // Update config field datatype in database
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'calculateWeight')
                    && $sqlHelper->getColumnType('s_core_shops_viison_ups', 'calculateWeight') === 'int unsigned'
                ) {
                    $database->query('ALTER TABLE s_core_shops_viison_ups CHANGE calculateWeight calculateWeight tinyint(1) NOT NULL DEFAULT 0');
                }
            case '2.14.0':
                // Nothing to do
            case '2.14.1':
                // Nothing to do
            case '2.14.2':
                // Nothing to do
            case '2.15.0':
                // Nothing to do
            case '2.15.1':
                // Update config field datatype in database
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'sendDispatchNotification')
                    && $sqlHelper->getColumnType('s_core_shops_viison_ups', 'sendDispatchNotification') === 'int unsigned'
                ) {
                    $database->query('ALTER TABLE s_core_shops_viison_ups CHANGE sendDispatchNotification sendDispatchNotification tinyint(1) NOT NULL DEFAULT 0');
                }
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'sendDeliveryNotification')
                    && $sqlHelper->getColumnType('s_core_shops_viison_ups', 'sendDeliveryNotification') === 'int unsigned'
                ) {
                    $database->query('ALTER TABLE s_core_shops_viison_ups CHANGE sendDeliveryNotification sendDeliveryNotification tinyint(1) NOT NULL DEFAULT 0');
                }
                if ($sqlHelper->doesColumnExist('s_core_shops_viison_ups', 'negotiatedRates')
                    && $sqlHelper->getColumnType('s_core_shops_viison_ups', 'negotiatedRates') === 'int'
                ) {
                    $database->query('ALTER TABLE s_core_shops_viison_ups CHANGE negotiatedRates negotiatedRates tinyint(1) NOT NULL DEFAULT 0');
                }
            case '2.15.2':
                // Nothing to do
            case '2.15.3':
                // Nothing to do
            case '2.15.4':
                // Nothing to do
            case '2.16.0':
                // Next release

                // *** *** *** *** ***
                // NEVER REMOVE THE FOLLOWING BREAK! All updates must be added above this comment block!
                // *** *** *** *** ***
                break;
            default:
                throw InstallationException::updateFromVersionNotSupported(
                    $this,
                    $oldInstallVersion,
                    $this->getVersion()
                );
        }

        // Update ViisonCommon and ViisonShippingCommon snippets
        $this->importViisonCommonSnippetsIntoDb();
        $this->removeObsoletePluginFiles();
    }

    /**
     * @inheritdoc
     */
    protected function runUninstall($deleteData)
    {
        if (!$deleteData) {
            // Nothing to do
            return;
        }

        $database = $this->get('db');

        // Remove hidden config field for completed encryption removal.
        $removeEncryptionMigration = new Encryption\RemoveEncryptionMigration(
            $database,
            $this->getLogger(),
            $this->get('models')
        );
        $removeEncryptionMigration->uninstall('s_core_shops_viison_ups');

        // Remove custom database tables
        $database->query(
            'DROP TABLE IF EXISTS
            s_order_viison_ups,
            s_viison_ups_products,
            s_viison_ups_packaging_codes,
            s_viison_ups_return_service_codes,
            s_premium_dispatch_viison_ups,
            s_core_shops_viison_ups'
        );

        // Remove custom snippets
        $database->query(
            'DELETE FROM s_core_snippets
            WHERE namespace LIKE \'%viison_ups%\''
        );

        $entityManager = $this->get('models');
        $sqlHelper = new SQLHelper($database);
        $container = $this->get('service_container');
        $shippingCommonInstaller = new ShippingCommonInstaller($entityManager, $sqlHelper, $database, $container);
        $shippingCommonInstaller->uninstallViisonShippingCommon();
    }

    /**
     * @inheritdoc
     */
    protected function runActivation()
    {
        // Nothing to do
    }

    /**
     * @inheritdoc
     */
    protected function runDeactivation()
    {
        // Nothing to do
    }

    /**
     * Registers the plugin's namespaces.
     *
     * NOTE: When using the test system don't forget to set check license to true
     */
    public function afterInit()
    {
        $this->loadDependencies();
        $this->loadPlugin();
    }

    /**
     * This callback function is triggered at the very beginning of the dispatch process and allows
     * us to register additional events on the fly.
     */
    public function onStartDispatch(\Enlight_Event_EventArgs $args)
    {
        // Nothing to do here, since the dynamic subscribers were already registered in 'afterInit()'
    }

    /* INSTALL/UPDATE/UNINSTALL HELP METHODS */

    // Removed license checking method
    // Removed license checking method
    // Removed license checking method
    // Removed license checking method
    // Removed license checking method
    // Removed license checking method

    /**
     * Checks whether this shop has a license to run this plugin.
     *
     * @param bool $throwException
     * @throws Exception
     * @return bool True, if the plugin is licensed. Otherwise false.
     */
    public function checkLicenseInternal($throwException = true)
    {
        $ionCubeNotLoaded = !extension_loaded('ionCube Loader');
        $fileNotEncoded = function_exists('ioncube_file_is_encoded') && !ioncube_file_is_encoded();
        if ($ionCubeNotLoaded || $fileNotEncoded) {
            return true;
        }

        // Check license manager status
        if (!Shopware()->Container()->has('license')) {
            if ($throwException) {
                throw new \Exception('The license manager has to be installed and active');
            } else {
                return false;
            }
        }

        try {
            static $r, $m = 'ViisonUPS';
            if (!isset($r)) {
                $s = base64_decode('tRU0p2ZjiLbKNh3MDySAZrJmjpM=');
                $c = base64_decode('IQ0xUXtQNoP6z45FJT7t5NYqW7I=');
                $r = sha1(uniqid('', true), true);
                /** @var $l Shopware_Components_License */
                $l = $this->get('license');
                $i = $l->getLicense($m, $r);
                $t = $l->getCoreLicense();
                $u = strlen($t) === 20 ? sha1($t . $s . $t, true) : 0;
                $r = $i === sha1($c. $u . $r, true);
            }
            if (!$r && $throwException) {
                throw new Exception('License check for module "' . $m . '" has failed.');
            }
            return $r;
        } catch (Exception $e) {
            if ($throwException) {
                throw new Exception('License check for module "' . $m . '" has failed.');
            } else {
                return false;
            }
        }
    }

    /* Other */

    /**
     * Uses the dependency loader to load the namespaces and susbcribers of all required,
     * shared dependencies.
     */
    private function loadDependencies()
    {
        // Require all shared dependencies
        $loader = VIISON\ShopwarePluginDependencyLoader\Loader::getInstance();
        $loader->requireDependencies($this->Path(), array(
            'ViisonCommon',
            'ViisonShippingCommon'
        ));
        Shopware\Plugins\ViisonCommon\Classes\PickwareAutoloadDependencyLoader::ensureDependenciesLoaded();

        // Add the subscribers of all dependencies
        $viisonCommonSubscriberRegistrator = new Shopware\Plugins\ViisonCommon\Classes\SubscriberRegistrator($this);
        $viisonCommonSubscriberRegistrator->registerSubscribers();

        // Load the Shopware polyfill
        require_once __DIR__ . '/ViisonCommon/Polyfill/Loader.php';

        // Make sure this plugin is installed and activated before registering functionality located within ShippingCommon
        if (!$this->isInstalledAndActive()) {
            return;
        }

        $viisonShippingCommonSubscriberRegistrator = new Shopware\Plugins\ViisonShippingCommon\Classes\SubscriberRegistrator($this);
        $viisonShippingCommonSubscriberRegistrator->registerSubscribers();

        // Call the legacy include helper to add backwards compatibility with outdated shipping plugins
        require_once __DIR__ . '/ViisonShippingCommon/legacy/IncludeHelper.php';
    }

    /**
     * First checks whether the plugin has a valid license, is installed and is active.
     * If all this is true, first the namespaces of this plugin are registered with the
     * class loader, before all subscribers are instanciated and added to the event manager.
     */
    private function loadPlugin()
    {
        // Make sure this plugin is installed and active
        if (!$this->checkLicenseInternal(false)) {
            return;
        }

        // Make sure this plugin is installed and active before registering the susbcribers
        if (!$this->isInstalledAndActive()) {
            return;
        }

        // Create all plugin subscribers
        $subscribers = array(
            new Subscribers\Backend\Index($this),
            new Subscribers\Backend\Order($this),
            new Subscribers\Backend\ViisonShippingCommonOrder($this),
            new Subscribers\Controllers($this),
            new Subscribers\ServicesSubscriber($this),
            new Subscribers\SubApplicationRegistration($this),
            new ViisonShippingCommonSubscribers\ShippingProviders($this, 'Shopware\Plugins\ViisonUPS\Classes\ShippingProvider'),
            new ViisonShippingCommonSubscribers\ConfigImporterSubscriber($this, new PluginInfo()),
            new ViisonCommonSubscribers\ViewLoading($this, 'ViisonUPS'),
        );

        // Make sure that the subscribers are only added once
        if (!$this->isSubscriberRegistered($subscribers[0])) {
            $eventManager = $this->get('events');
            foreach ($subscribers as $subscriber) {
                $eventManager->addSubscriber($subscriber);
            }
        }
    }

    /**
     * Creates for each existing sub shop a partly empty default configuration.
     *
     * @return True, if the creation was successful, otherwise an exception had been thrown before.
     */
    private function createSubShopConfigurations()
    {
        $database = $this->get('db');
        $shops = $database->fetchCol(
            'SELECT id
            FROM s_core_shops'
        );
        foreach ($shops as $shop) {
            $database->query(
                'INSERT IGNORE INTO s_core_shops_viison_ups (shopId)
                VALUES (?)',
                array(
                    $shop
                )
            );
        }

        return true;
    }
}
