/**
 * Company Name : 中贸促信息技术有限责任公司
 * Project Name:memberManageSys
 * File Name:RegisterService.java
 * Package Name:org.ccpit.business.registerManage
 * Date:2015年11月10日上午8:58:46
 * Copyright (c) 2015, dingwei@ccpit.org All Rights Reserved.
 */

package org.ccpit.business.registerManage;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.annotation.Resource;
import javax.transaction.Transactional;

import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.format.UnderlineStyle;
import jxl.write.Label;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;

import org.apache.commons.lang.StringUtils;
import org.ccpit.base.controller.Convert;
import org.ccpit.base.controller.Page;
import org.ccpit.base.controller.PageBo;
import org.ccpit.base.controller.PageRequest;
import org.ccpit.base.metadataManage.Metadata;
import org.ccpit.base.metadataManage.MetadataService;
import org.ccpit.base.user.User;
import org.ccpit.base.utils.TypeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * ClassName:RegisterService <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2015年11月10日 上午8:58:46 <br/>
 *
 * @author sunqipeng
 * @see
 * @since JDK 1.6
 */
@Component
public class RegisterService {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd MM:hh:ss");
    private static SimpleDateFormat sdf01 = new SimpleDateFormat("yyyy/MM/dd");
    List<Metadata> registerStatusM = null;
    List<Metadata> registerTypeM = null;
    List<Metadata> invoiceTypeM = null;
    List<Metadata> subjectM = null;
    List<Metadata> appreciationTaxType = null;
    List<Metadata> taxIssue = null;

    public void initMetadata() {
        registerStatusM = metadataService.getMetadatasByType2("status");// 报名状态
        registerTypeM = metadataService.getMetadatasByType2("registerType");// 报名类型
        invoiceTypeM = metadataService.getMetadatasByType2("invoiceType");// 发票类型
        subjectM = metadataService.getMetadatasByType2("subject");// 考试科目
        appreciationTaxType = metadataService.getMetadatasByType2("appreciationTaxType");// 增值税发票
        taxIssue = metadataService.getMetadatasByType2("taxIssue");// 发票开具时间
    }

    @Resource
    private RegisterDao registerDao;
    @Resource
    private MetadataService metadataService;
    @Resource
    private SubjectInfoDao subjectInfoDao;

    @Transactional
    public boolean addRegisterInfo(RegisterInfo registerInfo) {
        registerInfo.setSubmitTime(new Date());
        registerInfo.setEmail_en(registerInfo.getEmail());
        return registerDao.save(registerInfo);
    }

    @Transactional
    public boolean updateRegisterInfo(RegisterInfo registerInfo) {
        registerInfo.setModifyTime(new Date());
        registerInfo.setEmail_en(registerInfo.getEmail());
        return registerDao.update(registerInfo);
    }

    @Transactional
    public boolean deleteRegisterInfos(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return true;
        }

