/**
 * サビコン見積PDFのコントローラです。
 */

public with sharing class MaintenanceContractEstimatePDFController {
    /** 処理対象の見積オブジェクトです。 */
    public EstimateInfo targetObj { get; private set; }
    /** 見積オブジェクトのリスト（改ページ用） */
    public List<EstimateInfo> targetObjList { get; private set; }
    /** 1ページに表示する明細の数です。 */
    private Integer rowSize = 13; // TODO ラベルに定義
    
    private Integer nameMax = 23;
    private Integer commentMax = 5;
    
    private Integer lineNo = 0;
    
    public Integer year { get; private set; }
    
    public Integer getTargetObjSize() {
        return this.targetObjList.size();
    }

    /**
     * Visualforceページがアクセスするコンストラクタです。
     * 印刷するデータを収集し、インスタンス変数にセットします。
     * @param controller スタンダードコントローラーのインスタンス
     */
    public MaintenanceContractEstimatePDFController(ApexPages.StandardController controller) {
    }
    public void init() {
        String targetEstimateId = ApexPages.currentPage().getParameters().get('id');
        // 見積情報を取得、必ずあるはず
        // TODO 書き方修正
        List<Maintenance_Contract_Estimate__c> mceList = 
                [SELECT Id, Name, Maintenance_Contract__c, Estimate_Target__c, Dealer__r.Name, CreatedDate,
                        Maintenance_Contract__r.Management_Code__c,
                        Maintenance_Contract__r.Hospital__r.Name, Department__c,
                        Contract_Range__c, Contract_Esti_Start_Date__c, Contract_Esti_End_Date__c,
                        Contract_Start_Date__c, Contract_End_Date__c,
                        Estimate_Trial_Money__c, Asset_Repair_Sum_Price__c, Maintenance_Price__c, NotUse_Oxygenated_Water__c,
                        Examination_Price__c, Service_contract_target_number__c, Append_Condition_Price__c,
                        Discount_Price__c, Discount_Percentage__c, Last_Discount__c, Asset_Sum_Price__c,
                        Print_Contract__c, Print_RepairPrice__c, Print_DiscountPercentage__c,
                        Print_DiscountPrice__c, Print_ListPrice__c, Print_MaintePrice__c, Print_SumPrice__c
                   FROM Maintenance_Contract_Estimate__c WHERE Id = :targetEstimateId]
        ;
        // 見積を取得できない場合
        if (mceList.size() == 0) {
            throw new ControllerUtil.myException('报价不存在');
        }
        
        this.targetObj = new EstimateInfo(mceList);
        targetObjList = new List<EstimateInfo>();
        // ページ毎に見積の情報（製品はページ毎にバラバラ）
        EstimateInfo tmpTargetObj = new EstimateInfo(mceList);
        // 新品と酸化水の金額を算出するため、製品を一リストに集約
        EstimateInfo targetObjForSum = this.targetObj;
        
        // 合計の出力フラグによりページ毎の行数を変更
        if (!this.targetObj.estimate.Print_SumPrice__c) {
            rowSize = rowSize + 3;
        }
        if (!this.targetObj.estimate.Print_MaintePrice__c) {
            rowSize = rowSize + 1;
        }
        
        // 明細の設定
        Integer cnt = 1;
        for(Maintenance_Contract_Asset_Estimate__c mcae :
                [SELECT Id, Name, Asset__c,
                        Asset__r.Name, Asset__r.SerialNumber, Asset__r.InstallDate,
                        Product_Manual__c, Product_Manual__r.Maintenance_Price_Month__c, Product_Manual__r.Name, IsNew__c,
                        Maintenance_Price_Month__c, Estimate_List_Price__c,
                        Check_Result__c, Repair_Price__c, Comment__c
                   FROM Maintenance_Contract_Asset_Estimate__c
                  WHERE Maintenance_Contract_Estimate__c = :this.targetObj.estimate.Id
                  ORDER BY Product_Manual__c, Asset__r.SerialNumber, Asset__r.Name, Asset__r.Department_Name__c, Asset__r.InstallDate]) {
            //for(Integer a=0;a<20;a++){
            //tmpTargetObj.addAssetInfo(mcae);
            //targetObjForSum.addAssetInfo(mcae);
            
            String sname = '';
            if (mcae.Asset__c != null) {
            	sname = mcae.Asset__r.Name == null ? '' : mcae.Asset__r.Name;
            } else if (mcae.Product_Manual__c != null) {
            	sname = mcae.Product_Manual__r.Name == null ? '' : mcae.Product_Manual__r.Name;
            }
            String smodelNo = '';
            String scomment = mcae.Comment__c == null ? '' : mcae.Comment__c;
            if (sname.indexOf(':') >= 0) {
            	smodelNo = sname.subString(0, sname.indexOf(':')+1);
                sname = sname.subString(sname.indexOf(':')+1);
            } else if (sname.indexOf('：') >= 0) {
            	smodelNo = sname.subString(0, sname.indexOf('：')+1);
                sname = sname.subString(sname.indexOf('：')+1);
            } else {
            	smodelNo = '';
            }
            Integer iname = (sname.length() / nameMax) + (Math.mod(sname.length(), nameMax) > 0 ? 1 : 0);
            if (iname == 0) {
            	iname = 1;
            }
            Integer icomment = (scomment.length() / commentMax) + (Math.mod(scomment.length(), commentMax) > 0 ? 1 : 0);
            if (icomment == 0) {
            	icomment = 1;
            }
            Integer icnt = iname;
            if (iname < icomment) {
            	icnt = icomment;
            }
            if (icnt > 1) {
            	for (Integer i = 0; i < icnt; i++) {
            		if  (i == 0) {
            			String printName = '';
            			if (i + 1 == iname) {
				            printName = smodelNo + sname;
            			} else {
				            printName = smodelNo + sname.substring(0, nameMax);
            			}
            			if (i + 1 == icomment) {
            				mcae.Comment__c = scomment;
            			} else {
            				mcae.Comment__c = scomment.substring(0, commentMax);
            			}
            			lineNo += 1;
            			tmpTargetObj.addAssetInfo(lineNo, mcae, printName);
            			targetObjForSum.addAssetInfo(lineNo, mcae, printName);
            		} else {
            			String printName = '';
            			Maintenance_Contract_Asset_Estimate__c newmcae = mcae.clone();
            			if (i < iname) {
            				if (i + 1 == iname) {
					            printName = sname.substring(i*nameMax);
            				} else {
					            printName = sname.substring(i*nameMax, (i+1)*nameMax);
            				}
            			} else {
				            printName = '';
            			}
            			if (i < icomment) {
            				if (i + 1 == icomment) {
            					newmcae.Comment__c = scomment.substring(i*commentMax);
            				} else {
            					newmcae.Comment__c = scomment.substring(i*commentMax, (i+1)*commentMax);
            				}
            			} else {
            				newmcae.Comment__c = '';
            			}
            			tmpTargetObj.addAssetInfo(lineNo, newmcae, printName);
            			targetObjForSum.addAssetInfo(lineNo, newmcae, printName);
            			
            			AssetInfo ainfo = tmpTargetObj.assetInfoList.get(tmpTargetObj.assetInfoList.size()-1);
				        ainfo.lineNo = null;
				        ainfo.assetModelNo = null;
				        ainfo.assetSerialNumber = null;
				        ainfo.installDate = null;
				        ainfo.mcae.Check_Result__c = null;
				        ainfo.listPrice = 0.0;
				        ainfo.repairPrice = 0.0;
				        ainfo.newDiscount = 0.0;
				        ainfo.quantity = null;
				        ainfo.mcae.Repair_Price__c = null;
				        ainfo.mcae.Estimate_List_Price__c = null;

				        AssetInfo ainfo2 = targetObjForSum.assetInfoList.get(targetObjForSum.assetInfoList.size()-1);
				        ainfo2.lineNo = null;
				        ainfo2.assetModelNo = null;
				        ainfo2.assetSerialNumber = null;
				        ainfo2.installDate = null;
				        ainfo2.mcae.Check_Result__c = null;
				        ainfo2.listPrice = 0.0;
				        ainfo2.repairPrice = 0.0;
				        ainfo2.newDiscount = 0.0;
				        ainfo2.quantity = null;
				        ainfo2.mcae.Repair_Price__c = null;
				        ainfo2.mcae.Estimate_List_Price__c = null;
            		}
            		// 改ページ判断
		            if (cnt == this.rowSize) {
		                cnt = 0;
		                targetObjList.add(tmpTargetObj);
		                tmpTargetObj = new EstimateInfo(mceList);
		            }
		            cnt++;
            	}
            } else {
            	lineNo += 1;
            	tmpTargetObj.addAssetInfo(lineNo, mcae, null);
            	targetObjForSum.addAssetInfo(lineNo, mcae, null);
            	// 改ページ判断
	            if (cnt == this.rowSize) {
	                cnt = 0;
	                targetObjList.add(tmpTargetObj);
	                tmpTargetObj = new EstimateInfo(mceList);
	            }
	            cnt++;
            }
//            }
        }

        // 新品优惠
        lineNo += 1;
        Boolean rs = tmpTargetObj.addNewDiscountLine(lineNo, targetObjForSum.assetInfoList);
        targetObjForSum.addNewDiscountLine(lineNo, targetObjForSum.assetInfoList);
        if (!rs) {
        	lineNo -= 1;
        }
        // xudan 20140424 バグ修正、ちょうど改ページ後の第一行目に、新品优惠を出すかどうかの判断を修正
        if (tmpTargetObj.assetInfoList.size() > 0 && tmpTargetObj.assetInfoList[tmpTargetObj.assetInfoList.size() - 1].assetName == '新品优惠') {
            if (cnt == this.rowSize) {
                cnt = 0;
                targetObjList.add(tmpTargetObj);
                tmpTargetObj = new EstimateInfo(mceList);
            }
            cnt++;
        }
        
        // 酸化水非使用
        if (tmpTargetObj.estimate.NotUse_Oxygenated_Water__c) {
        	lineNo += 1;
            tmpTargetObj.addOxyDiscount(lineNo, targetObjForSum.assetInfoList);
            targetObjForSum.addOxyDiscount(lineNo, targetObjForSum.assetInfoList);
            if (cnt == this.rowSize) {
                cnt = 0;
                targetObjList.add(tmpTargetObj);
                tmpTargetObj = new EstimateInfo(mceList);
            }
            cnt++;
        }
        
        // 遡るIdx、端数処理金額をどんなページに置くかを制御
        Integer backIdx = this.calcBackIdx(cnt);
        // 遡るIdx、端数処理金額をどんな行に置くかを制御
        Integer backDetailIdx = this.calcBackDetailIdx(cnt);
        
        // 定期点検
        lineNo += 1;
        tmpTargetObj.addExaminationPrice(lineNo, tmpTargetObj.estimate);
        targetObjForSum.addExaminationPrice(lineNo, tmpTargetObj.estimate);
        
        targetObjList.add(tmpTargetObj);
        
        // 会計年度計算、ただしここは 日本の年度ではない
//        Integer y = this.targetObj.estimate.Contract_Esti_Start_Date__c.year();
//        Integer m = this.targetObj.estimate.Contract_Esti_Start_Date__c.month();
        Integer y = this.targetObj.estimate.Contract_Start_Date__c.year();
        Integer m = this.targetObj.estimate.Contract_Start_Date__c.month();
        if (m >= 4) {
            this.year = y;
        } else {
            this.year = y;  // y - 1;
        }
        
        // 合計金額との端数処理の場合、修理金額を無視
        // 実際金額との端数処理の場合、修理金額を含む（実際=合計+修理-优惠）
        Boolean countRepair = false;
        Decimal finalPrice = 0;
        // listpriceと実際金額の差額対応，端数処理
        if (!this.targetObj.estimate.Print_SumPrice__c && this.targetObj.estimate.Print_MaintePrice__c) {
            //this.targetObj.estimate.Examination_Price__c = (this.targetObj.estimate.Examination_Price__c * (1 - this.targetObj.estimate.Discount_Percentage__c / 100)).setScale(2, RoundingMode.HALF_UP);
            // listpriceと実際金額の差額対応
//            finalPrice = this.targetObj.estimate.Maintenance_Price__c - this.targetObj.estimate.Examination_Price__c;
            finalPrice = this.targetObj.estimate.Maintenance_Price__c;
            countRepair = true;
        }
        // listpriceと合計金額の差額対応，端数処理
        else {
//            finalPrice = this.targetObj.estimate.Estimate_Trial_Money__c - this.targetObj.estimate.Examination_Price__c;
            finalPrice = this.targetObj.estimate.Estimate_Trial_Money__c;
        }
        
        Decimal tmpPrice = 0;
        for (Integer i = 0; i < targetObjForSum.assetInfoList.size(); i++) {
            tmpPrice += targetObjForSum.assetInfoList[i].listPrice != null ? targetObjForSum.assetInfoList[i].listPrice : 0;
            if (countRepair) {
                if (targetObjForSum.assetInfoList[i].repairPrice != null) {
                    tmpPrice += targetObjForSum.assetInfoList[i].repairPrice;
                }
            }
system.debug('tmpPrice:::' + tmpPrice);
        }
system.debug('finalPrice:::' + finalPrice);
system.debug('targetObjList.size():::' + targetObjList.size());
system.debug('backIdx:::' + backIdx);
system.debug('backDetailIdx:::' + backDetailIdx);
        if (finalPrice - tmpPrice != 0) {
            // targetObjList.size()=ページ数 
            if (targetObjList.size() - 1 - backIdx >= 0) {
                // assetSize=ページ内の明細行数
                Integer assetSize = targetObjList[targetObjList.size() - 1 - backIdx].assetInfoList.size();
                if (assetSize - 1 - backDetailIdx >= 0) {
                    targetObjList[targetObjList.size() - 1 - backIdx].assetInfoList[assetSize - 1 - backDetailIdx].listPrice += finalPrice - tmpPrice;
                }
            }
        }
        
    }
    
    /**
    * 遡るIdx計算
    */
    private Integer calcBackIdx(Integer cnt) {
        // 定期点検行の前ちょうどに改ページ
        if (cnt == 1) {
            // 最後ページは明細がない、誤差補正金額を前ページの明細に加算
            return 1;
        } else {
            // 最後ページは明細があり、誤差補正金額をこのページの明細に加算
            return 0;
        }
    }
    
    /**
    * 遡るIdx計算
    */
    private Integer calcBackDetailIdx(Integer cnt) {
        // 定期点検行の前ちょうどに改ページ
        if (cnt == 1) {
            // 最後ページは定期点検しかない、誤差補正金額を前ページの最後行に加算
            return 0;
        } else {
            // 最後ページは明細があり、誤差補正金額をこのページの定期点検行の上に加算
            return 1;
        }
    }

    /**
     * 印刷するデータを格納するオブジェクを定義する、親
     */
    public class EstimateInfo {
        public Maintenance_Contract_Estimate__c estimate {get; private set;}
        public String createdDate {get; private set;}
        public List<AssetInfo> assetInfoList {get; private set;}
        
        public EstimateInfo(List<Maintenance_Contract_Estimate__c> estimateList) {
            if (estimateList.size() > 0) {
                this.estimate = estimateList[0];
                this.createdDate = estimateList[0].CreatedDate.format('yyyy/MM/dd');
                this.assetInfoList = new List<AssetInfo>();
            }
        }
        
        public void addAssetInfo(Integer lno, Maintenance_Contract_Asset_Estimate__c mcae, String printName) {
            this.assetInfoList.add(new AssetInfo(lno, mcae, estimate, printName));
        }
        
        public Boolean addNewDiscountLine(Integer lno, List<AssetInfo> tmpAssetInfoList) {
            AssetInfo tmpNewDiscount = new AssetInfo(lno);
            tmpNewDiscount.assetModelNo = '新品优惠';
            tmpNewDiscount.assetName = '新品优惠';
            tmpNewDiscount.assetSerialNumber = '-';
            tmpNewDiscount.installDate = '-';
            tmpNewDiscount.quantity = null;
            for (AssetInfo ai : tmpAssetInfoList) {
                tmpNewDiscount.listPrice -= ai.newDiscount;
            }
            if (tmpNewDiscount.listPrice < 0) {
                assetInfoList.add(tmpNewDiscount);
                return true;
            }
            return false;
        }
        
        public void addOxyDiscount(Integer lno, List<AssetInfo> tmpAssetInfoList) {
            AssetInfo tmpOxyDiscount = new AssetInfo(lno);
            tmpOxyDiscount.assetModelNo = '酸化水';
            tmpOxyDiscount.assetName = '酸化水';
            tmpOxyDiscount.assetSerialNumber = '-';
            tmpOxyDiscount.installDate = '-';
            tmpOxyDiscount.quantity = null;
            
            Decimal tmpPrice = 0;
            // 消毒液折扣=(定价-新品折扣)*0.1 
            for (AssetInfo ai : tmpAssetInfoList) {
                // 新品优惠を追加した場合、新品优惠行をスキップ
                if (ai.assetName != '新品优惠') {
                	system.debug(ai.listPrice);
                	system.debug(ai.newDiscount);
                    tmpPrice += ai.listPrice - ai.newDiscount;
                    system.debug(tmpPrice);
                }
            }
            tmpOxyDiscount.listPrice -= tmpPrice * 0.1;
            assetInfoList.add(tmpOxyDiscount);
        }
        
        public void addExaminationPrice(Integer lno, Maintenance_Contract_Estimate__c mce) {
            AssetInfo tmpCheckPrice = new AssetInfo(lno);
            tmpCheckPrice.assetModelNo = '定期点检';
            tmpCheckPrice.assetName = '定期点检';
            tmpCheckPrice.assetSerialNumber = '-';
            tmpCheckPrice.installDate = '-';
            tmpCheckPrice.quantity = Integer.valueOf(mce.Service_contract_target_number__c);
            tmpCheckPrice.listPrice = null;
//            tmpCheckPrice.listPrice = mce.Examination_Price__c;
//            if (!mce.Print_SumPrice__c && mce.Print_MaintePrice__c) {
//                tmpCheckPrice.listPrice = (mce.Examination_Price__c * (1 - mce.Discount_Percentage__c / 100)).setScale(2, RoundingMode.HALF_UP);
//            }
            assetInfoList.add(tmpCheckPrice);
        }
    }

    /**
     * 印刷するデータを格納するオブジェクを定義する、子供
     */
    public class AssetInfo {
        public Integer lineNo {get; private set;}
        public Maintenance_Contract_Asset_Estimate__c mcae {get; private set;}
        public Decimal listPrice {get; private set;}
        public Decimal repairPrice {get; private set;}
        public Decimal newDiscount {get; private set;}
        public String assetModelNo {get; private set;}
        public String assetName {get; private set;}
        public String assetSerialNumber {get; private set;}
        public Integer quantity {get; private set;}
        public String installDate {get; private set;}
        
        public AssetInfo(Integer lineNo) {
            this.lineNo = lineNo;
            this.listPrice = 0.0;
            this.repairPrice = 0.0;
            this.newDiscount = 0.0;
            this.mcae = null;
        }
        
        public AssetInfo(Integer lineNo, Maintenance_Contract_Asset_Estimate__c mcae, Maintenance_Contract_Estimate__c estimate, String printName) {
            this.lineNo = lineNo;
            this.mcae = mcae;
            this.listPrice = 0.0;
            this.newDiscount = 0.0;
            this.repairPrice = 0.0;
            this.quantity = 1;
            
            Decimal month = estimate.Contract_Range__c;
            if (month > 12) {
            	month = 12;
            }
            
            if (mcae.Asset__c != null) {
                // Assetある
                if (printName == null) {
                	this.assetName = mcae.Asset__r.Name;
                } else {
                	this.assetName = printName;
                }
                this.assetSerialNumber = mcae.Asset__r.SerialNumber;
                this.listPrice = estimate.Contract_Range__c * mcae.Estimate_List_Price__c;
                this.installDate = mcae.Asset__r.InstallDate != null ? String.valueOf(mcae.Asset__r.InstallDate).replace('-', '/') : '';
                if (mcae.IsNew__c) {
                    this.listPrice = estimate.Contract_Range__c * mcae.Maintenance_Price_Month__c;
//                    this.newDiscount = estimate.Contract_Range__c * (mcae.Maintenance_Price_Month__c - mcae.Estimate_List_Price__c);
					this.newDiscount = month * (mcae.Maintenance_Price_Month__c - mcae.Estimate_List_Price__c);
                }
            } else if (mcae.Product_Manual__c != null) {
                // 手入力
                if (printName == null) {
                	this.assetName = mcae.Product_Manual__r.Name;
                } else {
                    this.assetName = printName;
                }
                this.assetSerialNumber = '新购入';
                this.installDate = '新购入';
                this.listPrice = estimate.Contract_Range__c * mcae.Product_Manual__r.Maintenance_Price_Month__c;
//                this.newDiscount = estimate.Contract_Range__c * (mcae.Product_Manual__r.Maintenance_Price_Month__c - mcae.Estimate_List_Price__c);
				this.newDiscount = month * (mcae.Product_Manual__r.Maintenance_Price_Month__c - mcae.Estimate_List_Price__c);
            } else {}
            
            if (mcae.Repair_Price__c != null) {
                this.repairPrice = mcae.Repair_Price__c;
            }
            
            // 合計金額出さずに実際金額を出す場合、値引きで表示、四捨五入
            if (!estimate.Print_SumPrice__c && estimate.Print_MaintePrice__c) {
                this.listPrice = (this.listPrice * (1 - estimate.Discount_Percentage__c / 100)).setScale(2, RoundingMode.HALF_UP);
                this.newDiscount = (this.newDiscount * (1 - estimate.Discount_Percentage__c / 100)).setScale(2, RoundingMode.HALF_UP);
            }
            
            // 名前 ':' の対応
            this.assetName = assetName == null ? '' : assetName;
            if (this.assetName.indexOf(':') >= 0) {
                this.assetModelNo = this.assetName.subString(0, this.assetName.indexOf(':'));
                this.assetName = this.assetName.subString(this.assetName.indexOf(':')+1);
            } else if (this.assetName.indexOf('：') >= 0) {
                this.assetModelNo = this.assetName.subString(0, this.assetName.indexOf('：'));
                this.assetName = this.assetName.subString(this.assetName.indexOf('：')+1);
            } else {
                this.assetModelNo = '';
            }
        }
    }
}