<?php

/**
 * Plugin allows to issue serials from pre-defined list to customers
 */

class Am_Plugin_Serials extends Am_Plugin
{
    const PLUGIN_COMM = self::COMM_COMMERCIAL;
    const PLUGIN_REVISION = '5.3.2';
    protected $_configPrefix = 'misc.';

    static function getDbXml()
    {
        return <<<CUT
<schema version="4.0.0">
    <table name="serial">
        <field name="serial_id" type="int" unsigned="1" notnull="1" extra="auto_increment"/>
        <field name="serial" type="varchar" len="255"/>
        <field name="invoice_id" type="int" unsigned="1"/>
        <field name="invoice_item_id" type="int" unsigned="1"/>
        <index name="PRIMARY" unique="1">
            <field name="serial_id" />
        </index>
        <index name="serial" unique="1">
            <field name="serial" />
        </index>
    </table>
</schema>
CUT;
    }

    protected function _initSetupForm(Am_Form_Setup $form)
    {
        $form->addMagicSelect('products')
            ->setLabel('Issue Serials for the following Products')
            ->loadOptions($this->getDi()->productTable->getOptions());

        $root = $this->getDi()->url('admin-serial');
        $form->addHtml()
            ->setHtml("<a href='$root' target='_blank' class='link'>Manage Serial Numbers</a>");
    }

    public function onUserMenu(Am_Event $e)
    {
        $e->getMenu()->addPage(array(
            'id' => 'serials',
            'label' => ___('Serial Numbers'),
            'controller' => 'serials',
            'order' => 100,
        ));
    }

    public function onInvoiceStarted(Am_Event $event)
    {
        $invoice = $event->getInvoice();
        /* @var $invoice Invoice */
        $products = $this->getConfig('products', array());
        foreach ($invoice->getItems() as $it) {
            if (in_array($it->item_id, $products)) {
                $this->getDi()->serialTable->issue($it, $it->qty);
            }
        }
    }
}

class SerialsController extends Am_Mvc_Controller
{
    public function indexAction()
    {
        $user = $this->getDi()->user;
        $serials = $this->getDi()->serialTable->findByUser($user);
        $html = "";
        foreach ($serials as $serial) {
            $html .= "<pre>" . $serial->serial . "</pre><br />";
        }
        $this->view->content = $html;
        $this->view->title = "Your Serial Numbers";
        $this->view->display('member/layout.phtml');
    }
}

class AdminSerialController extends Am_Mvc_Controller_Grid
{
    public function checkAdminPermissions(Admin $admin)
    {
        return $admin->isSuper();
    }

    public function createGrid()
    {
        $ds = new Am_Query($this->getDi()->serialTable);
        $t = $ds->getAlias();
        $ds->leftJoin('?_invoice', 'i', "i.invoice_id=$t.invoice_id");
        $ds->leftJoin("?_user", 'u', 'u.user_id=i.user_id');
        $ds->addField('i.public_id', 'i_invoice');
        $ds->addField('u.login', 'u_user');
        $grid = new Am_Grid_Editable('_serial', "Serial Numbers", $ds, $this->_request, $this->view);
        $grid->setFilter(new Am_Grid_Filter_Text("Lookup by Serial", 'serial'));
        $grid->actionDelete('edit');
        $grid->actionDelete('insert');
        $grid->actionAdd(new Am_Grid_Action_SerialUpload())->setTarget('_top');

        $grid->addField('serial', "Serial");
        $grid->addField('u_user', "User");
        $grid->addField('i_invoice', "Invoice");

        return $grid;
    }
}

class Am_Grid_Action_SerialUpload extends Am_Grid_Action_Abstract
{
    protected $type = self::NORECORD;
    protected $id='serial-upload', $title='Upload Serials';

    public function run()
    {
        $serials = $this->grid->getRequest()->get('serials');
        if ($serials) {
            $table = $this->grid->getDi()->serialTable;
            $fail = $done = 0;
            foreach (explode("\n", $serials) as $s) {
                $s = trim($s);
                try {
                    $table->insert(array('serial' => $s));
                    $done++;
                } catch (Exception $e) {
                    echo "Cannot insert serial [$s] - " . $e->getMessage() . "\n<br />";
                    $fail++;
                }
            }
            echo $this->renderBackButton("Import Finished. $done records added, $fail errors");
        } else {
            $html = "<br />Please copy/paste serial numbers, one per line - no additional information please.<br /> Please be careful, there is no UNDO!<br />";
            $html .= "<textarea name='{$this->grid->getId()}_serials' cols=40 rows=15></textarea><br />";
            echo $this->renderConfirmationForm("Continue", $html);
        }
    }
}

/**
 * @property int $serial_id
 * @property string $serial
 * @property int $invoice_id
 * @property int $invoice_item_id
 */
class Serial extends Am_Record
{
    public function assign(InvoiceItem $item)
    {
        $this->invoice_id = $item->invoice_id;
        $this->invoice_item_id = $item->pk();
        $this->update();
    }
}

class SerialTable extends Am_Table
{
    protected $_table = '?_serial';
    protected $_key = 'serial_id';

    public function findByUser(User $user)
    {
        return $this->selectObjects("SELECT s.*
            FROM ?_serial s
                INNER JOIN ?_invoice i USING (invoice_id)
            WHERE i.user_id = ?d", $user->pk());
    }

    public function issue(InvoiceItem $item, $qty = 1)
    {
        $recs = $this->selectObjects("SELECT * FROM ?_serial WHERE invoice_item_id IS NULL LIMIT ?d", $qty);
        if (count($recs) != $qty) {
            $this->getDi()->errorLogTable->log("Cannot fetch new serial for invoice #$item->invoice_id : no [$qty] unused serial numbers!");
            return false;
        }
        foreach ($recs as $serial) {
            $serial->assign($item);
        }
        return $qty;
    }
}