<?php
/**
 * Created by IntelliJ IDEA.
 * User: zhuxun37
 * Date: 2017/5/16
 * Time: 下午6:28
 */

namespace Common\Service;


use Com\PythonExcel;
use Common\Common\Cache;
use Common\Common\Constant;
use Common\Common\Department;
use Common\Common\ExportDownload;
use Common\Common\User;

class DepartmentService extends AbstractService
{

    protected $_fixTitles = array(
        'departmentPath' => '组织路径',
        'departmentName' => '组织名称',
        'dpSerialNum' => '组织编号',
        'dptId' => '组织类型',
        'dpLead' => '组织负责人',
    );

    // 构造方法
    public function __construct()
    {

        parent::__construct();
    }

    /**
     * 导入数据
     * @param $result
     * @param $department
     * @param $request
     * @return bool
     */
    public function prepareImport(&$result, &$department, $request)
    {

        $result['finish'] = 0;
        $index = (int)$request['index'];
        $title_id = (int)$request['title_id'];
        // 读取 title 和待导入数据
        $importDataService = new ImportDataService();
        $dataList = $importDataService->list_by_pks(array($title_id, $index));
        $dataList = array_combine_by_key($dataList, 'cid_id');

        // 获取组织类型
        $titleData = json_decode($dataList[$title_id]['data']);
        $departmentData = json_decode($dataList[$index]['data']);
        // 新增导入失败原因
        $titleData[] = '失败原因';
        $result['title'] = $titleData;
        $result['data'] = $departmentData;
        $this->_getDepartmentType($type, $titleData, $departmentData);
        if (empty($type)) {
            E('1003:组织类型不存在');

            return false;
        }

        // 获取顶级部门, 确认顶级部门必须存在
        Department::instance()->get_top_dpId($topDpId);
        if (empty($topDpId)) {
            $result['finish'] = 1;
            E('1004:顶级组织不存在, 请先同步');

            return false;
        }

        // 重新整理组织数据
        list($titles, $configs) = $this->_generateTitleByType($type);
        $titleDataFlip = array_flip($titleData);
        $department = array(
            'extList' => array(),
        );
        foreach ($titles as $_k => $_title) {
            $index = $titleDataFlip[$_title];
            $department[$_k] = $departmentData[$index];

            // 处理组织名称
            if ('departmentPath' == $_k) {
                $indexName = $titleDataFlip[$titles['departmentName']];
                // 组织名称必填 (2017-10-30 16:46:23 修改报错信息)
                if (empty($departmentData[$indexName])) {
                    E('1007:组织名称必填');
                }
                $this->getDepartmentByPath($department, $department[$_k], $departmentData[$indexName]);
                unset($department[$_k]);
            } elseif ('departmentName' == $_k) { // 忽略部门名称
                unset($department[$_k]);
                continue;
            } elseif ('dpLead' == $_k && !empty($department[$_k])) {
                $user = new User();
                $conds = array('memUsername' => $department[$_k]);
                $leadList = $user->listByConds($conds);
                if (1 == count($leadList['list'])) {
                    $department[$_k] = $leadList['list'][0]['memUid'];
                } else {
                    $department[$_k] = '';
                }
                continue;
            }

            // 处理组织类型
            if ('dptId' == $_k) {
                $department[$_k] = $type['dptId'];
            }

            // 如果不是扩展数据
            if (empty($configs[$_k])) {
                continue;
            }

            // 如果扩展信息为空
            if (empty($department[$_k])) {
                unset($department[$_k]);
                continue;
            }

            // 如果是 areaselect
            if ('select' == $configs[$_k]['dfcType']) { // 如果是 select
                foreach ($configs[$_k]['dfcValues'] as $_val) {
                    if ($_val['name'] == $department[$_k]) {
                        $department['extList'][$_k] = $_val['id'];
                        break;
                    }
                }
            } else {
                $department['extList'][$_k] = $department[$_k];
            }

            unset($department[$_k]);
        }

        // 重新整理地区数据
        foreach ($department['extList'] as $_k => $_val) {
            if ('areaselect' == $configs[$_k]['dfcType']) {
                $department['extList'][$_k] = rjson_encode(array(
                    'province' => $_val,
                    'city' => $department[$_k . 'city'],
                    'town' => $department[$_k . 'town'],
                ));
                unset($department[$_k . 'city'], $department[$_k . 'town']);
            }
        }

        return true;
    }

