<?php

/**
 * IMPLEMENT:
 *    SoftSale main menu in admin area
 *     -> License Schemes page (custom, looks like this)
 *           <h1>Licensing Schemes</h1>
 *           <h3>aMember License scheme <a href>edit</a><a href>delete</a><a href>disable</a></h3>
 *           provides licenses for following products:
 *              here is list of enabled products and javascript link to add
 *              more products (show magicselect? when link clicked?)
 *          <h3>Wordpress Plugin License scheme<a href>edit</a><a href>delete</a><a href>disable</a></h3>
 *           provides licenses for following products:
 *              here is list of enabled products and javascript link to add
 *              more products (show magicselect? when link clicked?)
 *
 *     -> edit link brings the scheme editor page
 *          look at db.xml -> license_scheme for field details
 *          + keygen and activation plugins must be able to ask for additional settings
 *            settings will be saved into scheme->data()->set(plugin_type.plugin_id.'config-key')
 *          for example "predefined list" plugin must display textarea to copy/paste
 *          list of plugins
 *
 *     -> scheme must be impossible to delete if licenses are exist(!) link must be disabled
 *
 *     -> on product purchase (onAccessAfterInsert?) aMember must generate license keys
 *        for given scheme
 *
 *
 *     - implement REST controller for license activation
 *       -> software will contact aMember for license activation and send hostname,ip,other details
 *       -> aMember will check if activation allowed, run activation plugin and activate license
 *       -> LATER if temporary license is enabled in scheme, aMember will generate it too and include into response
 *
 * TODO LATER:
 *    implement sample API to access it in PHP, [C, C++, Java?]
 *    (later) suggest to by-default provide files with Protect Content -> Files, but also implement
 *        Protect Content -> Software Files with version control
 */
class Bootstrap_Softsale extends Am_Module
{
    const ADMIN_PERM_ID = 'softsale-license';
    const ADMIN_PERM_CONFIG_ID = 'softsale-config';

    function init()
    {
        $this->getDi()->plugins_softsale = new Am_Plugins($this->getDi(),
            'softsale', dirname(__FILE__) . '/plugins',
            'Am_Softsale_Plugin_%s', '%s.%s'
        );
        $this->getDi()->plugins_softsale->setTitle('SoftSale Plugins');
        $this->getDi()->plugins->offsetSet('softsale', $this->getDi()->plugins_softsale);
    }

    function onInitBlocks(Am_Event $event)
    {
        $event->getBlocks()->add('admin/user/invoice/right', new Am_Block_Base(
                "Licenses", 'invoice_licenses', $this, array($this, 'renderAdminInvoiceLicenses')));
    }

    public function renderAdminInvoiceLicenses(Am_View $view)
    {
        if (empty($view->invoice)) return;
        if (!$this->getDi()->authAdmin->getUser()->hasPermission(Bootstrap_Softsale::ADMIN_PERM_ID)) return;
        $invoice = $view->invoice;
        /* @var $invoice Invoice */
        if (!$licenses = $this->getDi()->licenseTable->findByInvoiceId($invoice->pk())) return;

        $t = ___('Licenses');
        $cnt = count($licenses);
        $url = $this->getDi()->url("softsale/admin-license/user/user_id/{$invoice->user_id}", array(
            '_license_filter' => $invoice->public_id
        ));
        $tooltip_url = $this->getDi()->url('softsale/admin-license/card', "id={$invoice->pk()}");
        $out = "| <a href=\"$url\" class=\"link\" data-tooltip-url=\"$tooltip_url\">$t&nbsp;($cnt)</a>";

        return $out;
    }

