package jp.agentec.sinaburocast.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.seasar.extension.jdbc.where.SimpleWhere;
import org.seasar.framework.container.annotation.tiger.Component;
import org.seasar.framework.container.annotation.tiger.InstanceType;
import org.seasar.framework.util.IntegerConversionUtil;
import org.seasar.framework.util.StringUtil;

import jp.agentec.sinaburocast.common.SinaburoConstant;
import jp.agentec.sinaburocast.entity.AdminUser;
import jp.agentec.sinaburocast.entity.Answer;
import jp.agentec.sinaburocast.entity.Question;
import jp.agentec.sinaburocast.form.admin.enquete.EnqueteRegistForm;

@Component(instance=InstanceType.SINGLETON)
public class QuestionService extends AbstractService<Question> {
	
	public static final String ID_SEQ_NAME = "question_id_seq";

	
	public AnswerService answerService;
	
	public ReplyService replyService;
	/**
	 * IDを発行して、登録する。
	 */
	public int insertQuestion(Question question, String insId) {
		question.questionId= 
			getSeqNextVal(Integer.class, ID_SEQ_NAME);
		return super.insert(question, insId);
	}
	
	
    public Question findById(Integer questionId) {
        return select().id(questionId).getSingleResult();
    }

    public List<Question> findAllOrderById() {
        return select().orderBy("questionId asc").getResultList();
    }
    
    /**
     * アンケートIDに紐付いている「設問マスタ」、「設問回答マスタ」を取得する。
     * ※セッションに保持する際はListでは保持されないのでArrayList使用
     * @param enqueteid アンケートID
     * @return 
     * 
     */
	public ArrayList<Question> findAllOrderByEnqueteId(String enqueteid) {
		
//        return (ArrayList<Question>)select().leftOuterJoin("answerList").where(new SimpleWhere()
//                                               .eq("enqueteid",enqueteid)
//                                               .eq("delFlg",SinaburoConstant.DelFlg.NOT_DEL))
//                                               .orderBy("T1_.enquete_id,T1_.question_no,T2_.Answer_no")
//                                               .getResultList();
		
		return (ArrayList<Question>)select().leftOuterJoin("answerList").where(
			"T1_.enquete_id = ? AND T1_.del_flg=? AND T2_.del_flg=?"
			,Integer.parseInt(enqueteid)
			,Integer.parseInt(SinaburoConstant.DelFlg.NOT_DEL)
			,Integer.parseInt(SinaburoConstant.DelFlg.NOT_DEL)
				)
        .orderBy("T1_.enquete_id,T1_.question_no,T2_.Answer_no")
        .getResultList();
		
    }
	
	/**
     * アンケートIDと設問番号に紐付いている「設問マスタ」、「設問回答マスタ」を取得する。
     * ※セッションに保持する際はListでは保持されないのでArrayList使用
     * @param enqueteid アンケートID
     * @return 
     * 
     */
	public Question findByQuestionIdOrderByEnqueteId(Integer questionId) {
		
        return (Question)select().leftOuterJoin("answerList").where(new SimpleWhere()
                                               .eq("questionId",questionId)
                                               .eq("delFlg",SinaburoConstant.DelFlg.NOT_DEL))
                                               .orderBy("T1_.enquete_id,T1_.question_no,T2_.Answer_no")
                                               .getSingleResult();
    }
	
	
    
    
    public List<Question> findAllByEnqueteId(String eid) {
        return select().where(new SimpleWhere().eq("enqueteId",eid).eq("delFlg", SinaburoConstant.DelFlg.NOT_DEL)).getResultList();
    }
    
    public List<Question> findAllByEnqueteId(Integer eid) {
        return select().where(new SimpleWhere().eq("enqueteId",eid).eq("delFlg", SinaburoConstant.DelFlg.NOT_DEL)).orderBy("questionId").getResultList();
    }
    
    
    /**
     * アンケート検索画面で削除ボタンを押した場合。論理削除
     * @param eid アンケートID
     * @return
     */
    public int deleteByEnqueteId(String eid,String adminLoginId){
    	int count=0; 
    	List<Question> answerList = findAllByEnqueteId(eid);
    	
    	for(Question answer :answerList){
    		answer.delFlg = Integer.parseInt(SinaburoConstant.DelFlg.DEL);
    		count+=update(answer,adminLoginId);
    	}
    	
    	return count;
    }
    
