public with sharing class OpportunityPCLController2 {
	public List<OppInfo> oppRecords { get; set; }
	// ページレイアウトの情報を取得
	private Map<String, String> DESC_RW = null;
  
	/*****************検索用******************/
	public Contact con1 { get; set; }
	public Contact con2 { get; set; }
  
	public String accSearch { get; set; }
	public String ownerSearch { get; set; }
  
	public List<SelectOption> dateOpts { get; private set; }
	public List<SelectOption> textOpts { get; private set; }
	public List<SelectOption> equalOpts { get; private set; }
	public List<SelectOption> textOpts2 { get; private set; }
	public List<SelectOption> equalOpts2 { get; private set; }
	public List<SelectOption> textOpts3 { get; private set; }
	public List<SelectOption> equalOpts3 { get; private set; }
	public List<SelectOption> limitOpts { get; private set; }
  
	public String dateField { get; set; }
  
	public String text { get; set; }
	public String condition { get; set; }
	public String value { get; set; }
  
	public String text2 { get; set; }
	public String condition2 { get; set; }
	public String value2 { get; set; }
  
	public String text3 { get; set; }
	public String condition3 { get; set; }
	public String value3 { get; set; }
  
	// TODO xudan 20140626 チェック：询价、未チェック：全部（後藤要望）
	public Boolean onlyOpp { get; set; }
	public String limits { get; set; }
  
	/*****************画面表示Bean******************/
	public Integer oppCount { get; set; }
	public String saveType { get; set; }
  
	/*****************ソートキー******************/
	public String sortKey { get; set; }
	public String preSortKey { get; set; }
	public Boolean sortOrderAsc { get; set; }
	public String[] sortOrder { get; set; }
	public String[] columus = new String[] {'Id'};
	public Set<String> columusSet = new Set<String> {'Id'};
  
	// 项目set 字段标签
	public List<String> titleLeft { get; private set; }
	public List<String> titleRight { get; private set; }
	// 项目set 字段名
	public List<List<String> > columnsLeftApi { get; private set; }         // 参照項目用
	public List<List<String> > columnsRightApi { get; private set; }        // 参照項目用
	public List<String> columnLeftCss { get; private set; }               // css 用
	public List<String> columnRightCss { get; private set; }              // css 用
	public Map<String, String> columnLeftRW { get; private set; }              // r,w,wm用
	public Map<String, String> columnRightRW { get; private set; }             // r,w,wm用
	public List<String> columnMark { get; private set; }                  // Mark用
	private String strColumus;                                            // soql用項目
	private String strColumusForMoney;                                    // 金額集計soql用項目
	public Map<String, Decimal> columnMoneyMap { get; private set; }
	public Map<String, Boolean> columnMoneyFlgMap { get; private set; }
  
	public Integer ratingStartIdx { get; private set; }  // Rating表示ラベルの開始Idx
  
	/*****************ソート時再検索条件（画面からの入力条件を無視するため）******************/
	private String hpForSort = null;
	private String ownerForSort = null;
	private String datefieldForSort = null;
	private Date fromdForSort = null;
	private Date todForSort = null;
	private String textForSort = null;
	private String conditionForSort = null;
	private String valueForSort = null;
	private String textForSort2 = null;
	private String conditionForSort2 = null;
	private String valueForSort2 = null;
	private String textForSort3 = null;
	private String conditionForSort3 = null;
	private String valueForSort3 = null;
	private String limitForSort = null;
	private Boolean onlyOppForSort = true;
  
	private static Integer oppLimit = 1000;
	private Boolean isForMoneyFlg = false;
  
	public OpportunityPCLController2() {
	  //Apexpages.currentPage().getHeaders().put('X-UA-Compatible', 'IE=8');
	  DESC_RW = SoapApi.getEditLayoutItemRW('Opportunity', new String[] {'01210000000QekKAAS'}).get('01210000000QekKAAS');
	  oppRecords = new List<OppInfo>();
  
	  // 日付検索条件のCalendar用
	  con1 = new Contact();
	  con2 = new Contact();
  
	  dateOpts = new List<SelectOption>();
	  dateOpts.add(new SelectOption('', '--无--'));
	  dateOpts.add(new SelectOption('Bid_Planned_Date__c', '预测招标日'));
	  dateOpts.add(new SelectOption('Bid_Date__c', '招标日'));
	  dateOpts.add(new SelectOption('Closing_Bid_Date__c', '中标日'));
  
	  dateOpts.add(new SelectOption('Close_Forecasted_Date__c', '预测OCSM签约日'));
  
	  //SWAG-C9NC23 【委托】[重要，优先！]周会询价管理表修改   lt   20211217  start
	  dateOpts.add(new SelectOption('Close_Forecasted_Assume_Date__c', '预测OCSM签约日(担当)'));
	  //SWAG-C9NC23 【委托】[重要，优先！]周会询价管理表修改   lt   20211217  end
  
	  dateOpts.add(new SelectOption('CloseDate', '预测发货日'));
	  dateOpts.add( new SelectOption('Created_Day__c', '创建日'));
	  dateOpts.add(new SelectOption('Last_Follow_Up_Date__c', '最后跟进日'));//***********************
	  // 日付検索に標準のLastModifiedDate（日時項目）は使えない、数式項目を利用
	  //dateOpts.add(new SelectOption('LastModified_Day__c', '最后更新日'));//**************************
	  //syu 2014/6/25 追加した
	  dateOpts.add( new SelectOption('Last_opd_date__c', '最后OPD实施日'));
	  dateOpts.add( new SelectOption('Key_tipics_last_update_day__c', '重要字段更新日'));
	  dateOpts.add( new SelectOption('Forecast_amount_last_update_day__c', '最后更新日-预测成交金额(含税)'));
	  dateOpts.add( new SelectOption('Stage2_last_update_day__c', '最后更新日-状态2'));
	  dateOpts.add( new SelectOption('OPP_rank_Last_update_day__c', '最后更新日-询价等级'));
	  dateOpts.add( new SelectOption('Tender_data_last_update_day__c', '最后更新日-预测招标日'));
	  dateOpts.add( new SelectOption('Bid_date_last_update_day__c', Schema.SObjectType.Opportunity.fields.Bid_date_last_update_day__c.label));
	  dateOpts.add( new SelectOption('Closing_Bid_date_last_update_day__c', '最后更新日-中标日'));
	  dateOpts.add( new SelectOption('Opp_forecast_day_last_update_day__c', '最后更新日-预测OCSM签约日'));
	  dateOpts.add( new SelectOption('Agent_Hospital_Contract_day_last_update__c', '最后更新日-经销商-医院(签)'));
	  dateOpts.add( new SelectOption('Agency_Contract_Date_last_update__c', '最后更新日-OCSM-经销商(签)'));
	  dateOpts.add( new SelectOption('Forecast_shipping_day_last_update__c', '最后更新日-预测发货日'));
	  dateOpts.add( new SelectOption('Situation_last_update_day__c', '最后更新日-询价跟进情况'));
	  dateOpts.add( new SelectOption('Manager_feedback_last_update__c', '最后更新日-经理反馈'));
	  dateOpts.add( new SelectOption('Follow_up_plan_last_update__c', '最后更新日-推进计划'));
  
	  textOpts = new List<SelectOption>();
	  textOpts.add(new SelectOption('','--无--'));
	  textOpts.add(new SelectOption('S:Name','询价名称'));
	  textOpts.add(new SelectOption('S:Opportunity_No__c',Schema.SObjectType.Opportunity.fields.Opportunity_No__c.label));
	  textOpts.add(new SelectOption('S:HP_Name__c','医院名'));
	  // TODO xudan 20140626 状态1をチェックボックスに、ここ要らない？
	  textOpts.add(new SelectOption('S:Owner.Salesdepartment__c','本部'));
	  textOpts.add(new SelectOption('S:Owner.Province__c','省'));
	  textOpts.add(new SelectOption('S:Owner.Group__c','组'));
	  textOpts.add(new SelectOption('S:StageName__c','状态1'));
	  textOpts.add(new SelectOption('S:Owner.Name','担当人'));
	  textOpts.add(new SelectOption('S:OCM__c','OCSM分类'));
	  textOpts.add(new SelectOption('S:Department_Name__c','科室名'));
	  textOpts.add(new SelectOption('S:Opportunity_Category__c','询价科室分类'));
	  //textOpts.add(new SelectOption('N:Estimation_List_Price__c','标准定价总额'));
	  //textOpts.add(new SelectOption('N:Wholesale_Price_F__c','预测成交金额(含税)'));
	  //textOpts.add(new SelectOption('N:Amount_Without_Tax_F__c','预测成交金额(不含税)'));
	  textOpts.add(new SelectOption('S:Agency1__r.Name','经销商1'));
	  //textOpts.add(new SelectOption('S:Status_Formula__c','状态2'));
	  textOpts.add(new SelectOption('S:Competitor__c','询价等级'));
	  //textOpts.add(new SelectOption('S:OPD_SIS_collect_evaluation_sight__r.Name',Schema.SObjectType.Opportunity.fields.OPD_SIS_collect_evaluation_sight__c.label));
	  textOpts.add(new SelectOption('S:Forecast_this_month__c','本月预测'));
	  //textOpts.add(new SelectOption('N:Lapsed_Days__c',Schema.SObjectType.Opportunity.fields.Lapsed_Days__c.label));
	  //textOpts.add(new SelectOption('S:Rating01__c','1月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating02__c','2月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating03__c','3月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating04__c','4月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating05__c','5月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating06__c','6月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating07__c','7月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating08__c','8月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating09__c','9月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating10__c','10月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating11__c','11月末询价状态'));
	  //textOpts.add(new SelectOption('S:Rating12__c','12月末询价状态'));
  
	  textOpts2 = textOpts;
	  textOpts3 = textOpts;
  
	  equalOpts = new List<SelectOption>();
	  equalOpts.add(new SelectOption('equals','等于'));
	  equalOpts.add(new SelectOption('notequals','不等于'));
	  equalOpts.add(new SelectOption('<','<'));
	  equalOpts.add(new SelectOption('>','>'));
	  equalOpts.add(new SelectOption('<=','<='));
	  equalOpts.add(new SelectOption('>=','>='));
	  equalOpts.add(new SelectOption('contains','包含'));
	  equalOpts.add(new SelectOption('notcontains','不包含'));
	  equalOpts.add(new SelectOption('starts with','起始字符'));
  
	  equalOpts2 = equalOpts;
	  equalOpts3 = equalOpts;
  
	  limitOpts = new List<SelectOption>();
	  limitOpts.add(new SelectOption('20','20'));
	  limitOpts.add(new SelectOption('50','50'));
	  limitOpts.add(new SelectOption('100','100'));
	  limitOpts.add(new SelectOption('200','200'));
	  limitOpts.add(new SelectOption('500','500'));
	  limitOpts.add(new SelectOption('' + (oppLimit + 1), '全部'));
  
	  limits = '50';
  
	  ratingStartIdx = -1;
	}
  
	public PageReference init() {
	  // xudan 20140626 状态1をチェックボックスに
	  onlyOpp = true;
  
	  //20140822　追加 by katsu start
	  String uidParam = System.currentPageReference().getParameters().get('uid');
	  if (uidParam != null) {
		User u = [select Id, FirstName, LastName from User where Id = :uidParam];
		ownerSearch = u.LastName + ' ' + u.FirstName;
	  }
	  String hpidParam = System.currentPageReference().getParameters().get('hpid');
	  if(hpidParam != null) {
		List<Account> hpAcc = ControllerUtil.selectAccountForTrigger(new String[] {hpidParam});
		if (hpAcc.size() > 0) {
		  accSearch = hpAcc[0].name;
		}
	  }
	  //20140822　追加 by katsu end
  
	  searchOppSetParam();
	  setLayoutRWInfo();
	  this.sortOrderAsc = true;
	  this.sortOrder = new String[columus.size()];
	  for (Integer i = 0; i < columus.size(); i++) this.sortOrder[i] = '　';
	  searchOppInner();
	  return null;
	}
  
	private void searchOppSetParam() {
	  hpForSort = accSearch;
	  ownerForSort = ownerSearch;
	  datefieldForSort = dateField;
	  fromdForSort = con1.Birthdate;
	  todForSort = con2.Birthdate;
	  textForSort = text;
	  conditionForSort = condition;
	  valueForSort = value;
	  textForSort2 = text2;
	  conditionForSort2 = condition2;
	  valueForSort2 = value2;
	  textForSort3 = text3;
	  conditionForSort3 = condition3;
	  valueForSort3 = value3;
	  limitForSort = limits;
	  onlyOppForSort = onlyOpp;
  
	}
  
	private void setLayoutRWInfo() {
	  if (this.sortOrder == null) {
  
		List<String> columnsForMoney = new List<String>();
		Set<String> currencyFields = new Set<String>();
  
		// 获得项目set
		Map<String, Schema.FieldSet> fsMap = Schema.getGlobalDescribe().get('Opportunity').getDescribe().fieldSets.getMap();
  
		// 合計金額計算用
		Schema.FieldSet fs = fsMap.get('Opportunity_PCL_Sum');
		List<FieldSetMember> fsmList = fs.getFields();
		columnMoneyMap = new Map<String, Decimal>();
		columnMoneyFlgMap = new Map<String, Boolean>();
		for (FieldSetMember fsm : fsmList) {
		  columnMoneyMap.put(fsm.getFieldPath(), 0);
		}
  
		// 左 固定
		fs = fsMap.get('Opportunity_PCL_L');
		// 获得项目set中的所有项目
		fsmList = fs.getFields();
		// 获得字段标签和字段名
		titleLeft = new List<String>();
		List<String> columnLeft = new List<String>();
  
		columnLeftCss = new List<String>();
		columnLeftRW = new Map<String, String>();
		columnsLeftApi = new List<List<String> >();
		for (FieldSetMember fsm : fsmList) {
		  titleLeft.add(fsm.getLabel());
		  columnLeft.add(fsm.getFieldPath());
		  List<String> splitFieldPath = fsm.getFieldPath().split('\\.');
		  columnsLeftApi.add(splitFieldPath);
  
		  if (String.valueOf(fsm.getType()) == 'CURRENCY') {
			currencyFields.add(fsm.getFieldPath());
		  }
  
		  if (DESC_RW == null) {
			columnLeftRW.put(fsm.getFieldPath(), 'r');
		  } else if (splitFieldPath.size() == 1) {
			String rw = DESC_RW.get(fsm.getFieldPath());
			if (rw != null) {
			  columnLeftRW.put(fsm.getFieldPath(), rw);
			} else {
			  columnLeftRW.put(fsm.getFieldPath(), 'r');
			}
		  } else {
			columnLeftRW.put(fsm.getFieldPath(), 'r');
		  }
		}
		for (String s : columnLeft) {
		  if (columusSet.contains(s) == false) {
			columus.add(s);
			if (currencyFields.contains(s)) {
			  columnsForMoney.add('convertCurrency(' + s + ')');
			} else {
			  columnsForMoney.add(s);
			}
			columusSet.add(s);
		  }
		  if (columnMoneyMap.containsKey(s)) {
			columnMoneyFlgMap.put(s.replace('.','_'), true);
		  } else {
			columnMoneyFlgMap.put(s.replace('.','_'), false);
		  }
		  columnLeftCss.add(s.replace('.','_'));
		}
		fs = fsMap.get('Opportunity_PCL');
		// 获得项目set中的所有项目
		fsmList = fs.getFields();
		// 获得字段标签和字段名
		titleRight = new List<String>();
		List<String> tmpColRight = new List<String>();
  
		columnRightCss = new List<String>();
		columnRightRW = new Map<String, String>();
		columnsRightApi = new List<List<String> >();
  
		Integer cnt = 0;
		for (FieldSetMember fsm : fsmList) {
		  titleRight.add(fsm.getLabel());
		  List<String> splitFieldPath = fsm.getFieldPath().split('\\.');
		  columnsRightApi.add(splitFieldPath);
  
		  if (String.valueOf(fsm.getType()) == 'CURRENCY') {
			currencyFields.add(fsm.getFieldPath());
		  }
		  // 「1月末」を設定したら、12ヶ月分を設定と見なす
		  // 設定の順番や、欠番などを考慮せず
		  if (splitFieldPath.size() == 1 && splitFieldPath[0] == 'Rating01__c') {
			ratingStartIdx = cnt;
		  }
  
		  if (DESC_RW == null) {
			columnRightRW.put(fsm.getFieldPath(), 'r');
		  } else if (splitFieldPath.size() == 1) {
			String rw = DESC_RW.get(fsm.getFieldPath());
			if (rw != null) {
			  columnRightRW.put(fsm.getFieldPath(), rw);
			} else {
			  columnRightRW.put(fsm.getFieldPath(), 'r');
			}
		  } else {
			columnRightRW.put(fsm.getFieldPath(), 'r');
		  }
  
		  tmpColRight.add(fsm.getFieldPath());
		  cnt++;
		}
		for (String s : tmpColRight) {
		  if (columusSet.contains(s) == false) {
			columus.add(s);
			if (currencyFields.contains(s)) {
			  columnsForMoney.add('convertCurrency(' + s + ')');
			} else {
			  columnsForMoney.add(s);
			}
			columusSet.add(s);
  
		  }
		  if (columnMoneyMap.containsKey(s)) {
			columnMoneyFlgMap.put(s.replace('.','_'), true);
		  } else {
			columnMoneyFlgMap.put(s.replace('.','_'), false);
		  }
		  columnRightCss.add(s.replace('.','_'));
		}
  
		for (Integer i = 0; i < columnRightCss.size(); i++) {
  
		  if (i == ratingStartIdx) {
			// 12ヶ月の旧Css
			Map<Integer, String> oldCssMap = new Map<Integer, String>();
			// 12ヶ月の旧ラベル
			Map<Integer, String> oldLabelMap = new Map<Integer, String>();
			for (Integer m = 1; m <= 12; m++) {
			  oldCssMap.put(m, columnRightCss[i + m - 1]);
			  oldLabelMap.put(m, titleRight[i + m - 1]);
			}
			// 12ヶ月
			for (Integer m = 1; m <= 12; m++) {
			  Integer newM = makeRatingLabel(m);
			  // ラベル
			  titleRight[i + m - 1] = oldLabelMap.get(newM);
			  // CSS
			  columnRightCss[i + m - 1] = oldCssMap.get(newM);
			  // Read/Write
			  columnRightRW.put(columnRightCss[i + m - 1], 'r');
			  // API
			  columnsRightApi[i + m - 1] = new String[] { makeRatingAPI(m, Date.today().month()) };
			  columus[columnLeftCss.size() + 1 + i + m - 1] = makeRatingAPI(m, Date.today().month());
			}
			break;
		  }
		}
  
		// ソート用
		this.sortOrderAsc = true;
		this.sortOrder = new String[columus.size()];
		for (Integer i = 0; i < columus.size(); i++) this.sortOrder[i] = '　';
  
		// Mark
		fs = fsMap.get('Opportunity_PCL_Mark');
		// 获得项目set中的所有项目
		fsmList = fs.getFields();
		columnMark = new List<String>();
		for (FieldSetMember fsm : fsmList) {
		  columnMark.add(fsm.getFieldPath());
		}
		for (String s : columnMark) {
		  if (columusSet.contains(s) == false) {
			columus.add(s);
			columusSet.add(s);
		  }
		}
  
		strColumus = String.join(columus, ',');
		strColumusForMoney = String.join(columnsForMoney, ',');
		system.debug('=====strColumus:' + strColumus);
	  }
	}
  
	private void searchOppInner() {
	  oppRecords = new List<OppInfo>();
  
	  String soql = this.makeSoql(false, hpForSort, ownerForSort,
								  datefieldForSort, fromdForSort, todForSort, textForSort, conditionForSort, valueForSort,
								  textForSort2, conditionForSort2, valueForSort2,
								  textForSort3, conditionForSort3, valueForSort3);
	  if (String.isBlank(this.sortKey)) {
		soql += ' order by LastModifiedDate desc limit ' + Integer.valueOf(limits);
	  } else {
		soql += ' order by ' + this.columus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first' : 'desc nulls last') + ' limit ' + Integer.valueOf(limits);
	  }
  
	  String soqlForMoney = this.makeSoql(true, hpForSort, ownerForSort,
										  datefieldForSort, fromdForSort, todForSort, textForSort, conditionForSort, valueForSort,
										  textForSort2, conditionForSort2, valueForSort2,
										  textForSort3, conditionForSort3, valueForSort3);
	  if (String.isBlank(this.sortKey)) {
		soqlForMoney += ' order by LastModifiedDate desc limit ' + Integer.valueOf(System.Label.TotalLimit);
	  } else {
		soqlForMoney += ' order by ' + this.columus[Integer.valueOf(this.sortKey)] + ' ' + (this.sortOrderAsc == true ? 'asc nulls first' : 'desc nulls last')+ ' limit ' + Integer.valueOf(System.Label.TotalLimit);
	  }
	  system.debug('soql:' + soql);
	  List<Opportunity> queryList = Database.query(soql);
	  List<Opportunity> queryListForMoney = Database.query(soqlForMoney);
  
	  this.makeOppRecordsForView(queryList, queryListForMoney);
  
	  oppCount = oppRecords.size();
	  if (String.isBlank(this.sortKey)) {
		ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '取得最近的 ' + oppCount + ' 条数据'));
	  } else {
		if (oppCount > oppLimit) {
		  ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '数据超过' + oppLimit + '件，只显示前' + oppLimit + '件'));
		} else {
		  ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '共有 ' + oppCount + ' 条数据'));
		}
	  }
	}
  
	public PageReference searchOpp() {
	  searchOppSetParam();
	  setLayoutRWInfo();
	  searchOppInner();
	  return null;
	}
  
	public PageReference sortTable() {
	  oppRecords = new List<OppInfo>();
  
	  if (this.sortKey == this.preSortKey) {
		if (String.isBlank(this.sortKey) == false) {
		  // 方向が変わるのみ
		  this.sortOrderAsc = !this.sortOrderAsc;
		  this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑' : '↓');
		}
	  } else {
		this.sortOrderAsc = true;
		if (String.isBlank(this.preSortKey) == false) {
		  this.sortOrder[Integer.valueOf(this.preSortKey)] = '　';
		}
		this.sortOrder[Integer.valueOf(this.sortKey)] = (this.sortOrderAsc == true ? '↑' : '↓');
	  }
	  this.preSortKey = this.sortKey;
  
	  setLayoutRWInfo();
	  searchOppInner();
	  return null;
	}
  
	public PageReference save() {
	  try {
		List<Opportunity> updOpps = new List<Opportunity>();
  
		List<String> oppidList = new List<String>();
		Map<String, String> oppidMap = new Map<String, String>();
		for (OppInfo oi : oppRecords) {
		  if (oi.changeFlg == '1') {
			if (oppidMap.containsKey(oi.rec.Id) == false) {
			  oppidList.add(oi.rec.Id);
			}
		  }
		}
  
		Map<String, Opportunity> oppMap = new Map<String, Opportunity>();
		List<Opportunity> oppList = [select Id, Competitor__c from Opportunity where Id = :oppidList];
		for (Opportunity opp : oppList) {
		  oppMap.put(opp.Id, opp);
		}
  
		for (OppInfo oi : oppRecords) {
		  // 変更チェック
		  if (oi.changeFlg == '1') {
			oi.changeFlg = '0';
			oi.rec.Competitor__c = oppMap.get(oi.rec.Id).Competitor__c;
			updOpps.add(oi.rec);
		  }
		}
  
		if (updOpps.size() > 0) update updOpps;
		ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, '保存完了'));
	  } catch (Exception ex) {
		ApexPages.addMessages(ex);
		return null;
	  }
  
	  if (saveType == '1') {
		searchOpp();
		saveType = '';
	  } else if (saveType == '2') {
		sortTable();
		saveType = '';
	  } else {
	  }
	  return null;
	}
  
	public PageReference cancel() {
	  return new PageReference('/home/home.jsp');
	}
  
	private String makeSoql(Boolean isforMoneyFlg, String accStr, String ownerStr, //String dept, String rank, Boolean consumable,
							String datefield, Date fromd, Date tod, String txt, String con, String val,
							String txt2, String con2, String val2,
							String txt3, String con3, String val3) {
	  String soql ='';
	  if (isforMoneyFlg == false) {
		soql += 'select ' + strColumus + ' from Opportunity where (RecordType.DeveloperName = \'Opportunity\' or RecordType.DeveloperName = \'SI_Oppor\')';
  /*            soql += 'select Id, Name, Hospital__r.Name, Hospital__c, StageName__c, Status_Formula__c,'
  + ' Opportunity_No__c, AccountId, Account.Name, OwnerId, Owner.Name, Opportunity_Category__c,'
  + ' Estimation_List_Price__c, Estimation_Id__c, Estimation_No__c, Last_Shipping_Scheduled_Date__c,  Last_Shipping_Date__c,'
  + ' Last_Follow_Up_Date__c, CreatedDate, LastModified_Day__c, Closing_Bid_Date__c, Important_Rroduct_Flg__c,'//Owner.Brief_Name__c,
  + ' Rating01__c, Rating02__c, Rating03__c, Rating04__c, Rating05__c, Rating06__c,'
  + ' Rating07__c, Rating08__c, Rating09__c, Rating10__c, Rating11__c, Rating12__c,'
  + ' HP_Name__c, Sales_incharge__c, Wholesale_Price_F__c, Agency1__c, '//Estimation_List_Price_Formula__c, OCM_Agent1_Price_Formula__c,
  + ' Segment__c, Opp_Code__c, Open_Quotation__c, Competitor__c, Bid_Planned_Date__c,'
  + ' Close_Forecasted_Date__c, CloseDate, Follow_up_comment__c, Department_Name__c,'
  + ' Next_Action__c, Create_Activity__c, Nunber_of_visit__c, Number_of_OPD__c, Rating__c, '//Quotation_Number_SAP__c,,  Discount_Rate__c
  + ' OCM__c, Amount_Without_Tax_F__c, Key_tipics_last_update_day__c, Update_situation__c , Last_opd_date__c,'
  + ' Stage2_last_update_day__c, Follow_up_plan_last_update__c, Closing_Bid_date_last_update_day__c, OPP_rank_Last_update_day__c, Situation_last_update_day__c, '
  + ' Opp_forecast_day_last_update_day__c, Tender_data_last_update_day__c, Forecast_amount_last_update_day__c, Forecast_shipping_day_last_update__c, Created_Day__c, '
  + ' Agency_Contract_Date1__c, Sales_Shop_Hospital_Contract__c, Manager_feedback__c, Forecast_this_month__c,'
  + ' Manager_feedback_last_update__c, Agency_Contract_Date_last_update__c, Agent_Hospital_Contract_day_last_update__c,'
  + ' Bid_Date__c, Bid_date_last_update_day__c, Collect_Customer_sign__c, Lapsed_Days__c, OPD_SIS_collect_evaluation_sight__c,'
  + ' Owner.Salesdepartment__c, Owner.Province__c, Owner.Group__c'
  + ' from Opportunity where (RecordType.DeveloperName = \'Opportunity\')';// and (stageName = \'引合\')';*/
	  } else {
		soql += 'select ' + strColumusForMoney + ' from Opportunity where (RecordType.DeveloperName = \'Opportunity\' or RecordType.DeveloperName = \'SI_Oppor\')';
  /*            soql += 'select Id, Name, Hospital__r.Name, Hospital__c, StageName__c, Status_Formula__c,'
  + ' Opportunity_No__c, AccountId, Account.Name, OwnerId, Owner.Name, Opportunity_Category__c,'
  + ' convertCurrency(Estimation_List_Price__c), Estimation_Id__c, Estimation_No__c, Last_Shipping_Scheduled_Date__c,  Last_Shipping_Date__c,'
  + ' Last_Follow_Up_Date__c, CreatedDate, LastModified_Day__c, Closing_Bid_Date__c, Important_Rroduct_Flg__c,'//Owner.Brief_Name__c,
  + ' Rating01__c, Rating02__c, Rating03__c, Rating04__c, Rating05__c, Rating06__c,'
  + ' Rating07__c, Rating08__c, Rating09__c, Rating10__c, Rating11__c, Rating12__c,'
  + ' HP_Name__c, Sales_incharge__c, convertCurrency(Wholesale_Price_F__c), Agency1__c, '//Estimation_List_Price_Formula__c, OCM_Agent1_Price_Formula__c,
  + ' Segment__c, Opp_Code__c, Open_Quotation__c, Competitor__c, Bid_Planned_Date__c,'
  + ' Close_Forecasted_Date__c, CloseDate, Follow_up_comment__c, Department_Name__c, '
  + ' Next_Action__c, Create_Activity__c, Nunber_of_visit__c, Number_of_OPD__c, Rating__c, '//Quotation_Number_SAP__c,,  Discount_Rate__c
  + ' OCM__c, convertCurrency(Amount_Without_Tax_F__c), Key_tipics_last_update_day__c, Update_situation__c , Last_opd_date__c,'
  + ' Stage2_last_update_day__c, Follow_up_plan_last_update__c, Closing_Bid_date_last_update_day__c, OPP_rank_Last_update_day__c, Situation_last_update_day__c, '
  + ' Opp_forecast_day_last_update_day__c, Tender_data_last_update_day__c, Forecast_amount_last_update_day__c, Forecast_shipping_day_last_update__c, Created_Day__c, '
  + ' Agency_Contract_Date1__c, Sales_Shop_Hospital_Contract__c, Manager_feedback__c, Forecast_this_month__c,'
  + ' Manager_feedback_last_update__c, Agency_Contract_Date_last_update__c, Agent_Hospital_Contract_day_last_update__c,'
  + ' Bid_Date__c, Bid_date_last_update_day__c, Collect_Customer_sign__c, Lapsed_Days__c, OPD_SIS_collect_evaluation_sight__c,'
  + ' Owner.Salesdepartment__c, Owner.Province__c, Owner.Group__c'
  + ' from Opportunity where (RecordType.DeveloperName = \'Opportunity\')';// and (stageName = \'引合\')';*/
	  }
	  // xudan 20140626 状态1をチェックボックスに
	  if (onlyOpp) {
		soql += ' and StageName__c = \'询价\'';
	  }
	  if (!String.isBlank(accStr)) {
		//soql += ' and Hospital__c = \'' + accStr + '\'';
		String[] vals = accStr.split(' ');
		for (String v : vals) {
		  soql += ' and Hospital__r.Name like \'%' + String.escapeSingleQuotes(v.replaceAll('%', '\\%')) + '%\'';
		}
	  }
	  if (!String.isBlank(ownerStr)) {
		//soql += ' and OwnerId = \'' + ownerStr + '\'';
		String[] vals = ownerStr.split(' ');
		for (String v : vals) {
		  soql += ' and Owner.Name like \'%' + String.escapeSingleQuotes(v.replaceAll('%', '\\%')) + '%\'';
		}
	  }
  
	  if (!String.isBlank(datefield)) {
		if (fromd != null) {
		  soql += ' and ' +  datefield + ' >= ' + String.valueOf(fromd).substring(0, 10);
		}
		if (tod != null) {
		  soql += ' and (' +  datefield + ' <= ' + String.valueOf(tod).substring(0, 10) + ' OR ' + datefield + ' = null)';
		}
	  }
  
  
	  // xudan 20140507 検索ロジック修正
	  soql += this.makeTextSql(txt, con, val);
	  soql += this.makeTextSql(txt2, con2, val2);
	  soql += this.makeTextSql(txt3, con3, val3);
  
	  system.debug(soql);
	  return soql;
	}
  
	private void makeOppRecordsForView(List<Opportunity> queryList, List<Opportunity> queryListForMoney) {
	  Savepoint sp = Database.setSavepoint();
	  // TODO queryList について、最初のoppLimitだけ更新すればOKです。
	  Database.SaveResult[] results = Database.update(queryList, false);
	  // 強制ロールバック
	  Database.rollback(sp);
	  // 合计值清空
	  for (String key : columnMoneyMap.keySet()) {
		columnMoneyMap.put(key, 0);
	  }
  
	  for (Integer i = 0; i < queryListForMoney.size(); i++) {
		if(i<queryList.size()) {
		  // limitを超えた場合前limit件のみを出す
		  if (i == oppLimit + 1) {
			// TODO メッセージ表示
			continue;
		  }
		  oppRecords.add(new OppInfo(queryList[i]));
		  oppRecords[oppRecords.size() - 1].lineNo = oppRecords.size() - 1;
		  if (!results[i].isSuccess()) {
			oppRecords[oppRecords.size() - 1].canEdit = false;
			// 空更新失敗の場合、編集できないとみなす
			// xudan 20140624 更新権限のエラーのみロック
			if (results[i].getErrors()[0].getStatusCode() != null) {
			  if (String.valueOf(results[i].getErrors()[0].getStatusCode()) == 'INSUFFICIENT_ACCESS_OR_READONLY') {
				oppRecords[oppRecords.size() - 1].hasError = true;
				// xudan 20140624 更新権限エラーとほかのエラーを区別
			  } else {
				oppRecords[oppRecords.size() - 1].hasFieldError = true;
			  }
			}
		  }
		}
  
		for (String key : columnMoneyMap.keySet()) {
		  Decimal d = columnMoneyMap.get(key);
		  d += queryListForMoney[i].get(key) == null ? 0 : Decimal.valueOf(String.valueOf(queryListForMoney[i].get(key)));
		  columnMoneyMap.put(key, d);
		}
	  }
	}
  
	private String makeTextSql(String txt1, String con, String val) {
	  String soql = '';
	  // containsの場合、日報画面の病院検索を真似し、spaceで分けて、and検索
	  // equalsの場合、SF標準の検索を真似し、「,」で分けて、or検索
	  if (!String.isBlank(txt1)) {
		if ((con == 'contains' || con == 'notcontains') && val.contains(' ')) {
		  String[] vals = val.split(' ');
		  String cSql = '';
		  for (String v : vals) {
			cSql += this.makeTextSqlStr(txt1, con, v);
		  }
		  if (con == 'contains') {
			soql += cSql;
		  } else {
			// notcontains
			cSql = cSql.replaceAll(' and ', ') and (NOT ');
			soql += cSql.substring(1) + ') ';
		  }
		} else if ((con == 'equals' || con == 'notequals') && val.contains(',')) {
		  String[] vals = val.split(',');
		  if (vals.size() > 0) {
			String txt = txt1.substring(2);     // S:Name 、最初の２文字がタイプです
			soql += ' and ( ';
			for (String v : vals) {
			  if (con == 'equals') {
				soql += txt + ' = \'' + v + '\' or ';
			  } else {
				// notequals
				soql += txt + ' <> \'' + v + '\' and ';
			  }
			}
			soql = soql.substring(0, soql.length() - 4);
			soql += ')';
		  }
		} else {
		  String cSql = this.makeTextSqlStr(txt1, con, val);
		  if (con != 'notcontains') {
			soql += this.makeTextSqlStr(txt1, con, val);
		  } else {
			// notcontains
			cSql = cSql.substring(5);       // ' and ' の5文字を外す
			soql += ' and (NOT ' + cSql + ') ';
		  }
		}
	  }
	  return soql;
	}
  
	/**
	 * 文字列検索文を作成
	 */
	private String makeTextSqlStr(String txt1, String con, String val) {
	  String soql = '';
	  if (!String.isBlank(txt1)) {
		String txt = txt1.substring(2);
		String colType = txt1.substring(0, 2);
		String tmpVal = val;
		// 空白の場合''にする
		if (String.isBlank(tmpVal)) {
		  if (con == 'equals') {
			//soql += ' and ' + txt + ' = ' + tmpVal;
			soql += ' and ' + txt + ' = null';
		  } else if (con == 'notequals') {
			soql += ' and ' + txt + ' <> null';
		  } else {
			// 空白の場合、contains, notcontains と starts withは無視
		  }
		} else {
		  soql += ' and ' + txt;
		  if (con == 'equals') {
			if (colType == 'S:') {
			  soql += ' = \'' + tmpVal + '\'';
			} else {
			  soql += ' = ' + tmpVal + ' ';
			}
		  } else if (con == 'notequals') {
			if (colType == 'S:') {
			  soql += ' <> \'' + tmpVal + '\'';
			} else {
			  soql += ' <> ' + tmpVal + ' ';
			}
		  } else if (con == 'contains' || con == 'notcontains') {
			soql += ' like \'%' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
		  } else if (con == 'starts with') {
			soql += ' like \'' + String.escapeSingleQuotes(tmpVal.replaceAll('%', '\\%')) + '%\'';
		  } else {
			if (colType == 'S:') {
			  soql += ' ' + con + '\'' + tmpVal + '\'';
			} else {
			  soql += ' ' + con + ' ' + tmpVal + ' ';
			}
		  }
		}
	  }
	  return soql;
	}
  
	/**
	 * 現在の月にて、表示すべきラベル名を作成
	 */
	private Integer makeRatingLabel(Integer idx) {
	  Integer m = Date.today().month();
  
	  Integer val = idx - 1 + m;
	  if (val > 12) {
		val = val - 12;
	  }
	  return val;
	}
  
	/**
	 * 現在の月にて、Ratingのソート番号を作成
	 */
  
	private Integer makeRatingSortIdx(Integer idx) {
	  Integer m = Date.today().month();
  
	  Integer val = idx - 1 + m;
	  if (val > 29) {
		  val = val - 12;
	  }
	  return val;
	}
  
  
	/**
	 * 現在の月にて、取得すべきAPI名を作成
	 */
	private String makeRatingAPI(Integer idx, Integer m) {
	  String rtn = '';
  
	  Integer val = idx - 1 + m;
	  if (val > 12) {
		val = val - 12;
	  }
	  if (val < 10) {
		rtn = '0' + val;
	  } else {
		rtn = '' + val;
	  }
  
	  return 'Rating' + rtn + '__c';
	}
  
	class OppInfo {
	  public Opportunity rec { get; set; }
	  public Boolean canEdit { get; private set; }
	  public Boolean hasError { get; private set; }
	  public Boolean hasFieldError { get; private set; }
	  public Integer lineNo { get; private set; }
	  public String changeFlg { get; set; }
  
	  public OppInfo(Opportunity record) {
		rec = record;
		canEdit = true;
		hasError = false;
		hasFieldError = false;
		lineNo = 0;
		changeFlg = '0';
	  }
	}
  }