        boolean success = true;
        for (long id : ids) {
            RegisterInfo reg = registerDao.queryById(id);
            if (reg == null) {
                success = false;
                break;
            }
            reg.setWhetherDelete(true);
            boolean result = registerDao.save(reg);
            if (!result) {
                success = false;
            }
        }
        return success;
    }

    public RegisterInfo queryRegisterById(long id) {
        return registerDao.queryById(id);
    }


    public RegisterInfo queryByEmail(String email, Long phaseId, Boolean regType) {
        String hql = "from RegisterInfo where email = ? and phase.id = ? ";
        if (regType != null) {
            hql += " and regType= " + (regType ? "1" : "0");
        }
        List<RegisterInfo> list = registerDao.query(hql, email, phaseId);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    public List<RegisterInfo> queryList(String hql) {
        return registerDao.query(hql, null);
    }

    public List<RegisterInfo> query(String subject, Long phase, String name, String status) {
        StringBuilder sb = new StringBuilder("from SubjectInfo where 1=1 ");
        if (StringUtils.isNotBlank(subject)) {
            sb.append(" and subject = " + subject);
        }
        if (phase != null && phase != 0) {
            sb.append(" and phaseId = " + phase);
        }
        if (StringUtils.isNotBlank(name)){
            sb.append(" and name like '%"+name+"%'");
        }
        if (StringUtils.isNotBlank(status)){
            sb.append(" and registerStatus='"+status+"'");
        }
        List<SubjectInfo> subjectInfos = subjectInfoDao.query(sb.toString());
        List<RegisterInfo> registerInfos = new ArrayList<>();
        String hql = "";
        if(phase != null && phase != 0){
            hql = "from RegisterInfo where phase.id = '" + phase + "'";
        }else {
            hql = "from RegisterInfo";
        }
        List<RegisterInfo> registerInfoList = registerDao.query(hql);
        for (SubjectInfo s_info : subjectInfos) {
            long registerInfo_id = s_info.getRegisterInfo_id();
            for (RegisterInfo r_info : registerInfoList) {
                if (registerInfo_id == r_info.getId()) {
                    RegisterInfo n_info = new RegisterInfo();
                    n_info.setId(s_info.getId());
                    n_info.setSubject(s_info.getSubject());
                    n_info.setRegisterStatus(s_info.getRegisterStatus());
                    n_info.setAppreciationTaxType(s_info.getAppreciationTaxType());
                    n_info.setInvoiceType(s_info.getInvoiceType());
                    n_info.setInvoiceTitle(s_info.getInvoiceTitle());
                    n_info.setTaxpayerNum(s_info.getTaxpayerNum());
                    n_info.setAddressName(s_info.getAddressName());
                    n_info.setTelephone(s_info.getTelephone());
                    n_info.setBankAddress(s_info.getBankAddress());
                    n_info.setBankAccount(s_info.getBankAccount());
//                    n_info.setImg1(s_info.getImg1());
                    n_info.setTaxIssue(s_info.getTaxIssue());
                    n_info.setPayTime(s_info.getPayTime());
                    n_info.setName(r_info.getName());
                    n_info.setGender(r_info.getGender());
                    n_info.setBirthday(r_info.getBirthday());
                    n_info.setTelphone(r_info.getTelphone());
                    n_info.setMobileTel(r_info.getMobileTel());
                    n_info.setEmail(r_info.getEmail());
                    n_info.setCompany(r_info.getCompany());
                    n_info.setCompany_en(r_info.getCompany_en());
                    n_info.setAddress(r_info.getAddress());
                    n_info.setTitle(r_info.getTitle());
                    n_info.setEmail_en(r_info.getEmail_en());
                    n_info.setDateOfBirth(r_info.getDateOfBirth());
                    n_info.setGender_en(r_info.getGender_en());
                    n_info.setName_en(r_info.getName_en());
                    n_info.setName_en_last(r_info.getName_en_last());
                    n_info.setAddress_en(r_info.getAddress_en());
                    n_info.setCountry(r_info.getCountry());
                    n_info.setDcNumber(r_info.getDcNumber());
                    n_info.setPhone(r_info.getPhone());
                    n_info.setSubmitTime(s_info.getSubmitTime());
                    n_info.setProvince(r_info.getProvince());
                    n_info.setChengshi(r_info.getChengshi());
                    n_info.setDistrict(r_info.getDistrict());
                    n_info.setInvoiceInfo(r_info.getInvoiceInfo());
                    registerInfos.add(n_info);
                }
            }
        }
        return registerInfos;
    }

    public Page<RegisterInfo> queryMemberBaseInfos(PageRequest pageRequest) {
        String hql = "from RegisterInfo order by createTime desc,sort asc";
        return registerDao.findPage(pageRequest, hql, null);
    }

    public Page<RegisterInfo> queryRegisterInfos(PageRequest pageRequest,
                                                 String hql) {
        return registerDao.findPage(pageRequest, hql, null);
    }

    public Map<String, Object> convertToMap(RegisterInfo RegisterInfo) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (RegisterInfo == null) {
            return map;
        }
        map.put("id", RegisterInfo.getId());
        map.put("createTime", sdf.format(RegisterInfo.getCreateTime()));
        map.put("creator", RegisterInfo.getCreator().getUsername());
        map.put("submitTime", sdf.format(RegisterInfo.getSubmitTime()));
        map.put("city", RegisterInfo.getCity());
        map.put("city_ne", RegisterInfo.getCity_en());
        map.put("name", RegisterInfo.getName());
        map.put("name_en", RegisterInfo.getName_en());
        map.put("name_en_last", RegisterInfo.getName_en_last());
        map.put("gender_en", RegisterInfo.getGender_en());
        map.put("gender", "male".equals(RegisterInfo.getGender()) ? "男" : "女");
        map.put("birthday", sdf01.format(RegisterInfo.getBirthday()));
        map.put("telphone", RegisterInfo.getTelphone());
        map.put("mobileTel", RegisterInfo.getMobileTel());
        map.put("email", RegisterInfo.getEmail());
        map.put("company", RegisterInfo.getCompany());
        map.put("invoiceInfo", RegisterInfo.getInvoiceInfo());
//        map.put("invoiceType",
//                TypeUtils.translateData("invoiceType", RegisterInfo.getInvoiceType()));
        map.put("subject", TypeUtils.translateData("subject", RegisterInfo.getSubject()));
        map.put("registerStatus",
                TypeUtils.translateData("registerStatus",
                        RegisterInfo.getRegisterStatus()));
        map.put("sort", RegisterInfo.getSort());
        return map;
    }

    public PageBo<RegisterInfo> convert(Page<RegisterInfo> page) {
        return new PageBo<RegisterInfo>(page, new Convert<RegisterInfo>() {
            @Override
            public Map<String, Object> convert(RegisterInfo obj) {
                return convertToMap(obj);
            }
        });
    }


    /**
     * 根据选择的属性，导出数据到excel <功能详细描述>
     *
     * @see [类、类#方法、类#成员]
     */

    public void outProperties(List<RegisterInfo> listLike, String[] optionPros,
                              OutputStream out) {
        initMetadata();// 初始化Metadata的数据
        WritableWorkbook book = null;
        try {
            // book = Workbook.createWorkbook(out);
            WorkbookSettings workbookSettings = new WorkbookSettings();
            //编码代码有：GB18030，UTF-8，ISO-8859-1 等
            workbookSettings.setEncoding("GB2312"); //关键代码，解决中文乱码
            book = Workbook.createWorkbook(out, workbookSettings);
            jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.BLACK);
            jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
            // 设置单元格样式
            // wcfFC.setBackground(jxl.format.Colour.GRAY_25);// 单元格颜色
            wcfFC.setAlignment(jxl.format.Alignment.CENTRE);// 单元格居中
            // 生成名为“第一页”的工作表，参数0表示这是第一页
            WritableSheet sheet = book.createSheet(" 第一页 ", 0);
            List<String> list = new ArrayList<String>();// 用于接收选择属性的值
            List<String> opList = new ArrayList<String>();// 存放选择的属性的集合
            Label label = null;

            for (int i = 0; i < optionPros.length; i++) {
                opList.add(optionPros[i]);
            }
            Map<String, String> mapProsHeader = null;
            mapProsHeader = initProsHeader();
            //System.out.println(opList);
            for (int i = 0; i < opList.size(); i++) {
                // 在Label对象的构造子中指名单元格位置是第一列第一行(0,0)
                // 以及单元格内容为test
                label = new Label(i, 0, mapProsHeader.get(opList.get(i)), wcfFC);
                // 将定义好的单元格添加到工作表中
                sheet.addCell(label);
            }
            list = getOutExcelList(listLike, optionPros);
            int row = 1;
            int colum = 0;
            for (int i = 0; i < list.size(); i++) {

                // 在Label对象的构造子中指名单元格位置是第一列第一行(0,0)
                // 以及单元格内容为test
                label = new Label(colum++, row, list.get(i), wcfFC);
                // 将定义好的单元格添加到工作表中
                sheet.addCell(label);
                if ((i + 1) % opList.size() == 0) {
                    row++;
                    colum = 0;
                }
            }
        } catch (Exception e) {
        } finally {
            try {
                book.write();
                book.close();
                out.flush();
                out.close();
            } catch (Exception e2) {
            }
        }

    }

    public Map<String, String> initProsHeader() {
        Map<String, String> mapProsHeader = new HashMap<String, String>();
        String[] enPros = {"id", "submitTime", "name", "password", "gender", "birthday", "telphone", "mobileTel", "email", "company", "province","chengshi","district","address","ifBuyFee"
                , "taxIssue","appreciationTaxType","invoiceTitle", "invoiceInfo", "taxpayerNum", "addressName", "telephone", "bankAddress", "bankAccount", "title", "dateOfBirth", "gender_en", "name_en", "name_en_last", "company_en", "address_en"
                , "country", "dcNumber", "payTime", "phone", "city_en", "subject", "subject2", "registerStatus", "sort", "whetherDelete"
                , "creator", "createTime", "modifyBy", "modifyTime"};
        String[] cnPros = {"序号", "提交时间", "姓名", "密码", "性别", "出生日期", "电话", "手机", "EMAIL", "工作单位", "省/直辖市","市","区/县","详细地址","是否购买CDCS/CSDG考前培训","发票开具时间","增值税发票类型", "发票抬头", "发票内容", "纳税人识别号", "公司地址", "公司电话", "开户行", "银行账号"
                , "TITLE", "DATE OF BIRTH", "GENDER", "Family NAME", "Given NAME", "COMPANY NAME", "ADDRESS", "COUNTRY", "DC/IFS NUMBER", "缴费时间", "PHONE", "CITY SELECT"
                , "考试科目", "考试科目", "报名状态", "排序号", "是否删除", "创建人", "创建时间", "修改人", "修改时间"};
        for (int i = 0; i < enPros.length; i++) {
            mapProsHeader.put(enPros[i], cnPros[i]);
        }
        return mapProsHeader;
    }

    /**
     * 把要导出的数据整理到list集合中 <功能详细描述>
     *
     * @param options
     * @return
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("finally")
    public List<String> getOutExcelList(List<RegisterInfo> listLike, String[] options) {
        List<RegisterInfo> listInfo = listLike;// 查询注册信息的所有内容
        for (int i = 0; i < listInfo.size(); i++) {
            //System.out.println(listInfo.get(i));
        }
        List<String> listNew = new ArrayList<String>();// 用来存放选择的属性对应值的集合
        Field[] fields = null;// 注册信息的所有属性
        try {
            List<String> optionPros = new ArrayList<String>();// 存放选择的属性的集合

            for (int i = 0; i < options.length; i++) {
                optionPros.add(options[i]);
            }
            List<String> optionProsProxy = new ArrayList<String>();// 创建存放属性的代理，之后会用来作为判断是否包含某个属性
            for (int i = 0; i < options.length; i++) {
                optionProsProxy.add(options[i]);
            }
            // 获得所有属性，并让私有属性可以在类外使用
            fields = listInfo.get(0).getClass().getDeclaredFields();
            List<String> listFields = new ArrayList<String>();
            for (int i = 0; i < fields.length; i++) {
                fields[i].setAccessible(true);
                listFields.add(fields[i].getName());
            }
            Map<String, Map<String, String>> listMapPros = DataIdMapDataName(options, fields);
            // 通过反射获得方法，让方法invoke，调用。
            String getMethodName = null;
            Class tCls = null;
            Method getMethod = null;
            for (int j = 0; j < listInfo.size(); j++) {// 控制行
                for (int i = 0; i < optionProsProxy.size(); i++) {// 控制列
                    if (optionProsProxy != null && listFields.contains(optionProsProxy.get(i))) {
                        getMethodName = "get" + optionProsProxy.get(i).substring(0, 1).toUpperCase() + optionProsProxy.get(i).substring(1);
                        tCls = listInfo.get(j).getClass();
                        getMethod = tCls.getMethod(getMethodName, new Class[]{});
                        Object value = getMethod.invoke(listInfo.get(j), new Object[]{});
                        // 把数据放入到新的list集合中，并最后把这个集合的内容导出到excel中
                        formatData(listNew, value, optionProsProxy.get(i), listMapPros);
                        if (optionProsProxy == null) {
                            break;
                        }
                    }
                }
            }
            for (int i = 0; i < fields.length; i++)
                fields[i].setAccessible(false);
            // return listNew;
        } catch (Exception e) {

        } finally {
            return listNew;
        }
    }

    /**
     * 通过属性的不同名称，进行数据的格式转换，最后都变成字符串放入到listNew中 <功能详细描述>
     *
     * @see [类、类#方法、类#成员]
     */
    public void formatData(List<String> listNew, Object value, String propertyName, Map<String, Map<String, String>> listMapPros) {
        // private boolean whetherDelete; private Date modifyTime;private Date
        // birthday;
        // private User modifyBy; private Date createTime;private Date
        // submitTime;
        // private User creator; private Date dateOfBirth;
        //
        String textValue = null;// 用来保存转化后的字符串
        // 把日期转变成字符串形式
        if (value instanceof Date) {
            Date date = (Date) value;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            textValue = sdf.format(date);
        } else if (value instanceof User) {// 如果是User类型，则获得name值便可
            textValue = ((User) value).getUsername();
        } else if (value instanceof Boolean) {
            textValue = (Boolean) value == true ? "是" : "否";
        } else if (value instanceof Integer) {
            // Integer类型的数值会代表不同的内容，所以通过数据库initMetadata()初始化Metadata的数据查出的
            // List集合来分别代表不同的内容。
            if("ifBuyFee".equals(propertyName)){
                if(1 == (Integer) value){
                    textValue = "是";
                }else {
                    textValue = "否";
                }
            }else {
                textValue = DataIdToDataName(listMapPros, value, propertyName);
            }
        } else {
            if (value != null)
                textValue = value.toString();
        }
        listNew.add(textValue);
    }

    public String DataIdToDataName(Map<String, Map<String, String>> listMapPros, Object value, String propertyName) {
        return listMapPros.get(propertyName).get(String.valueOf(value));
    }

    // 根据属性名查出属性名由状态数字表示的真正属性名,并放到map映射中。
    public Map<String, Map<String, String>> DataIdMapDataName(String[] optionPros, Field[] fields) {

        List<Metadata> listMeta = new ArrayList<Metadata>();
        // 把Integer状态转化为String的名字，先把需要转化的属性跳出来，然后放到一个List集合中，再把该集合中的每一个需要转化的属性的所有状态码与属性名的映射放到一个新的list中
        Map<String, Map<String, String>> mapMapPros = new HashMap<String, Map<String, String>>();
        List<String> listPros = new ArrayList<String>();
        for (String property : optionPros) {
            for (Field field : fields) {
                if (property.equals(field.getName())) {
                    if (field.getType().equals(Integer.class)) {
                        listPros.add(property);
                    }
                }
            }
        }
        for (String property1 : listPros) {
            if (property1.equals("registerStatus")) {
                listMeta = metadataService.getMetadatasByType2("status");
            } else {
                listMeta = metadataService.getMetadatasByType2(property1);
            }
            Map<String, String> mapData = new HashMap<String, String>();
            for (Metadata meta : listMeta) {
                mapData.put(meta.getDataNameId(), meta.getDataName());
            }
            if (!mapData.isEmpty()) {
                mapMapPros.put(property1, mapData);
            }
        }
        return mapMapPros;
    }

}