    /**
     * 根据部门路径获取部门ID
     * @param $currentDepartment
     * @param $path
     * @param $name
     * @param $isEdit
     * @return bool
     */
    public function getDepartmentByPath(&$currentDepartment, $path, $name = '', $isEdit = true)
    {
        $dpServ = &Department::instance();
        $dpServ->get_top_dpId($topDpId);
        // 2017-10-02 14:02:37 zhoutao
        // 获取顶级部门 方法返回的数据格式 因为可能会有多个顶级的情况 故修改为 数组
        // 这里导入部门 前提肯定是装了通讯录 装了通讯录获取到的顶级部门只会有一个
        $topDpId = $topDpId[0];
        if (empty($topDpId)) {
            E('1004:顶级组织不存在, 请先同步');
        }

        if (empty($path)) {
            E('_ERR_EXCEL_DEP_PATH');
        }

        // 获取部门路径上的所有部门名称
        if (!empty($name)) {
            $path = $path . '/' . $name;
        }

        $path = str_replace('\\', '/', $path);
        $path = preg_replace('/\/+/i', '/', $path);
        $dpNames = explode('/', $path);
        // 验证部门路径上的部门是否存在
        list($currentDpId, $allDepartment, $currentDepartment) =
            $this->verifyDepPath($currentDepartment, $dpNames, $topDpId);
        if (!empty($currentDepartment['dpParentid'])) {
            return true;
        }

        // 如果修改的是顶级部门, 则报错
        if ($isEdit && $currentDpId == $topDpId && 1 == count($dpNames)) {
            E('1006:顶级部门不允许更改');
        }

        $currentDepartment['dpId'] = $allDepartment[$currentDpId]['dpId'];
        $currentDepartment['dpParentid'] = $allDepartment[$currentDpId]['dpParentid'];
        $currentDepartment['dpName'] = $allDepartment[$currentDpId]['dpName'];

        return true;
    }

    /**
     * 根据部门名称从关联部门信息中获取部门ID
     * @param $dpId
     * @param $parentId
     * @param $dpName
     * @param $relateDps
     * @return bool
     */
    protected function _getDpIdFromRelateDps(&$dpId, $parentId, $dpName, $relateDps)
    {
        foreach ($relateDps as $_dp) {
            if ($parentId == $_dp['dpParentid'] && $dpName == $_dp['dpName']) {
                $dpId = $_dp['dpId'];

                return true;
            }
        }

        return false;
    }

    /**
     * 根据部门类型生成完整的 title
     * @param $type
     * @return array
     */
    protected function _generateTitleByType($type)
    {

        $titles = $this->_fixTitles;
        $fieldConfigs = Cache::instance()->get('Common.DepartmentFieldConfig');
        $configs = $fieldConfigs[$type['dptId']];
        foreach ($configs as $_config) {
            if ('areaselect' == $_config['dfcType']) {
                $titles[$_config['dfcId']] = $_config['dfcName'] . '(省)';
                $titles[$_config['dfcId'] . 'city'] = $_config['dfcName'] . '(市)';
                $titles[$_config['dfcId'] . 'town'] = $_config['dfcName'] . '(区)';
            } else {
                $titles[$_config['dfcId']] = $_config['dfcName'];
            }
        }

        return array($titles, $configs);
    }

    /**
     * 获取部门类型数据
     * @param $type
     * @param $title
     * @param $data
     * @return bool
     */
    protected function _getDepartmentType(&$type, $title, $data)
    {

        $type = array();
        $typeIndex = 0;
        foreach ($title as $_index => $_title) {
            if ('组织类型' == $_title) {
                $typeIndex = $_index;
                break;
            }
        }

        $typeName = $data[$typeIndex];
        if (empty($typeName)) {
            return false;
        }

        $types = Cache::instance()->get('Common.DepartmentType');
        foreach ($types as $_type) {
            if ($typeName == $_type['dptName']) {
                $type = $_type;

                return true;
            }
        }

        return false;
    }

