<?php

/**
 * @am_plugin_api 6.0
 * @setup_url default/admin-content/p/widget
 */
class Am_Plugin_Widget extends Am_Plugin
{
    const PLUGIN_STATUS = self::STATUS_PRODUCTION;
    const PLUGIN_COMM = self::COMM_COMMERCIAL;
    const PLUGIN_REVISION = '6.3.43';

    const EVENT_ID = 'widgetBeforeRender';
    const EVENT_ID_GET_TARGET = 'widgetGetTargetList';

    protected $_configPrefix = 'misc.';

    static function getDbXml()
    {
        return <<<CUT
<schema version="4.0.0">
    <table name="widget">
        <field name="widget_id" type="int" unsigned="1" notnull="1" extra="auto_increment"/>
        <field name="target" type="text" />
        <field name="title" type="varchar" len="255" notnull="0" />
        <field name="content" type="text" />
        <field name="not_conditions" type="varchar" len="255" notnull="0" />
        <field name="not_conditions_expired" type="tinyint" notnull="0" />
        <field name="not_conditions_future" type="tinyint" notnull="0" />
        <field name="order" type="int" />
        <index name="PRIMARY" unique="1">
            <field name="widget_id"/>
        </index>
    </table>
</schema>
CUT;
    }

    function onDbSync(Am_Event $e)
    {
        parent::onDbSync($e);
        foreach ($this->getDi()->db->selectPage($total, "SELECT widget_id, target FROM ?_widget") as $row) {
            if (!is_array(@json_decode($row['target'], true))) {
                $target = json_encode([$row['target']]);
                $this->getDi()->db->query("UPDATE ?_widget SET target=? WHERE widget_id=?", $target, $row['widget_id']);
            }
        }
    }

    function onInitAccessTables(Am_Event $e)
    {
        $e->getRegistry()->registerAccessTable($this->getDi()->widgetTable);
    }

    function onInitBlocks(Am_Event $e)
    {
        if ($this->getDi()->auth->getUserId()) {
            if ($resources = $this->getDi()->resourceAccessTable
                ->getAllowedResources($u = $this->getDi()->user, WidgetRecord::ACCESS_TYPE)) {

                $t = new Am_SimpleTemplate;
                $t->assign('user', $u);

                foreach ($resources as $w) {
                    if (!$this->hasAccess($u, $w)) continue;
                    $targets = @json_decode($w->target, true);

                    if (empty($targets))
                        continue;

                    foreach ($targets as $target) {
                        $e->getBlocks()->add(
                            $target,
                            new Am_Block_Base($t->render(___($w->title)), "widget-{$target}-{$w->pk()}", null,
                                function(Am_View $v) use ($w, $t, $u){
                                    $e = new Am_Event_WidgetBeforeRender(self::EVENT_ID, [
                                        'template' => $t,
                                        'user' => $u,
                                        'widget' => $w,
                                        'html' => $w->content,
                                    ]);
                                    $this->getDi()->hook->call($e);

                                    return $t->render($e->getHtml());
                                }),
                            $w->order ?: Am_Blocks::MIDDLE
                        );
                    }
                }
            }
        }
    }

    function hasAccess(User $user, ResourceAbstract $r)
    {
        return !$r->not_conditions || $this->checkNotConditions($user, $r);
    }

    public function checkNotConditions(User $user, ResourceAbstract $r)
    {
        $pids = [];
        $catp = null;
        foreach (array_filter(explode(',', $r->not_conditions)) as $s)
        {
            if ($s == 'c-1') {
                if ($r->not_conditions_future && $user->getFutureProductIds()) {
                    return false;
                }
                if (!$r->not_conditions_expired) {
                    return $user->status != User::STATUS_ACTIVE;
                } else {
                    return $user->status == User::STATUS_PENDING;
                }
            } elseif ($s[0] == 'p') {
                $pids[] = substr($s, 1);
            } elseif ($s[0] == 'c') {
                if (!$catp)
                    $catp = $this->getDi()->productCategoryTable->getCategoryProducts(true);
                if (!empty($catp[substr($s, 1)]))
                    $pids = array_merge($pids, $catp[substr($s, 1)]);
            }
        }
        if (!$pids) return true;
        $userPids = $user->getActiveProductIds();
        if ($r->not_conditions_expired)
            $userPids = array_merge($userPids, $user->getExpiredProductIds());
        if ($r->not_conditions_future)
            $userPids = array_merge($userPids, $user->getFutureProductIds());

        return !$pids || !array_intersect($pids, $userPids);
    }
}

class WidgetRecord extends ResourceAbstract
{
    const ACCESS_TYPE = 'widget';
}

/** @extends ResourceAbstractTable<WidgetRecord> */
class WidgetTable extends ResourceAbstractTable
{
    protected $_table = '?_widget';
    protected $_key = 'widget_id';
    protected $_recordClass = 'WidgetRecord';

    public function getAccessType()
    {
        return WidgetRecord::ACCESS_TYPE;
    }

    public function getAccessTitle()
    {
        return ___('Widget');
    }

    public function getPageId()
    {
        return WidgetRecord::ACCESS_TYPE;
    }
}

class Am_Grid_Editable_Widget extends Am_Grid_Editable_Content
{
    public function __construct(Am_Mvc_Request $request, Am_View $view)
    {
        parent::__construct($request, $view);
        $this->setFilter(new Am_Grid_Filter_Content_Common);
        $this->setFormValueCallback('not_conditions',
            ['RECORD', 'unserializeList'],
            ['RECORD', 'serializeList']);
        $this->setFormValueCallback('target',
            function($value){
                return json_decode($value, true);
            },
            function($value){
                return json_encode($value);
            });
    }