    /**
     * 次の設問番号を取得する。
     * @param eid
     * @return
     */
    public int getNextNo(Integer eid){
    	return jdbcManager.selectBySql(Integer.class, "select COALESCE(max(question_no),0) + 1 from m_question where enquete_id=? and del_flg=0", eid).getSingleResult();
    }
    
    
    /**
     * 設問を削除する。
     * @param questionId
     * @param adminLoginId
     * @return
     */
    private int deleteByQuestionId(Integer questionId,String adminLoginId){
    	return jdbcManager.updateBySql("update m_question set del_flg=1 where question_id = ? ", Integer.class).params(questionId).execute();
    }
    
    /**
     * 設問一覧画面にて削除した場合
     * @param frm
     * @param adminLoginId
     * @param isUpdate 
     * @return
     */
    public int questionRegist(EnqueteRegistForm frm,String adminLoginId, boolean isUpdate){
    	
    	Integer eidInt = Integer.parseInt(frm.eid);
    	if(frm.inputQuestion.questionNo == null && !isUpdate){
    		frm.inputQuestion.questionNo=this.getNextNo(eidInt);
    	}
    	
    	
    	if(isUpdate){
    		this.update(frm.inputQuestion, adminLoginId);
    	}else{
    		this.insertQuestion(frm.inputQuestion, adminLoginId);
    	}
    	//this.update(frm.inputQuestion, adminLoginId);
		
		//設問回答登録
		for (int j = 0; j < frm.inputQuestion.answerList.size(); j++) {
			Answer answer = frm.inputQuestion.answerList.get(j);
			answer.enqueteId = eidInt; 
			answer.answerNo = j +1 ;
			answer.questionId = frm.inputQuestion.questionId;
			answer.freeTextFlg = answer.freeTextFlg == null ? 0 :answer.freeTextFlg;
			answer.freeTextColWidth = answer.freeTextColWidth == null ? 0 :answer.freeTextColWidth;
			answer.freeTextRowNum = answer.freeTextRowNum == null ? 0 :answer.freeTextRowNum;
			answer.freeTextLimit = answer.freeTextLimit == null ? 0 :answer.freeTextLimit;
			answer.delFlg = 0;
			
			//採番登録
			if(answer.answerId == null){
				answerService.insertAnswer(answer, adminLoginId);
			//登録
			}else{
				//answerService.insert(answer, adminLoginId).;
				answerService.insert(answer,adminLoginId);
			}
		}
		
		return 0;
    }
    
    public List<Question> findAllByCondId(Integer questionId) {
        return select().where(new SimpleWhere().eq("condRequiredQuestionNo", questionId)).getResultList();
    }
    
    
    /**
     * 設問一覧画面にて削除した場合TX
     * 設問に関連する情報を全部削除する。
     * @param questionId
     * @param adminLoginId
     * @param isClear trueの場合条件付き必須設問クリア
     * @return
     */
    public int deleteByQuestionInfo(String delQuestionId,String adminLoginId, boolean isClear){
    	String[] delQuestionIdList = delQuestionId.split(",");

		for (int i = 0; i < delQuestionIdList.length; i++) {
			Integer questionId = Integer.parseInt(delQuestionIdList[i]);
			
			//削除対象設問を条件付き必須に設定している設問の条件付き設定をクリアする。
			if(isClear){//更新の場合は削除しない
				List<Question> condQuestionList = findAllByCondId(questionId);
				for (Question condQuestion : condQuestionList) {
					condQuestion.condRequiredQuestionNo=0;
					condQuestion.condRequiredAnswer="0";
					this.update(condQuestion);
				}
				// m_question
				this.deleteByQuestionId(questionId,adminLoginId);
				// m_answer			
				answerService.deleteByQuestionId(questionId, adminLoginId);	
			}else{
				//更新の場合
				answerService.recodeDeleteByQuestionId(questionId, adminLoginId);
			}
			
			// m_reply
			replyService.deleteByquestionId(questionId, adminLoginId);
		}
		
		return 0;
	
    }
    
//    public QuestionService questionService;
    