    /**
     * 读取 Excel 文件, 为导入做准备
     * @param $result
     * @param $request
     * @param $user
     * @return bool
     */
    public function readExcel(&$result, $request, $user)
    {

        // 分页和每页数
        $page = (int)$request['page'];
        $limit = (int)$request['limit'];
        $start = $limit * ($page - 1) + Constant::DP_IMPORT_START;
        $result = array(
            'rowsReaded' => 0,
            'page' => $page,
            'limit' => $limit,
        );

        // 附件Url
        $attachmentUrl = $request['attachmentUrl'];
        //list($attachmentUrl,) = explode('?', $attachmentUrl);
        //$attachmentUrl = str_replace('http://t-rep.vchangyi.com/', '/Users/zhuxun37/web/javaDownloads/', $attachmentUrl);
        if (empty($attachmentUrl)) {
            E('1002:Excel文件地址为空');

            return false;
        }

        // 导入唯一标识
        $importFlag = $request['importFlag'];
        if (empty($importFlag)) {
            $importFlag = NOW_TIME . random(8);
        }
        $result['importFlag'] = $importFlag;

        // 获取附件
        $localFile = get_sitedir() . $importFlag . '.xls';
        if (!file_exists($localFile)) {
            file_put_contents($localFile, file_get_contents($attachmentUrl));
        }

        // 如果文件大小为 0
        if (0 >= filesize($localFile)) {
            E('1004:Excel文件错误或文件内容为空');

            return false;
        }

        $importDataService = new ImportDataService();

        // 读取指定行
        $data = PythonExcel::instance()->read($localFile, $start, $start + $limit);
        if (empty($data)) {
            return true;
        }

        // 删除默认数据
        unset($data[1]);

        $result['rowsReaded'] = count($data);
        // 默认表头没有失败原因一列
        $existMessage = false;
        // 最后一列索引
        $i = 0;
        // 如果是第一页, 则需要额外保存表头
        if (1 == $page) {
            // 校验表头是否有多出的'失败原因'一列,有的话需要过滤掉
            $exceHead = $data[0];
            $i = count($exceHead) - 1;
            if ($exceHead[$i] == '失败原因') {
                $existMessage = true;
                array_splice($exceHead, $i, 1);
            }

            $importDataService->insert(array(
                'ea_id' => $user['eaId'],
                'import_flag' => $importFlag,
                'data_type' => 'title',
                'data' => rjson_encode($exceHead),
            ));
            unset($data[0]);
        }

        // 其他数据入库
        $insertData = array();
        foreach ($data as $_data) {
            if ($existMessage) {
                array_splice($_data, $i, 1);
            }

            $insertData[] = array(
                'ea_id' => $user['eaId'],
                'import_flag' => $importFlag,
                'data_type' => 'department',
                'data' => rjson_encode($_data),
            );
        }
        $importDataService->insert_all($insertData);

        return true;
    }

    // 导出模板
    public function exportTpl()
    {
        $data = [];

        list($titles,) = $this->_generateTitle();

        $this->_forExportTitle($titles);

        // 初始化标题简介数据
        $merge_titles = Constant::DP_LIST_TITLES_DESC;
        $merge_titles[] = array_values($titles);
        // 初始化默认值数据
        $merge_titles[] = Constant::DP_LIST_DATA;

        // 合并标题到数据中
        $data = array_merge($merge_titles, $data);

        $title_xls[] = '填写说明';

        $filename = NOW_TIME . random(8) . '.xls';
        PythonExcel::instance()->write(get_sitedir() . $filename, $title_xls, $data);

        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control:must-revalidate, post-check=0, pre-check=0");
        header("Content-Type:application/force-download");
        header("Content-Type:application/vnd.ms-execl");
        header("Content-Type:application/octet-stream");
        header("Content-Type:application/download");
        header('Content-Disposition:attachment;filename=departmentTpl.xls');
        header("Content-Transfer-Encoding:binary");
        echo file_get_contents(get_sitedir() . $filename);
        exit;
    }

