<?php
class flowCommon extends commonModel
{
    /**
     * Load custom lang.
     *
     * @access public
     * @return void
     */
    public function loadCustomLang()
    {
        if(defined('IN_UPGRADE') and IN_UPGRADE) return;
        $query      = $this->dao->get();
        $flows      = $this->loadModel('workflow', 'flow')->getList('browse', $type = '', $status = '');  // Must assign empty string to the parameter $type and $status.
        $flowFields = $this->loadModel('workflowfield', 'flow')->getGroupList();
        foreach($flows as $flow)
        {
            if(!isset($this->lang->{$flow->module})) $this->lang->{$flow->module} = new stdclass();

            $fields = zget($flowFields, $flow->module, array());
            foreach($fields as $field)
            {
                if($flow->module && $field->field) $this->lang->{$flow->module}->{$field->field} = $field->name;
            }
        }

        if(!empty($query)) $this->dao->sqlobj->sql = $query;
    }

    /**
     * Merge lang from flow.
     *
     * @access public
     * @return void
     */
    public function mergeLangFromFlow()
    {
        if(defined('IN_UPGRADE')) return;
        if(!$this->config->db->name) return;

        $this->app->setOpenApp();

        $rawModule = $this->app->rawModule;
        $rawMethod = $this->app->rawMethod;
        $tab       = $this->app->tab;

        $primaryFlows   = array();
        $secondaryFlows = array();
        $flows          = $this->dao->select('*')->from(TABLE_WORKFLOW)->where('buildin')->eq('0')->andWhere('vision')->eq($this->config->vision)->andWhere('status')->eq('normal')->andWhere('type')->eq('flow')->orderBy('navigator_asc')->fetchAll('id');
        foreach($flows as $flow)
        {
            if($flow->navigator == 'primary') $primaryFlows[$flow->module] = $flow;

            $flowApp = $flow->app;
            if($flowApp == 'scrum' or $flowApp == 'waterfall') $flowApp = 'project';
            if($flow->navigator == 'secondary' and ($flowApp == $tab or $tab == 'workflow')) $secondaryFlows[$flow->module] = $flow;
        }

        $this->sortFlows($primaryFlows, 'primary');
        $isLogon = $this->loadModel('user')->isLogon();

        /* If main nav has workflow, load menuOrders from lang table. */
        //if(!empty($primaryFlows)) $this->app->LoadLang('mainNav');

        foreach($primaryFlows as $flow)
        {
            $this->lang->{$flow->module} = new stdclass();
            $this->lang->{$flow->module}->common  = $flow->name;
            $this->lang->mainNav->{$flow->module} = "{$this->lang->navIcons['workflow']} {$flow->name}|{$flow->module}|browse|";
            if($tab == $flow->module)
            {
                $flowLabels = $this->dao->select('*')->from(TABLE_WORKFLOWLABEL)->where('module')->eq($flow->module)->orderBy('`order`')->fetchAll('id');
                foreach($flowLabels as $flowLabel)
                {
                    if($isLogon and !common::hasPriv($flow->module, $flowLabel->id)) continue;

                    if(!isset($this->lang->{$flow->module})) $this->lang->{$flow->module} = new stdclass();
                    if(!isset($this->lang->{$flow->module}->menu)) $this->lang->{$flow->module}->menu = new stdclass();
                    $this->lang->{$flow->module}->menu->{$flowLabel->code} = array('link' => "{$flowLabel->label}|{$flowLabel->module}|browse|label={$flowLabel->id}");
                    $this->lang->{$flow->module}->menuOrder[$flowLabel->order] = $flowLabel->code;
                }

                if($isLogon and commonModel::hasPriv($flow->module, 'report'))
                {
                    $this->app->loadLang('workflowaction');
                    $this->lang->{$flow->module}->menu->report = array('link' => $this->lang->workflowaction->default->actions['report'] . "|{$flow->module}|report|module={$flow->module}");
                    $this->lang->{$flow->module}->menuOrder[] = 'report';
                }
            }
        }

        $this->sortFlows($secondaryFlows, 'secondary');
        foreach($secondaryFlows as $flow)
        {
            $flowApp = ($this->config->vision == 'lite' and $flow->app == 'project') ? 'kanban' : $flow->app;
            $this->lang->{$flow->module} = new stdclass();
            $this->lang->{$flow->module}->common = $flow->name;
            $this->lang->{$flowApp}->menu->{$flow->module} = array('link' => "{$flow->name}|{$flow->module}|browse|");
        }

        if($this->app->isFlow)
        {
            if($tab == 'product' or $tab == 'qa')
            {
                $products  = $this->loadModel('product')->getPairs('nocode');
                $productID = $this->product->saveState(0, $products);
                $branch    = (int)$this->cookie->preBranch;
                if($tab == 'product') $this->product->setMenu($productID, $branch, 0);
                if($tab == 'qa') $this->loadModel('qa')->setMenu($products, $productID, $branch);
            }
            elseif($tab == 'project')
            {
                $projects  = $this->loadModel('project')->getPairsByProgram();
                $projectID = $this->project->saveState($this->session->project, $projects);
                $this->project->setMenu($projectID);
            }
            elseif($tab == 'execution')
            {
                $this->loadModel('execution')->setMenu($this->session->execution);
            }
        }
    }