    /**
     * アンケート更新時のみ呼ばれる。
     * @param oldQuestion
     * @param condAnswerStr
     * @param frm
     * @param adminUser
     * @return
     */
    public int questionUpdate(Question oldQuestion,ArrayList<String>  condAnswerStr,EnqueteRegistForm frm, AdminUser adminUser){
    	//削除対象設問を条件付き必須に設定している設問の条件付き設定をクリアする。
		List<Question> condQuestionList = this.findAllByCondId(oldQuestion.questionId);
		String condString = "";
		for (Question condQuestion : condQuestionList) {
			//condQuestion.condRequiredAnswer="0";
			condString = "";
			for (String condAnswerId : condQuestion.condRequiredAnswer.split(",")) {
				if(condAnswerStr.contains(condAnswerId)){
					//残っている回答だけを入れる。 
					condString +=condAnswerId+",";
				}
			}
			 
			if(condString.endsWith(",")){
				condQuestion.condRequiredAnswer=condString.substring(0,condString.lastIndexOf(","));
			}
			//condQuestion.condRequiredAnswer=condAnswerStr;
			this.update(condQuestion);//削除対象を条件付きにかけている設問の回答IDを変更
		}
		//既存の設問情報、回答情報削除
		frm.delQuestionIdList = frm.inputQuestion.questionId.toString();
		
		this.deleteByQuestionInfo(frm.delQuestionIdList,adminUser.loginId,false);
		this.questionRegist(frm,adminUser.loginId, true);
    	return 0;
    }
    