    /**
     * 导出到下载中心
     * @param array $dp_ids 部门IDS集合
     * @param array $user 后台管理员详情
     */
    public function export($dp_ids = [], $user = [])
    {

        // 生成标题
        list($titles, $mergeConfigs) = $this->_generateTitle();

        if (empty($dp_ids)) {
            $departments = Department::instance()->listAll();
        } else {
            $departments = Department::instance()->listById($dp_ids);
        }

        $types = Cache::instance()->get('Common.DepartmentType');
        $configs = Cache::instance()->get('Common.DepartmentFieldConfig');
        $dfcId2config = array();
        foreach ($configs as $_config) {
            $dfcId2config = array_merge($dfcId2config, $_config);
        }

        // 读取部门负责人信息
        $uids = array_column($departments, 'dpLead');
        $memberList = User::instance()->listByUid($uids);

        // 组织 excel 数据
        $data = array();
        foreach ($departments as $_dp) {
            $row = array();
            // 剔除顶级部门
            if (false === stripos($_dp['departmentPath'], '/', 1)) {
                continue;
            }
            // 根据标题获取组织数据
            foreach ($titles as $_k => $_val) {
                // 组织类型数据
                if ('dptId' == $_k) {
                    $row[] = empty($_dp[$_k]) || empty($types[$_dp[$_k]]) ? '' : $types[$_dp[$_k]]['dptName'];
                    continue;
                } elseif ('departmentPath' == $_k) { // 如果是路径, 则需要拆分成两段
                    $paths = explode('/', $_dp[$_k]);
                    $dpName = array_pop($paths);
                    $row['departmentPath'] = implode('/', $paths);
                    $row['departmentName'] = $dpName;
                    continue;
                } elseif ('departmentName' == $_k) {
                    continue;
                } elseif ('dpLead' == $_k) {
                    $row['dbLead'] = empty($memberList[$_dp[$_k]]) ? '' : $memberList[$_dp[$_k]]['memUsername'];
                    continue;
                }

                // 如果当前键值对应的值为空并且需要合并处理
                if (empty($_dp[$_k]) && isset($mergeConfigs[$_k])) {
                    foreach ($mergeConfigs as $_dfcId) {
                        if (!empty($_dp[$_dfcId])) {
                            $_dp[$_k] = $_dp[$_dfcId];
                        }
                    }
                }

                // 地区数据特殊处理
                if (!empty($dfcId2config[$_k]) && !empty($_dp[$_k]) && 'areaselect' == $dfcId2config[$_k]['dfcType']) {
                    $pct = (array)$_dp[$_k];
                    $row[] = empty($pct['province']) ? '' : $pct['province'];
                    $row[] = empty($pct['city']) ? '' : $pct['city'];
                    $row[] = empty($pct['town']) ? '' : $pct['town'];
                    continue;
                }

                // 选项数据特殊处理
                if (!empty($dfcId2config[$_k]) && !empty($_dp[$_k]) && 'select' == $dfcId2config[$_k]['dfcType']) {
                    $config = $dfcId2config[$_k];
                    $configVals = array_combine_by_key($config['dfcValues'], 'id');
                    $row[$_k] = empty($_dp[$_k]) ? '' : $configVals[$_dp[$_k]]['name'];
                    continue;
                }

                // zhoutao 2017-08-23 15:10:06 修复标题跟 内容不对齐的情况
                if (isset($_dp[$_k])) {
                    $row[$_k] = $_dp[$_k];
                }
            }

            $data[] = array_values($row);
        }

        $this->_forExportTitle($titles);

        // 初始化标题简介数据
        $merge_titles = Constant::DP_LIST_TITLES_DESC;
        $merge_titles[] = array_values($titles);
        // 初始化默认值数据
        $merge_titles[] = Constant::DP_LIST_DATA;

        // 合并标题到数据中
        $data = array_merge($merge_titles, $data);

        $title_xls[] = '填写说明';
        $filename = rgmdate(NOW_TIME, 'Y') . rgmdate(NOW_TIME, 'm') . rgmdate(NOW_TIME, 'd') . '_组织列表';

        $site_dir = ExportDownload::get_down_dir($user['eaId'] . microtime(true));

        $ret = PythonExcel::instance()->write($site_dir . $filename . '.xls', $title_xls, $data);

        if ($ret) {
            $conditon = [
                'title' => $filename,
                'ea_id' => $user['eaId'],
                'username' => $user['eaRealname'],
                'type' => ExportDownload::EXCEL_TYPE,
                'size' => filesize(get_sitedir() . $filename . '.xls'),
                'url' => $site_dir . $filename . '.xls',
                'app_dir' => APP_DIR
            ];

            ExportDownload::insert_down_load($conditon);
        }

        return true;
    }