    public function initActions()
    {
        parent::initActions();
        $this->actionAdd(new Am_Grid_Action_Group_ContentSetAccessPermission);
        $this->actionAdd(new Am_Grid_Action_Group_Delete);
    }

    protected function initGridFields()
    {
        $this->addField('title', ___('Title'))->setRenderFunction([$this, 'renderAccessTitle']);
        parent::initGridFields();
    }

    protected function createAdapter()
    {
        return new Am_Query(Am_Di::getInstance()->widgetTable);
    }

    function createForm()
    {
        $r = $this->getRecord();
        $form = new Am_Form_Admin('widget-' . ($r->isLoaded() ? $r->pk() : 'new'));

        $targets = [
            'member/main/top' => ___('Dashboard') . " / " . ___('Top'),
            'member/main/left' => ___('Dashboard') . " / " . ___('Left Column'),
            'member/main/right' => ___('Dashboard') . " / " . ___('Right Column'),
            'member/main/bottom' => ___('Dashboard') . " / " . ___('Bottom'),
            'member/profile/top' => ___('Profile Form') . " / " . ___('Top'),
            'member/profile/bottom' => ___('Profile Form') . " / " . ___('Bottom'),
            'signup/form/before' => ___('Signup Form') . " / " . ___('Top'),
            'signup/form/after' => ___('Signup Form') . " / " . ___('Bottom'),
            'member/payment-history/top' => ___('Payments History') . " / " . ___('Top'),
            'payment-history/center' => ___('Payments History') . " / " . ___('Middle'),
            'member/payment-history/bottom' => ___('Payments History') . " / " . ___('Bottom'),
            'member/category/top' => ___('Content Category') . " / " .___('Top'),
            'member/category/bottom' => ___('Content Category') . " / " .___('Bottom'),
            'content/before' => ___('All Pages') . " / " . ___('Top'),
        ];

        $targets = $this->getDi()->hook->filter($targets, Am_Plugin_Widget::EVENT_ID_GET_TARGET);

        $form->addMagicSelect('target', ['class'=> 'am-combobox'])
            ->setLabel(___('Target'))
            ->loadOptions($targets);

        $form->addInteger('order', ['placeholder' => Am_Blocks::MIDDLE])
            ->setLabel(___('Sort Order'));

        $form->addText('title', ['class' => 'am-el-wide translate'])
            ->setLabel(___('Title'));

        $placeholder_items = & $options['placeholder_items'];
        foreach ($this->getUserTagOptions() as $k => $v) {
            $placeholder_items[] = [$v, $k];
        }

        $form->addHtmlEditor('content')
            ->setMceOptions($options);

        $form->addElement(new Am_Form_Element_ResourceAccess)
            ->setName('_access')
            ->setLabel(___('Access Permissions'))
            ->setAttribute('without_free_without_login', 'true');

        $group = $form->addGroup()
            ->setLabel(___('Show Widget only if customer has no subscription (optional)'));
        $group->setSeparator('<br />');

        $select = $group->addMagicSelect('not_conditions', ['class'=>'am-combobox']);
        $this->addCategoriesProductsList($select);
        $group->addAdvCheckbox('not_conditions_expired')
            ->setContent(___('check expired subscriptions too'));
        $group->addAdvCheckbox('not_conditions_future')
            ->setContent(___('check future subscriptions too'));

        return $form;
    }

    function addCategoriesProductsList(HTML_QuickForm2_Element_Select $select)
    {
        $g = $select->addOptgroup(___('Product Categories'),
            ['class' => 'product_category_id', 'data-text' => ___("Category")]);
        $g->addOption(___('Any Product'), 'c-1', ['style' => 'font-weight: bold']);
        foreach ($this->getDi()->productCategoryTable->getAdminSelectOptions() as $k => $v) {
            $g->addOption($v, 'c' . $k);
        }
        $g = $select->addOptgroup(___('Products'), ['class' => 'product_id', 'data-text' => ___("Product")]);
        foreach ($this->getDi()->productTable->getOptions() as $k => $v) {
            $g->addOption($v, 'p' . $k);
        }
    }

    function getUserTagOptions()
    {
        $tagOptions = [
            '%user.name_f%' => 'User First Name',
            '%user.name_l%' => 'User Last Name',
            '%user.login%' => 'Username',
            '%user.email%' => 'E-Mail',
            '%user.user_id%' => 'User Internal ID#',
            '%user.street%' => 'User Street',
            '%user.street2%' => 'User Street (Second Line)',
            '%user.city%' => 'User City',
            '%user.state%' => 'User State',
            '%user.zip%' => 'User ZIP',
            '%user.country%' => 'User Country',
            '%user.status%' => 'User Status (0-pending, 1-active, 2-expired)'
        ];

        foreach ($this->getDi()->userTable->customFields()->getAll() as $field) {
            if (!empty($field->sql) && !empty($field->from_config)) {
                $tagOptions["%user.{$field->name}%"] = "User {$field->title}";
            }
        }

        return $tagOptions;
    }
}

class Am_Event_WidgetBeforeRender extends Am_Event
{
    function setHtml($html)
    {
        $this->vars['html'] = $html;
    }
}