    /**
     * 設問をコピーする。
     * 
     * @param questionId 設問ID
     * @return
     */
    public void questionCopy(Integer originEnqueteId, Integer newEnqueteId, String loginId) {
    	List<Question> questionList = findAllByEnqueteId(originEnqueteId);
    	// アンケートに設問がない場合
    	if  (CollectionUtils.isEmpty(questionList)) {return;}
    	HashMap<Integer, Integer> questionIdMap = new HashMap<Integer, Integer>();
    	HashMap<String, String> answerIdStrMap = new HashMap<String, String>();
    	Integer originQuestionId;
    	Integer originAnswerId;
    	for (Question question : questionList) {
    		originQuestionId = question.questionId;
    		question.enqueteId = newEnqueteId;
    		question.version = 0;
    		// 詳細項目情報取得
	    	List<Answer> answerList = answerService.findAllByEnqueteId(originEnqueteId, originQuestionId);
			insertQuestion(question, loginId);
			questionIdMap.put(originQuestionId, question.questionId);
			for (Answer answer : answerList) {
				originAnswerId = answer.answerId;
				answer.enqueteId = newEnqueteId;
				// 新しいquestionIdをセット
				answer.questionId = question.questionId;
				answer.version = 0;
				answerService.insertAnswer(answer, loginId);
				answerIdStrMap.put(String.valueOf(originAnswerId), String.valueOf(answer.answerId));
			}
		}
    	// 条件付必須情報コピー
    	List<Question> copiedQuestionList = findAllByEnqueteId(newEnqueteId);
    	String answerIdArrayStr = "";
    	for (Question copiedQuestion : copiedQuestionList) {
			if (copiedQuestion.condRequiredQuestionNo != null && !copiedQuestion.condRequiredQuestionNo.equals(0)) {
				copiedQuestion.condRequiredQuestionNo = questionIdMap.get(copiedQuestion.condRequiredQuestionNo);
				for (String answerIdStr : copiedQuestion.condRequiredAnswer.split(",")) {
					answerIdArrayStr += answerIdStrMap.get(answerIdStr) + ",";
				}
				copiedQuestion.condRequiredAnswer = answerIdArrayStr.replaceAll(",$", "");
				update(copiedQuestion, loginId);
				answerIdArrayStr = "";
			} else if ((copiedQuestion.condRequiredQuestionNo == null || copiedQuestion.condRequiredQuestionNo.equals(0)) 
					&& copiedQuestion.condRequiredAnswer != null) {
				copiedQuestion.condRequiredAnswer = null;
				update(copiedQuestion, loginId);
			}
		}
    }
    /**
     * 条件付必須チェック(初期画面表示・非表示セット)
     * 
     * @param questionList
     * @return
     */
    public void setQuestionDisable(List<Question> questionList) {
    	Map<Integer, Integer> requiredAnswerIdMap = new HashMap<Integer, Integer>();
    	Map<Integer, Integer> defaultAnswerIdMap = new HashMap<Integer, Integer>();
    	for (Question question : questionList) {
    		if (question.controlId.equals(SinaburoConstant.ControlType.TEXTAREA) 
    		 || question.controlId.equals(SinaburoConstant.ControlType.TEXTFIELD)
    		 || question.controlId.equals(SinaburoConstant.ControlType.HIDUKE)) {continue;}
    		
    		for (Answer answer : question.answerList) {
    			if (question.condRequiredQuestionNo != null && requiredAnswerIdMap.get(answer.answerId) == null) {
    				if (answer.defaultFlg == 0 && StringUtil.isBlank(answer.answerIdValue)) {continue;}
    				//条件付回答設定の選択した値
    				if ((question.controlId.equals(SinaburoConstant.ControlType.RADIO)
    				  || question.controlId.equals(SinaburoConstant.ControlType.SELECTMENU)) 
    				     && answer.defaultFlg == 0 && StringUtil.isNotBlank(answer.answerIdValue)) {
    					requiredAnswerIdMap.put(answer.answerId, question.controlId);
    					break;
    				}
    				if (question.controlId.equals(SinaburoConstant.ControlType.CHECKBOX) 
    				 && answer.defaultFlg == 0 && StringUtil.isNotBlank(answer.answerIdValue)) {
    					requiredAnswerIdMap.put(answer.answerId, question.controlId);
    				}
    				//条件付回答設定のデフォルト値
    				if (answer.defaultFlg == 1) {
    					defaultAnswerIdMap.put(answer.answerId, question.controlId);
    				}
				}
    		}
    	}
    	for (Map.Entry<Integer, Integer> entry : defaultAnswerIdMap.entrySet()) {
			//デフォルト値は存在、選択値はなし
    		if (!requiredAnswerIdMap.containsValue(entry.getValue())) {
    			requiredAnswerIdMap.put(entry.getKey(), entry.getValue());
			}
		}
		for (Question question : questionList) {
			//条件付必須チェック(初期画面表示・非表示セット)
			if (question.condRequiredQuestionNo != null && question.condRequiredQuestionNo != 0
					&& StringUtils.isNotBlank(question.condRequiredAnswer)) {
				List<String> requiredAnswerIdList = new ArrayList<String>(Arrays.asList(question.condRequiredAnswer.split(",")));
				for (String requiredAnswerId : requiredAnswerIdList) {
					if (requiredAnswerIdMap.get(IntegerConversionUtil.toInteger(requiredAnswerId)) == null) {
						question.questionInitDisable = SinaburoConstant.initDisable.YES;
					} else {
						question.questionInitDisable = SinaburoConstant.initDisable.NO;
						break;
					}
				}
			}
		}
		//グレーアウト処理した項目を初期化
		for (Question question : questionList) {
			if (question.questionInitDisable == SinaburoConstant.initDisable.YES) {
				for (Answer answer : question.answerList) {
					if (answer.defaultFlg == 0) {
						answer.answerIdValue = "";
						answer.answerValue = "";
					}
				}
			}
		}
    }

    
    /**
     * 指定した設問の回答件数をメンバーIDの重複は除いて(複数回答対応のため)返す。
     * 
     * @param questionId 設問ID
     * @return
     */
    public Integer getAnswerMemberCount(Integer questionId){
    	return jdbcManager.selectBySql(Integer.class,
    			"select count(distinct member_id) " +
    			"from m_question mq " +
    			"inner join t_reply tr " +
    			"on mq.question_id = tr.question_id " +
    			"where mq.question_id = ? " +
    			"group by mq.question_id", questionId).getSingleResult();
    }
    
    /**
     * 指定した設問の回答件数を回答回数の重複は除いて(複数回答対応のため)返す。
     * 
     * 
     * @param questionId 設問ID
     * @return
     */
    public Integer getAnswerTimesCount(Integer questionId){
    	return jdbcManager.selectBySql(Integer.class,
    			"select count(distinct answer_times) " +
    			"from m_question mq " +
    			"inner join t_reply tr " +
    			"on mq.question_id = tr.question_id " +
    			"where mq.question_id = ? " +
    			"group by mq.question_id", questionId).getSingleResult();
    }
    
	public Question getMailTypeQuestion(Integer enqueteId) {
		return select().where(new SimpleWhere().eq("enqueteId", enqueteId).eq("mailType", 1).eq("delFlg", 0)).getSingleResult();
	}
}