    public function onAdminMenu(Am_Event $event)
    {
        $menu = $event->getMenu();
        $admin = $this->getDi()->authAdmin->getUser();
        if($admin->hasPermission(Bootstrap_Softsale::ADMIN_PERM_CONFIG_ID) || $admin->hasPermission(Bootstrap_Softsale::ADMIN_PERM_ID)) {
            $menu->addPage(array(
                'id' => 'softsale',
                'uri' => '#',
                'label' => ___('Software'),
                'resource' => "softsale",
                'order' => 90,
                'pages' => array_merge(array(
                    array(
                        'id' => 'softsales-scheme',
                        'controller' => 'admin-scheme',
                        'module' => 'softsale',
                        'label' => ___("Licensing Schemes"),
                        'resource' => Bootstrap_Softsale::ADMIN_PERM_CONFIG_ID,
                    ),
                    array(
                        'id' => 'softsales-license',
                        'controller' => 'admin-license',
                        'module' => 'softsale',
                        'label' => ___("Licenses"),
                        'resource' => Bootstrap_Softsale::ADMIN_PERM_ID,
                    ),
                    array(
                        'id' => 'content-softsalefile',
                        'uri' => $this->getDi()->url('default/admin-content/p/softsalefile/index',null,false),
                        'label' => ___('Software Download'),
                        'resource' => Bootstrap_Softsale::ADMIN_PERM_CONFIG_ID,
                    ),
            ))));
        }
    }

    function onUserTabs(Am_Event_UserTabs $event)
    {
        $cnt = $this->getDi()->licenseTable->countByUserId($event->getUserId());

        if ($cnt) {
            $event->getTabs()->addPage(array(
                'id' => 'license',
                'module' => 'softsale',
                'controller' => 'admin-license',
                'action' => 'user',
                'params' => array(
                    'user_id' => $event->getUserId()
                ),
                'label' => ___('Licenses') . sprintf(' ((%s))', $cnt),
                'order' => 1000,
                'resource' => Bootstrap_Softsale::ADMIN_PERM_ID,
            ));
        }
    }

    function onSetupEmailTemplateTypes(Am_Event $e)
    {
        foreach ($this->getDi()->db->selectCol("SELECT scheme_id FROM ?_softsale_license_scheme") as $id) {
            $e->addReturn(array(
                'id' => "softsale_new_license_$id",
                'title' => 'Generated License to Customer',
                'mailPeriodic' => Am_Mail::REGULAR,
                'vars' => array(
                    'user',
                    'invoice',
                    'product.title' => 'Product Title',
                    'license.key' => 'License Key',
                    'license.expires' => 'License Expiration',
                    'license.info' => 'License Info',
                    'scheme.title' => 'License Scheme Title',
                    'scheme.comment' => 'License Scheme Comment',
                )),
            "softsale_new_license_$id");
        }
    }

    public function onInvoiceStarted(Am_Event_InvoiceStarted $event)
    {
        $invoice = $event->getInvoice();
        $ids = array();
        foreach ($invoice->getItems() as $item)
            if ($item->item_type == 'product')
                $ids[] = $item->item_id;
        if (!$ids) return;
        $schemes = $this->getDi()->licenseSchemeTable->getForProductIds($ids);
        foreach ($invoice->getItems() as $item)
        {
            if (empty($schemes[$item->item_id])) continue;
            foreach ($schemes[$item->item_id] as $scheme)
            {
                /* @var $scheme LicenseScheme */
                $scheme->renewLicense($item, $invoice);
            }
        }
        //disable licenses for upgraded invoice
        if ($parent_invoice_id = $invoice->data()->get(Invoice::UPGRADE_INVOICE_ID))
        {
            $licenses = $this->getDi()->licenseTable->findByInvoiceId($parent_invoice_id);
            foreach ($licenses as $l)
            {
                $this->getDi()->licenseLogTable->log("license deleted", "license [$l->key] deleted along with upgrade of invoice [$parent_invoice_id]");
                $l->disable();
            }
        }
    }

    public function onInvoiceAfterDelete(Am_Event $event)
    {
        $invoice_id = $event->getInvoice()->pk();
        $licenses = $this->getDi()->licenseTable->findByInvoiceId($invoice_id);
        foreach ($licenses as $l)
        {
            $this->getDi()->licenseLogTable->log("license deleted", "license [$l->key] deleted along with invoice [$invoice_id]");
            $l->disable();
        }
    }

