public without sharing class ListAssetForHospitalController {
    private static String YEAR_NULL = '-';
    public List<PageLine> pageLines { get; private set; }
    public PageLine totalLine { get; private set; }
    // where
    public User dateFrom { get; set; }
    public User dateTo { get; set; }
    public String category2 { get; set; }
    public String category3 { get; set; }
    public String category4 { get; set; }
    public String category5 { get; set; }
    public String modelNo { get; set; }
    public Boolean isImportantProduct { get; set; }
    public String isCompetitorProduct { get; set; }
    public String isThisYear { get; set; }
    public String isHDSD { get; set; }
    public String isNBIProcessor { get; set; }
    
    // sort用
    private static Map<String, Integer> DC_LEVEL_Map;
    static {
        DC_LEVEL_Map = new Map<String, Integer>();
        DC_LEVEL_Map.put('消化科', 0);
        DC_LEVEL_Map.put('呼吸科', 1);
        DC_LEVEL_Map.put('普外科', 2);
        DC_LEVEL_Map.put('泌尿科', 3);
        DC_LEVEL_Map.put('妇科', 4);
        DC_LEVEL_Map.put('耳鼻喉科', 5);
        DC_LEVEL_Map.put('ET', 6);
        DC_LEVEL_Map.put('其他', 7);
    }

    public static List<SelectOption> getCategory2Opts() {
        List<SelectOption> category2Opts = new List<SelectOption>();
        category2Opts.add(new SelectOption('全部','全部'));
        category2Opts.add(new SelectOption('本体','本体'));
        category2Opts.add(new SelectOption('耗材','耗材'));
        category2Opts.add(new SelectOption('附属品','附属品'));
        return category2Opts;
    }
    
    public static List<SelectOption> getIsCompetitorProductOpts() {
        List<SelectOption> isCompetitorProductOpts = new List<SelectOption>();
        isCompetitorProductOpts.add(new SelectOption('全部','全部'));
        isCompetitorProductOpts.add(new SelectOption('true','是'));
        isCompetitorProductOpts.add(new SelectOption('false','否'));
        return isCompetitorProductOpts;
    }
    
    public static List<SelectOption> getIsThisYearOpts() {
        List<SelectOption> isThisYearOpts = new List<SelectOption>();
        isThisYearOpts.add(new SelectOption('全部','全部'));
        isThisYearOpts.add(new SelectOption('更新对象','更新对象'));
        isThisYearOpts.add(new SelectOption('非对象','非对象'));
        return isThisYearOpts;
    }
    
    public static List<SelectOption> getIsHDSDOpts() {
        List<SelectOption> isHDSDOpts = new List<SelectOption>();
        isHDSDOpts.add(new SelectOption('全部','全部'));
        isHDSDOpts.add(new SelectOption('HD主机','HD主机'));
        isHDSDOpts.add(new SelectOption('SD主机','SD主机'));
        return isHDSDOpts;
    }

    public static List<SelectOption> getIsNBIProcessorOpts() {
        List<SelectOption> isNBIProcessorOpts = new List<SelectOption>();
        isNBIProcessorOpts.add(new SelectOption('全部','全部'));
        isNBIProcessorOpts.add(new SelectOption('NBI主机','NBI主机'));
        isNBIProcessorOpts.add(new SelectOption('其他主机','其他主机'));
        return isNBIProcessorOpts;
    }

    // group by y
    public Boolean isCategory2 { get; set; }
    public Boolean isCategory3 { get; set; }
    public Boolean isCategory4 { get; set; }
    public Boolean isCategory5 { get; set; }
    public Boolean isProductCode { get; set; }
    // group by x
    public Boolean isShowYear { get; set; }
    public Boolean isShowDc { get; set; }
    public List<String> headerYrCols { get; private set; }
    public Map<String, List<String>> headerDcCols { get; private set; }     // year毎の dcのList
    public Map<String, Integer> headerYrColspan { get; private set; }
    public Map<String, Integer> headerXColspan { get; private set; }        // Mapのキーにyearの情報のあります。
    
    // 集計項目
    public Boolean isShowCnt { get; set; }
    public Boolean isShowSumRepair { get; set; }
    public Boolean isShowHDRatio { get; set; }
    public Boolean isShowNBIRatio { get; set; }
    public Integer aggregateColspan { get; private set; }
    public Integer setAggregateColspan() {
        aggregateColspan = 0;
        if (isShowCnt && ishp) aggregateColspan++;
        if (isShowCnt && !ishp) {
            aggregateColspan++;
            aggregateColspan++;
        }
        if (isShowSumRepair) aggregateColspan++;
        if (isShowHDRatio) aggregateColspan++;
        if (isShowNBIRatio) aggregateColspan++;
        return aggregateColspan;
    }
    
    // true:医院,false:战略科室
    public Boolean ishp { get; private set; }
    
    private final String recordId;
    private String hpid;
    private String dcid;

    public ListAssetForHospitalController(ApexPages.StandardController stdController) {
        recordId = stdController.getId();
        pageLines = new List<PageLine>();
        totalLine = new PageLine(false, false, false, false, false);

        dateFrom = new User(id=Userinfo.getUserId());
        dateTo = new User(id=Userinfo.getUserId());
        category2 = '全部';
        isImportantProduct = false;
        isCompetitorProduct = '全部';
        isThisYear = '全部';
        isHDSD = '全部';
        isNBIProcessor = '全部';
        isCategory2 = false;
        isCategory3 = true;
        isCategory4 = true;
        isCategory5 = true;
        isProductCode = true;
        isShowYear = false;
        isShowDc  = false;
        // 集計項目
        isShowCnt = true;
        isShowSumRepair = true;
        isShowHDRatio = false;
        isShowNBIRatio = false;
    }
    
    public PageReference init() {
        List<Account> acc = [select id,RecordType.DeveloperName from Account where Id = :recordId];
        if (acc.size() <= 0) {
            throw new ControllerUtil.myException('没有指定参数。');
            //ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '没有指定参数。'));
            //return null;
        }
        if (acc[0].RecordType.DeveloperName == 'HP') {
            hpid = recordId;
            ishp = true;
        } else {
            dcid = recordId;
            ishp = false;
            //isShowDc = true;            // Dcの場合必ずtrue、sql側項目をselectするため
        }
        // SWAG-BJHAPX start
        return null;
        // 原代码
        //  return searchBtn();
        // SWAG-BJHAPX end
    }
    
    public PageReference searchBtn() {
        headerYrCols = new List<String>();
        headerDcCols = new Map<String, List<String>>();
        headerYrColspan = new Map<String, Integer>();
        headerXColspan = new Map<String, Integer>();
        pageLines = new List<PageLine>();
        setAggregateColspan();
        if (aggregateColspan == 0) {
            aggregateColspan = 1;
            isShowCnt = true;
        }
        // 无效id
        if (hpid == null && dcid == null) {
            return null;
        }
        // 检索数据
        List<AggregateResult> aggAstList = getSqlResult();
        String breakKey = '';
        for (AggregateResult aggAst : aggAstList) {

            breakKey = addPageLines(breakKey, aggAst, isCategory2, isCategory3, isCategory4, isCategory5, isProductCode, isShowYear, isShowDc);
        }
        // データを整形、行毎 Mapにない値を設定
        // まず、headerYrCols、headerDcCols の値をセット
        for (Integer line = 0; line < pageLines.size(); line++) {
            PageLine pl = pageLines.get(line);
            if (isShowYear) {
                for (String installYear : pl.yrCols) {
                    Integer colspan = headerYrColspan.get(installYear);
                    if (colspan == null) {
                        headerYrCols.add(installYear);
System.debug('headerYrCols.add(' + installYear + ')');
                        headerYrColspan.put(installYear, aggregateColspan);     // Default 数量、修理金額
                    }
                    List<String> headerDcList = headerDcCols.get(installYear);
                    if (headerDcList == null) {
                        headerDcList = new List<String>();
                        headerDcCols.put(installYear, headerDcList);
                        if (isShowDc == false) {
                            headerDcList.add(installYear);
                            headerXColspan.put(installYear, aggregateColspan);     // Default 数量、修理金額
                        }
                    }
                }
            } else {
                Integer colspan = headerYrColspan.get(YEAR_NULL);
                if (colspan == null) {
                    headerYrCols.add(YEAR_NULL);
System.debug('headerYrCols.add(' + YEAR_NULL + ')');
                    headerYrColspan.put(YEAR_NULL, aggregateColspan);     // Default 数量、修理金額
                }
                List<String> headerDcList = headerDcCols.get(YEAR_NULL);
                if (headerDcList == null) {
                    headerDcList = new List<String>();
                    headerDcCols.put(YEAR_NULL, headerDcList);
                    if (isShowDc == false) {
                        headerDcList.add(YEAR_NULL);
                        headerXColspan.put(YEAR_NULL, aggregateColspan);     // Default 数量、修理金額
                    }
                }
            }
            if (isShowDc) {
                for (String installYear : headerYrCols) {
                    List<String> xColList = pl.xColListMap.get(installYear);
                    List<String> dcList = pl.dcCols.get(installYear);
                    if (xColList != null) {
                        List<String> headerDcList = headerDcCols.get(installYear);          // 前のloopで必ず、newしたはず、nullの可能性がない。
                        for (Integer xColIdx = 0; xColIdx < xColList.size(); xColIdx++) {
                            String departmentClass = dcList.get(xColIdx);
                            String xKey = xColList.get(xColIdx);          // xKey にはすでにyearの情報が入っています。
System.debug(xKey + '=xColList.get(' + xColIdx + ')');
                            Integer colspan = headerXColspan.get(installYear + '｜' + departmentClass);
                            if (colspan == null) {
                                // x列がない、追加
System.debug('headerXColspan.put(' + installYear + '｜' + departmentClass + ')');
                                headerDcList.add(departmentClass);
                                headerXColspan.put(installYear + '｜' + departmentClass, aggregateColspan);     // Default 数量、修理金額
                            } else {
                                // 存在するとは、すでに別のlineにて追加済み
                            }
                        }
                    }
System.debug('headerDcCols.get(' + installYear + ').size()=' + headerDcCols.get(installYear).size());
                }
            }
        }
        // たりないセルの値をMapにput
        // headerYrCols と headerDcCols の sort
        // 最後の合計行を出す
        headerYrCols.sort();
        totalLine = new PageLine(isCategory2, isCategory3, isCategory4, isCategory5, isProductCode);
        for (Integer line = 0; line < pageLines.size(); line++) {
            PageLine pl = pageLines.get(line);
            for (String installYear : headerYrCols) {
                // sort headerDcList
                List<String> headerDcList = headerDcCols.get(installYear);
                for (Integer si = 0; si < headerDcList.size() - 1; si++) {
                    for (Integer sj = headerDcList.size() - 1; sj > si; sj--) {
                        String sjValue = headerDcList.get(sj);
                        String sj1Value = headerDcList.get(sj - 1);
                        Integer sjLevel = DC_LEVEL_Map.get(headerDcList.get(sj));
                        Integer sj1Level = DC_LEVEL_Map.get(headerDcList.get(sj - 1));
                        if (sjLevel == null) sjLevel = DC_LEVEL_Map.size();
                        if (sj1Level == null) sj1Level = DC_LEVEL_Map.size();
                        if (sjLevel < sj1Level) {
                            headerDcList.set(sj, sj1Value);
                            headerDcList.set(sj - 1, sjValue);
                        }
                    }
                }
                headerDcCols.put(installYear, headerDcList);
System.debug('for pageLines :' + installYear + '｜' + line + '｜' + headerDcList.size());
                headerYrColspan.put(installYear, headerDcList.size() * aggregateColspan);
                for (String departmentClass : headerDcList) {
                    String xKey = installYear + '｜' + departmentClass + '｜' + line;
                    String xTKey = installYear + '｜' + departmentClass + '｜' + pageLines.size();
System.debug('pl.cntMap[' + xKey + ']');
                    if (pl.cntMap.get(xKey) == null) {
System.debug('pl.cntMap.put(' + xKey + ', 0)');
                        pl.cntMap.put(xKey, 0);
                        pl.cntRpMap.put(xKey, 0);
                        pl.sumRepairMap.put(xKey, 0);
                    } else {
                        if (totalLine.cntMap.get(xTKey) == null) {
                            totalLine.allCnt += pl.cntMap.get(xKey);
                            totalLine.allRpCnt += pl.cntRpMap.get(xKey);
                            totalLine.allSumRepair += pl.sumRepairMap.get(xKey);
                            totalLine.cntMap.put(xTKey, pl.cntMap.get(xKey));
                            totalLine.cntRpMap.put(xTKey, pl.cntRpMap.get(xKey));
                            totalLine.sumRepairMap.put(xTKey, pl.sumRepairMap.get(xKey));
                        } else {
                            totalLine.allCnt += pl.cntMap.get(xKey);
                            totalLine.allRpCnt += pl.cntRpMap.get(xKey);
                            totalLine.allSumRepair += pl.sumRepairMap.get(xKey);
                            totalLine.cntMap.put(xTKey, totalLine.cntMap.get(xTKey) + pl.cntMap.get(xKey));
                            totalLine.cntRpMap.put(xTKey, totalLine.cntRpMap.get(xTKey) + pl.cntRpMap.get(xKey));
                            totalLine.sumRepairMap.put(xTKey, totalLine.sumRepairMap.get(xTKey) + pl.sumRepairMap.get(xKey));
                        }
                    }
                }
            }
        }
        return null;
    }
    
    private List<AggregateResult> getSqlResult() {
        //String soql = 'select Count(Id) Cnt_Id, Sum(Accumulation_Repair_Amount__c) Sum_Repair';
        String soql = 'select Count(Id) Cnt_Id';
        //if (ishp) {
        //    soql += ', Sum(Accumulation_Repair_Amount__c) Sum_Repair, Sum(Count_Final_Inspection_Date_Repair__c) Rpcnt';
        //} else {
            soql += ', Sum(Sum_Final_Inspection_Date_Repair_Price__c) Sum_Repair, Sum(Count_Final_Inspection_Date_Repair__c) RpCnt';
        //}
        if (isCategory2) {
            soql += ', Product2.Category2__c';
        }
        if (isCategory3) {
            soql += ', Product2.Category3__c';
        }
        if (isCategory4) {
            soql += ', Product2.Category4__c';
        }
        if (isCategory5) {
            soql += ', Product2.Category5__c';
        }
        if (isProductCode) {
            soql += ', Product2.Asset_Model_No__c, Max(Product2.Image_Small__c) Image_Small';
        }
        if (isShowYear) {
            soql += ', CALENDAR_YEAR(InstallDate) InstallYear';
        }
        if (isShowDc) {
            soql += ', Department_Class__r.Department_Class_Label__c';
        }
        soql = soql + ' from Asset';
        //if (ishp) {
        //    soql = soql + ' where Status = \'使用中\'';
        //} else {
            soql = soql + ' where (Status = \'使用中\' or Status = \'不明\')';
        //}
        if (hpid != null) {
            soql += ' and Hospital__c != null';
            soql += ' and Hospital__c = :hpid';
        }
        if (dcid != null) {
            soql += ' and Department_Class__c != null';
            soql += ' and Department_Class__c = :dcid';
        }
        if (category2 != '全部') {
            soql += ' and Product2.Category2__c = :category2';
        }
        if (String.isBlank(category3) == false) {
            String prd_Category3 = '%' + category3.replaceAll('%', '\\%') + '%';
            soql += ' and Product2.Category3__c like :prd_Category3';
        }
        if (String.isBlank(category4) == false) {
            String prd_Category4 = '%' + category4.replaceAll('%', '\\%') + '%';
            soql += ' and Product2.Category4__c like :prd_Category4';
        }
        if (String.isBlank(category5) == false) {
            String prd_Category5 = '%' + category5.replaceAll('%', '\\%') + '%';
            soql += ' and Product2.Category5__c like :prd_Category5';
        }
        if (String.isBlank(modelNo) == false) {
            String prd_Asset_Model_No = '%' + modelNo.replaceAll('%', '\\%') + '%';
            soql += ' and Product2.Asset_Model_No__c like :prd_Asset_Model_No';
        }
        if (isImportantProduct) {
            soql += ' and Important_product__c = :isImportantProduct';
        }
        if (isCompetitorProduct != '全部') {
            Boolean competitorProduct = Boolean.valueof(isCompetitorProduct);
            soql += ' and IsCompetitorProduct = :competitorProduct';
        }
        if (isThisYear != '全部') {
            soql += ' and This_year__c = :isThisYear';
        }
        if (isHDSD != '全部') {
            soql += ' and Product2.HD_SD__c = :isHDSD';
        }
        if (isNBIProcessor != '全部') {
            soql += ' and NBI_processor__c = :isNBIProcessor';
        }
        if (dateFrom.Birth_Date__c != null) {
            Date fromDate = dateFrom.Birth_Date__c;
            soql += ' and InstallDate >= :fromDate';
        }
        if (dateTo.Birth_Date__c != null) {
            Date toDate = dateTo.Birth_Date__c;
            soql += ' and InstallDate <= :toDate';
        }
        soql += ' group by Hospital__c';
        if (isCategory2) {
            soql += ', Product2.Category2__c';
        }
        if (isCategory3) {
            soql += ', Product2.Category3__c';
        }
        if (isCategory4) {
            soql += ', Product2.Category4__c';
        }
        if (isCategory5) {
            soql += ', Product2.Category5__c';
        }
        if (isProductCode) {
            soql += ', Product2.Asset_Model_No__c';
        }
        if (isShowYear) {
            soql += ', InstallDate';
        }
        if (isShowDc) {
            soql += ', Department_Class__r.Department_Class_Label__c';
        }
        soql += ' order by Hospital__c';
        if (isCategory2) {
            soql += ', Product2.Category2__c';
        }
        if (isCategory3) {
            soql += ', Product2.Category3__c';
        }
        if (isCategory4) {
            soql += ', Product2.Category4__c';
        }
        if (isCategory5) {
            soql += ', Product2.Category5__c';
        }
        if (isProductCode) {
            soql += ', Product2.Asset_Model_No__c';
        }
        system.debug('=====sql:' + soql);
        return Database.query(soql);
    }

    private String addPageLines(String breakKey, AggregateResult aggAst, Boolean isCategory2, Boolean isCategory3, Boolean isCategory4, Boolean isCategory5, Boolean isProductCode, Boolean isShowYear, Boolean isShowDc) {
        // Y軸
        String category2 = isCategory2 ? (aggAst.get('Category2__c') == null ? '' : String.valueOf(aggAst.get('Category2__c'))) : '';
        String category3 = isCategory3 ? (aggAst.get('Category3__c') == null ? '' : String.valueOf(aggAst.get('Category3__c'))) : '';
        String category4 = isCategory4 ? (aggAst.get('Category4__c') == null ? '' : String.valueOf(aggAst.get('Category4__c'))) : '';
        String category5 = isCategory5 ? (aggAst.get('Category5__c') == null ? '' : String.valueOf(aggAst.get('Category5__c'))) : '';
        String productCode = isProductCode ? (aggAst.get('Asset_Model_No__c') == null ? '' : String.valueOf(aggAst.get('Asset_Model_No__c'))) : '';
        // X軸
        String installYear = isShowYear ? (aggAst.get('InstallYear') == null ? '' : String.valueOf(aggAst.get('InstallYear'))) : '';
        installYear = String.isBlank(installYear) ? YEAR_NULL : installYear;
        String departmentClass = isShowDc ? (aggAst.get('Department_Class_Label__c') == null ? '' : String.valueOf(aggAst.get('Department_Class_Label__c'))) : installYear;

        // keyの比較
        String rtnKey = category2 + '｜｜' + category3 + '｜｜' + category4 + '｜｜' + category5 + '｜｜' + productCode;
        PageLine nowLine = null;
        if (rtnKey != breakKey) {
            nowLine = new PageLine(aggAst, isCategory2, isCategory3, isCategory4, isCategory5, isProductCode, isShowYear, isShowDc);
            pageLines.add(nowLine);
        } else {
            nowLine = pageLines[pageLines.size() - 1];
        }
        String xKey = installYear + '｜' + departmentClass + '｜' + (pageLines.size() - 1);
        
        List<String> xColList = nowLine.xColListMap.get(installYear);
        List<String> dcList = nowLine.dcCols.get(installYear);
System.debug('nowLine.xColListMap.get(' + installYear + ')');
        if (xColList == null) {
            nowLine.yrCols.add(installYear);
            xColList = new List<String>();
            dcList = new List<String>();
            nowLine.xColListMap.put(installYear, xColList);
            nowLine.dcCols.put(installYear, dcList);
        }
        dcList.add(departmentClass);
        xColList.add(xKey);     // GroupByしているので、ここはX軸のxKeyもレコードごと重複がないはず
System.debug('xColList.add(' + xKey + ')');
        nowLine.allCnt += Integer.valueOf(aggAst.get('Cnt_Id'));
        nowLine.allRpCnt += Integer.valueOf(aggAst.get('RpCnt'));
        // SWAG-BD86DN 2019-07-04 start
        nowLine.allSumRepair += Double.valueOf(aggAst.get('Sum_Repair') == null 
            || !Schema.sObjectType.Asset.fields.Sum_Final_Inspection_Date_Repair_Price__c.isAccessible() 
            ? '0' : aggAst.get('Sum_Repair'));
        // SWAG-BD86DN 2019-07-04 end
        nowLine.cntMap.put(xKey, Integer.valueOf(aggAst.get('Cnt_Id')));
        nowLine.cntRpMap.put(xKey, Integer.valueOf(aggAst.get('RpCnt')));
        // SWAG-BD86DN 2019-07-04 start
        nowLine.sumRepairMap.put(xKey, Double.valueOf(aggAst.get('Sum_Repair') == null ||
            !Schema.sObjectType.Asset.fields.Sum_Final_Inspection_Date_Repair_Price__c.isAccessible() 
            ? '0' : aggAst.get('Sum_Repair')));
        // SWAG-BD86DN 2019-07-04 end
        // breakKeyを返す
        return rtnKey;
    }

    public class PageLine {
        public String category2 { get; private set; }
        public String category3 { get; private set; }
        public String category4 { get; private set; }
        public String category5 { get; private set; }
        public String productCode { get; private set; }
        public String productImage { get; private set; }
        public Integer ttlColspan { get; private set; }
        public Integer allCnt { get; private set; }
        public Integer allRpCnt { get; private set; }
        public Double allSumRepair { get; private set; }
        public Map<String, Integer> cntMap { get; private set; }        // 非表示でも、必ずCntする
        public Map<String, Integer> cntRpMap { get; private set; }
        public Map<String, Double> sumRepairMap { get; private set; }
        public List<String> yrCols { get; private set; }
        public Map<String, List<String>> dcCols { get; private set; }
        public Map<String, List<String>> xColListMap { get; private set; }

        public PageLine(AggregateResult aggAst, Boolean isCategory2, Boolean isCategory3, Boolean isCategory4, Boolean isCategory5, Boolean isProductCode, Boolean isShowYear, Boolean isShowDc) {
            category2 = isCategory2 ? (aggAst.get('Category2__c') == null ? '' : String.valueOf(aggAst.get('Category2__c'))) : '';
            category3 = isCategory3 ? (aggAst.get('Category3__c') == null ? '' : String.valueOf(aggAst.get('Category3__c'))) : '';
            category4 = isCategory4 ? (aggAst.get('Category4__c') == null ? '' : String.valueOf(aggAst.get('Category4__c'))) : '';
            category5 = isCategory5 ? (aggAst.get('Category5__c') == null ? '' : String.valueOf(aggAst.get('Category5__c'))) : '';
            productCode = isProductCode ? (aggAst.get('Asset_Model_No__c') == null ? '' : String.valueOf(aggAst.get('Asset_Model_No__c'))) : '';
            productImage = isProductCode ? (aggAst.get('Image_Small') == null ? '' : String.valueOf(aggAst.get('Image_Small'))) : '';
            allCnt = 0;
            allRpCnt = 0;
            allSumRepair = 0;
            cntMap = new Map<String, Integer>();
            cntRpMap = new Map<String, Integer>();
            sumRepairMap = new Map<String, Double>();
            yrCols = new List<String>();
            dcCols = new Map<String, List<String>>();
            xColListMap = new Map<String, List<String>>();
        }
        
        // 合計行の場合
        public PageLine(Boolean isCategory2, Boolean isCategory3, Boolean isCategory4, Boolean isCategory5, Boolean isProductCode) {
            allCnt = 0;
            allRpCnt = 0;
            allSumRepair = 0;
            cntMap = new Map<String, Integer>();
            cntRpMap = new Map<String, Integer>();
            sumRepairMap = new Map<String, Double>();
            yrCols = new List<String>();
            dcCols = new Map<String, List<String>>();
            xColListMap = new Map<String, List<String>>();
            ttlColspan = 0;
            if (isCategory2) ttlColspan++;
            if (isCategory3) ttlColspan++;
            if (isCategory4) ttlColspan++;
            if (isCategory5) ttlColspan++;
            if (isProductCode) ttlColspan++;
        }
    }
}