    public function sortFlows($flows, $navigator = 'primary')
    {
        $tab       = $this->app->tab;
        $menuOrder = array();
        $waterfallOrder = array();
        if($navigator == 'primary')
        {
            $menuOrder = $this->lang->mainNav->menuOrder;
        }
        elseif($navigator == 'secondary')
        {
            if($tab == 'project')
            {
                $menuOrder = $this->lang->scrum->menuOrder;
                if(isset($this->lang->waterfall->menuOrder)) $waterfallOrder = $this->lang->waterfall->menuOrder;
                if($this->config->vision == 'lite') $menuOrder = $this->lang->kanban->menuOrder;
            }
            elseif(isset($this->lang->{$tab}->menuOrder))
            {
                $menuOrder = $this->lang->{$tab}->menuOrder;
            }
        }
        if(empty($menuOrder) and empty($waterfallOrder)) return true;

        $waterfallFlows = array();
        foreach($flows as $module => $flow)
        {
            if($flow->app != 'waterfall') $menuOrder[] = $flow->module;
            if($flow->app == 'waterfall')
            {
                $waterfallOrder[] = $flow->module;
                $waterfallFlows[$module] = $flow;
                unset($flows[$module]);
            }
        }
        $waterfallOrderFlip = array_flip($waterfallOrder);
        $menuOrderFlip = array_flip($menuOrder);

        foreach($flows as $flow)
        {
            if($flow->app != 'waterfall') $menuOrderFlip = $this->computeMenuOrder($flow, $menuOrderFlip, $flows);
            if($flow->app == 'waterfall') $waterfallOrderFlip = $this->computeMenuOrder($flow, $waterfallOrderFlip, $waterfallFlows);
        }

        $menuOrder = $this->flipMenuOrder($menuOrderFlip);
        $waterfallOrder = $this->flipMenuOrder($waterfallOrderFlip);
        if($navigator == 'primary')
        {
            $this->lang->mainNav->menuOrder = $menuOrder;
        }
        elseif($navigator == 'secondary')
        {
            if($tab == 'project')
            {
                $this->lang->scrum->menuOrder = $menuOrder;
                if(isset($this->lang->waterfall->menuOrder)) $this->lang->waterfall->menuOrder = $waterfallOrder;
                if($this->config->vision == 'lite') $this->lang->kanban->menuOrder = $menuOrder;
            }
            elseif(isset($this->lang->{$tab}->menuOrder))
            {
                $this->lang->{$tab}->menuOrder = $menuOrder;
            }
        }

        return true;
    }

    public function computeMenuOrder($flow, $menuOrderFlip, $flows)
    {
        static $computedModules = array();
        if(isset($computedModules[$flow->module])) return $menuOrderFlip;

        if(strpos($flow->position, 'before') === 0 or strpos($flow->position, 'after') === 0)
        {
            $computedModules[$flow->module] = true;

            $mode   = strpos($flow->position, 'before') === 0 ? 'before' : 'after';
            $module = substr($flow->position, strlen($mode));
            if(isset($flows[$module]) and $module != $flow->module and !isset($computedModules[$module])) $menuOrderFlip = $this->computeMenuOrder($flows[$module], $menuOrderFlip, $flows);

            if(isset($menuOrderFlip[$module]))
            {
                $order = $menuOrderFlip[$module];
                $order = $mode == 'before' ? (string)($order - 0.05) : (string)($order + 0.05);
                $menuOrderFlip[$flow->module] = $order;
            }
        }

        return $menuOrderFlip;
    }

    public function flipMenuOrder($orderFlip, $menuOrder = array(), $moduleName = '')
    {
        if($moduleName)
        {
            $order = $orderFlip[$moduleName];
            if(isset($menuOrder[$order]))
            {
                $orderFlip[$moduleName] = $order + 0.01;
                return $this->flipMenuOrder($orderFlip, $menuOrder, $moduleName);
            }
            else
            {
                $menuOrder[(string)$order] = $moduleName;
                return $menuOrder;
            }
        }

        foreach($orderFlip as $module => $order)
        {
            if(isset($menuOrder[$order]))
            {
                $orderFlip[$module] = $order + 0.01;
                $menuOrder = $this->flipMenuOrder($orderFlip, $menuOrder, $module);
            }
            else
            {
                $menuOrder[(string)$order] = $module;
            }
        }
        return $menuOrder;
    }
}