    /**
     * 整理输出头信息
     * @param $titles
     * @return bool
     */
    protected function _forExportTitle(&$titles)
    {

        $configs = Cache::instance()->get('Common.DepartmentFieldConfig');
        // 必填
        $titles['dptId'] = array(
            'value' => $titles['dptId'],
            'pattern' => array('pattern' => 'solid', 'fore_colour' => 'red', 'width' => '800'),
        );
        $titles['departmentPath'] = array(
            'value' => $titles['departmentPath'],
            'pattern' => array('pattern' => 'solid', 'fore_colour' => 'red'),
        );
        $titles['departmentName'] = array(
            'value' => $titles['departmentName'],
            'pattern' => array('pattern' => 'solid', 'fore_colour' => 'red'),
        );
        foreach ($titles as $_k => $_title) {
            if (!empty($configs[$_k]) && 0 < $configs[$_k]['dfcRequire']) {
                $titles[$_k] = array(
                    'value' => $_title,
                    'pattern' => array('pattern' => 'solid', 'fore_colour' => 'red'),
                );
            }
        }

        return true;
    }

    /**
     * 生成 Excel 标题
     * @return array
     */
    protected function _generateTitle()
    {

        $titles = $this->_fixTitles;
        // 如果有同名字段, 则记录合并
        $mergeConfigs = array();
        $name2id = array();

        $fieldConfigs = Cache::instance()->DepartmentFieldConfig();
        foreach ($fieldConfigs as $_dptId => $_configs) {
            foreach ($_configs as $_cfg) {
                if (isset($name2id[$_cfg['dfcName']])) {
                    $sourceId = $name2id[$_cfg['dfcName']];
                    if (!isset($mergeConfigs[$sourceId])) {
                        $mergeConfigs[$sourceId] = array();
                    }

                    $mergeConfigs[$sourceId][] = $_cfg['dfcId'];
                    continue;
                }

                // 如果是地区类型字段, 则拆成3列
                if ('areaselect' == $_cfg['dfcType']) {
                    $titles[$_cfg['dfcId']] = $_cfg['dfcName'] . '(省)';
                    $titles[$_cfg['dfcId'] . 'city'] = $_cfg['dfcName'] . '(市)';
                    $titles[$_cfg['dfcId'] . 'town'] = $_cfg['dfcName'] . '(区)';
                } else {
                    $titles[$_cfg['dfcId']] = $_cfg['dfcName'];
                }
                $name2id[$_cfg['dfcName']] = $_cfg['dfcId'];
            }
        }

        return array($titles, $mergeConfigs);
    }

    /**
     * 生成默认数据
     * @param $titles
     * @return array
     */
    protected function _generateDefault($titles)
    {

        $data = array();
        foreach ($titles as $_k => $val) {
            $data[$_k] = '';
        }

        return $data;
    }