    public function onPaymentWithAccessAfterInsert(Am_Event_PaymentWithAccessAfterInsert $event)
    {
        $invoice = $event->getInvoice();
        $pc = $invoice->getPaymentsCount();
        if ((double)$invoice->first_total && ($pc == 1)) return;
        if (!(double)$invoice->first_total && ($pc == 0)) return; //?
        // we handle only rebill here, first payment handled in onInvoiceStarted
        $ids = array();
        foreach ($invoice->getItems() as $item)
            if ($item->item_type == 'product')
                $ids[] = $item->item_id;
        $schemes = $this->getDi()->licenseSchemeTable->getForProductIds($ids);
        foreach ($invoice->getItems() as $item)
        {
            if (empty($schemes[$item->item_id])) continue;
            foreach ($schemes[$item->item_id] as $scheme)
            {
                if ($scheme->valid_to != '') continue; // expiration date not depends on rebill
                /* @var $scheme LicenseScheme */
                $scheme->renewLicense($item, $invoice);
            }
        }
    }

    function onRefundAfterInsert(Am_Event $event)
    {
        $invoice = $event->getInvoice();
        $licenses = $this->getDi()->licenseTable->findByInvoiceId($invoice->invoice_id);
        foreach ($licenses as $l)
        {
            $this->getDi()->licenseLogTable->log("license deleted", "license [$l->key] deleted with refund of invoice [$invoice_id]");
            $l->disable();
        }
    }

    function onGetPermissionsList(Am_Event $event)
    {
        $event->addReturn(___('Can manage software licensing schemes'), Bootstrap_Softsale::ADMIN_PERM_CONFIG_ID);
        $event->addReturn(___('Can manage software licenses'), Bootstrap_Softsale::ADMIN_PERM_ID);
    }

    function onUserMenu(Am_Event $event)
    {
        $user = $event->getUser();
        if($this->getDi()->licenseTable->countByUserId($user->pk())>0)
        {
            $event->getMenu()->addPage(
                array(
                    'id' => 'license',
                    'controller' => 'license',
                    'module' => 'softsale',
                    'label' => ___('Licenses'),
                    'order' => 800,
                )
            );
        }
        else
        {
            $files = $this->getDi()->resourceAccessTable->getAllowedResources($user,
                    SoftsaleFile::ACCESS_TYPE);
            foreach ($files as $k => $file)
            {
                if ($file->hide) { unset($files[$k]); continue; }
                if (!($file->getUploads(true))) { unset($files[$k]); continue; }
            }
            if (count($files)) {
                $event->getMenu()->addPage(
                    array(
                        'id' => 'download',
                        'action' => 'download',
                        'controller' => 'license',
                        'module' => 'softsale',
                        'label' => ___('Downloads'),
                        'order' => 800,
                    )
                );
            }

        }
    }

    function onGetResourceTypes(Am_Event $event)
    {
        if ($event->getType() == ResourceAccess::USER_VISIBLE_TYPES) {
            $return = $event->getReturn();
            array_push($return, SoftsaleFile::ACCESS_TYPE);
            $event->setReturn($return);
        }
    }

    function onInitAccessTables(Am_Event $event)
    {
        $event->getRegistry()->registerAccessTable($this->getDi()->softsaleFileTable);
    }

    function onAccessAfterUpdate(Am_Event $event)
    {
        $access = $event->getAccess();
        $old = $event->getOld();
        if(
            ($access->expire_date != $old->expire_date)
            && ($licenses = $this->getDi()->licenseTable->findBy(array(
                'user_id' => $access->user_id,
                'invoice_id'=>$access->invoice_id,
                'invoice_item_id' => $access->invoice_item_id
                ))))
        {
            foreach($licenses as $license)
                if(empty($license->getScheme()->valid_to))
                {
                    $oldExpire = $license->expires;

                    $license->expires = sprintf('%s 23:59:59', $this->getDi()->db->selectCell(""
                        . "SELECT MAX(expire_date) "
                        . "FROM ?_access "
                        . "WHERE user_id = ? AND  invoice_id=? AND  invoice_item_id = ?",
                        $access->user_id, $access->invoice_id, $access->invoice_item_id));
                    $license->update();
                    $this->getDi()->licenseLogTable->log("license expiration date changed", "Expiration date for license [$license->key] has been changed. Old value[$oldExpire] new value [$license->expires]");

                }
        }
    }
}