    /**
     * 获取扩展信息, 并验证
     * @param $ext
     * @param $dptId
     * @param $request
     * @return bool
     */
    public function getExt(&$ext, $dptId, $request)
    {

        $ext = array();
        $configs = Cache::instance()->get('Common.DepartmentFieldConfig');
        foreach ($configs[$dptId] as $_config) {
            $val = $request[$_config['dfcId']];

            // 如果是地区, 省/市/区三级不全, 则视为未填
            if ('areaselect' == $_config['dfcType']) {
                if (empty($val['province']) || empty($val['city']) || empty($val['town'])) {
                    $val = array(
                        'province' => '',
                        'city' => '',
                        'town' => '',
                    );
                }
            }

            // 必填检查, 注意地区数据判断
            if (0 != $_config['dfcRequire'] && (empty($val) || (isset($val['province']) && empty($val['province'])))) {
                E(L('1001:{$name}不能为空', array('name' => $_config['dfcName'])));

                return false;
            }

            // 字符串验证
            if ('string' == $_config['dfcType']) {
                if (0 < $_config['dfcMin'] && count($val) < $_config['dfcMin']) {
                    E(L('1002:{$name}长度不能小于{$min}', array('name' => $_config['dfcName'], 'min' => $_config['dfcMin'])));

                    return false;
                }
                if (0 < $_config['dfcMax'] && count($val) > $_config['dfcMax']) {
                    E(L('1002:{$name}长度不能大于{$max}', array('name' => $_config['dfcName'], 'max' => $_config['dfcMax'])));

                    return false;
                }
            }

            // 数字验证
            if ('number' == $_config['dfcType']) {
                if (0 < $_config['dfcMin'] && $val < $_config['dfcMin']) {
                    E(L('1002:{$name}不能小于{$min}', array('name' => $_config['dfcName'], 'min' => $_config['dfcMin'])));

                    return false;
                }
                if (0 < $_config['dfcMax'] && val < $_config['dfcMax']) {
                    E(L('1002:{$name}不能大于{$max}', array('name' => $_config['dfcName'], 'max' => $_config['dfcMax'])));

                    return false;
                }
            }

            $ext[$_config['dfcId']] = 'areaselect' == $_config['dfcType'] ? rjson_encode($val) : $val;
        }

        return true;
    }

    /**
     * 验证部门路径上的部门是否存在
     * @param      $currentDepartment array 当前部门
     * @param      $dpNames array 所有部门路径名称
     * @param      $topDpId string 顶级部门ID
     * @param bool $isRepeat 是否重新获取进来 的标识
     * @return array|bool
     */
    protected function verifyDepPath($currentDepartment, $dpNames, $topDpId, $isRepeat = false)
    {
        $depServ = new Department();
        $allDepartment = $depServ->listAll();

        // 获取部门路径内名称相同的部门数据
        $relateDps = array();
        foreach ($allDepartment as $_dp) {
            if (in_array($_dp['dpName'], $dpNames)) {
                $relateDps[] = $_dp;
            }
        }

        // 从一级部门开始
        $currentDpId = $topDpId;
        foreach ($dpNames as $_index => $_name) {
            // 判断一级组织是否存在
            if (0 == $_index && $_name == $allDepartment[$topDpId]['dpName']) {
                $currentDpId = $topDpId;
                continue;
            }

            // 获取名称对应的部门ID
            if (!$this->_getDpIdFromRelateDps($currentDpId, $currentDpId, $_name, $relateDps)) {
                if ($_index + 1 == count($dpNames)) {
                    $currentDepartment['dpParentid'] = $currentDpId;
                    $currentDepartment['dpName'] = $_name;

                    return [$currentDpId, $allDepartment, $currentDepartment];
                }

                // 重新获取 进来的 直接返回, 防止死循环
                if ($isRepeat) {
                    return false;
                }
                // 按照部门路径的长度 进行重新获取部门
                for ($i = 0; $i < count($dpNames); $i++) {
                    // 等待上级部门创建
                    sleep(2);
                    $verifyDepPathReturn = $this->verifyDepPath($currentDepartment, $dpNames, $topDpId, true);
                    if (false !== $verifyDepPathReturn) {
                        return $verifyDepPathReturn;
                    }
                }
                E('1005:部门层级错误');
            }
        }

        return [$currentDpId, $allDepartment, $currentDepartment];
    }
}