package net.sourceforge.jsurveyor;
import java.util.ArrayList;
import java.lang.Integer;

/**
 * This class is made for containing and calculating on the evaluations that
 * users write in. It's only input is a questionnaireID where the rest is
 * taking from the database, and it is used by ReportOutput to generate a pdf
 * document. The calculations done in this class is getting the newest
 * evaluations and adding the multiplechoice answers together. There will only
 * be get and creation of the report method in this Class because it's not the
 * idea to change the data that is retrieved from the database.
 * 
 * @version 1.0
 * @author Claus Methmann Christensen
 * @author Anders Spliid Hansen
 * @author Esben Iversen Hansen
 * @author Lars H Jensen
 * @author Marcus Overheu
 * @author Thomas Ramdal
 * @author Peter Thomsen
 */
public class Report {
	/**
	 * Field reportID
	 */
	private int reportID;
	/**
	 * Field questionnaireID
	 */
	private int questionnaireID;
	/**
	 * Field questionnaireIntroText
	 */
	private String questionnaireIntroText;
	/**
	 * Field questionnaireName
	 */
	private String questionnaireName;
	/**
	 * Field allEvaluations
	 */
	private ArrayList allEvaluations;
	/**
	 * Field usableEvaluations which are the newest evaluations send in by each
	 * user, for this particular questionnaire
	 */
	private ArrayList usableEvaluations = new ArrayList();
	/**
	 * Field innerAnswerMultipleChoice
	 */
	private ArrayList innerAnswerMultipleChoice = new ArrayList();
	/**
	 * Field innerQuestionFreeText
	 */
	private ArrayList innerQuestionFreeText = new ArrayList();
	/**
	 * Default Constructor for Report, with no inputs and values
	 *  
	 */
	public Report() {

	}

	/**
	 * Constructor for Report, this is the most used constructor for report it
	 * takes the questionnaireID as an input for knowing which quesionnaire to
	 * take, and calls 2 methods: getEvaluations(questionnaireID) and
	 * findTypeOfInnerAnswers()
	 * 
	 * @param questionnaireID
	 *                    int
	 */
	public Report(int questionnaireID) {
		Questionnaire tempQuestionnaire =
			(Questionnaire) DataAccess.retrieveQuestionnaire(questionnaireID);
		this.questionnaireID = questionnaireID;
		this.questionnaireIntroText = tempQuestionnaire.getIntroText();
		this.questionnaireName = tempQuestionnaire.getQuestionnaireName();
		getEvaluations(questionnaireID);
		findTypeOfInnerAnswers();

	}

	/**
	 * Method getEvaluations, this method runs through all evaluations for that
	 * questionnaire and takes out each of them and compares them with the ones
	 * already in the ArrayList usableEvaluations.
	 * 
	 * @param questionnaireID int
	 */
	public void getEvaluations(int questionnaireID) {
		allEvaluations = DataAccess.retrieveAllEvaluations(questionnaireID);
		int i = 0;
		if (allEvaluations.isEmpty() == false
			&& allEvaluations.get(i) instanceof Object) {
			for (i = 0; i < allEvaluations.size(); i++) {
				Evaluation o = (Evaluation) allEvaluations.get(i);
				for (int j = 0; j <= usableEvaluations.size(); j++) {
					if (usableEvaluations.size() == j) {
						usableEvaluations.add(o);
						break;
					} else {
						Evaluation evaluationObject =
							(Evaluation) usableEvaluations.get(j);
						if (evaluationObject
							.getUserName()
							.equals(o.getUserName())) {
							if (evaluationObject.getTimestamp()
								< o.getTimestamp()) {
								usableEvaluations.remove(j);
								usableEvaluations.add(o);
								break;
							} else {
								break;
							}
						}
					}
				}
			}
		}
	}

	/**
	 * The method is called after the evaluations are put into order, where it
	 * goes through each usable evaluation and finds out which type of answer
	 * it contains, which are send to their cyclemethod for their type.
	 * 
	 * Method findTypeOfInnerAnswers
	 */
	public void findTypeOfInnerAnswers() {
		ArrayList answers = new ArrayList();

		for (int i = 0; i < usableEvaluations.size(); i++) {
			Evaluation o = (Evaluation) usableEvaluations.get(i);
			answers = o.getAnswers();
			for (int j = 0; j < answers.size(); j++) {
				try {
					if (answers.get(j).toString().charAt(0) == 'M') {
						cycleMultipleChoices(j, i);
						System.out.println("multi sendt" + i);
					} else {
						cycleFreeTexts(j, i);
						System.out.println("freeText sendt  " + i);
					}
				} catch (Exception e) {
					System.err.println(e + "" + i);
				}
			}
		}
	}

	/**
	 * This method returns the size of the Arraylist that contains the
	 * references to the objects of the Class.
	 * 
	 * @return int
	 */
	public int getInnerFreeTextSize() {
		return innerQuestionFreeText.size();
	}

	/**
	 * The method returns the text that was in the intro in the used
	 * questionnaire
	 * 
	 * @return String
	 */
	public String getQuestionnaireIntroText() {
		return questionnaireIntroText;
	}

	/**
	 * The method returns the name for the questionnaire
	 * 
	 * @return String
	 */
	public String getQuestionnaireName() {
		return questionnaireName;
	}

	/**
	 * 
	 * The method returns the size of the Arraylist allEvaluations that
	 * contains the reference to all evaluations taken from the database
	 * 
	 * @return int
	 */
	public int getAllEvaluationsSize() {
		return allEvaluations.size();
	}

	/**
	 * The method returns the size of the Arraylist usableEvaluations which
	 * contains the references to the newest evaluations for each user
	 * 
	 * @return int
	 */
	public int getUsableEvaluationsSize() {
		return usableEvaluations.size();
	}

	/**
	 * The method return the ArrayList innerAnswerMultipleChoice which contains
	 * the references to the instances of InnerAnswerMultipleChoice in the
	 * report
	 * 
	 * @return ArrayList
	 */
	public ArrayList getInnerAnswerMultipleChoice() {
		return innerAnswerMultipleChoice;
	}

	/**
	 * The method return the size of the ArrayList
	 * 
	 * @return int
	 */
	public int getInnerAnswerMultipleChoiceSize() {
		return innerAnswerMultipleChoice.size();
	}

	/**
	 * Method getInnerAnswerMultipleChoiceQuestionText
	 * 
	 * @param j int
	 * @return String
	 */
	public String getInnerAnswerMultipleChoiceQuestionText(int j) {

		Report.InnerAnswerMultipleChoice multipleChoiceAnswer =
			(InnerAnswerMultipleChoice) innerAnswerMultipleChoice.get(j);
		return multipleChoiceAnswer.getInnerAnswerMultipleChoiceQuestionText();
	}

	/**
	 * The method returns a String Array for a specific
	 * InnerAnswerMultipleChoice, where the String contains the text for each
	 * choice posibility
	 * 
	 * @param j  int
	 * @return String[]
	 */
	public String[] getInnerAnswerMultipleChoiceText(int j) {

		Report.InnerAnswerMultipleChoice o =
			(InnerAnswerMultipleChoice) innerAnswerMultipleChoice.get(j);
		return o.getInnerAnswerMultipleChoiceText();
	}

	/**
	 * The method gets the instance of the type InnerAnswerMultipleChoice at
	 * the index j in the ArrayLisy innerAnswerMultipleChoice.
	 * 
	 * @param j int
	 * @return int[]
	 */
	public int[] getInnerAnswerMultipleChoiceDistribution(int j) {

		Report.InnerAnswerMultipleChoice o =
			(InnerAnswerMultipleChoice) innerAnswerMultipleChoice.get(j);
		return o.getInnerAnswerMultipleChoiceDistribution();
	}

	/**
	 * The method retrieves from the database and instantiate a tempAnswer from
	 * the evaluation evaluationNumber, where the tempAnswer is at the position
	 * answerNumber in the evaluations answers list. After that it cycles the
	 * InnerMultipleChoiceAnswers to find out if one of the same type is there
	 * and adds it's distribution to it or creates a new
	 * InnerMultipleChoiceAnswer if there isn't anyone of the same type. The
	 * type of the answer is questionID specific they are equal if they have
	 * the same questionID.
	 * 
	 * @param answerNumber int
	 * @param evaluationNumber int
	 */
	public void cycleMultipleChoices(int answerNumber, int evaluationNumber) {

		QuestionMultipleChoice tempQuestion = new QuestionMultipleChoice();
		AnswerMultipleChoice answer = new AnswerMultipleChoice();
		Evaluation tempEvaluation = new Evaluation();

		tempEvaluation = (Evaluation) usableEvaluations.get(evaluationNumber);
		ArrayList tempAnswers = tempEvaluation.getAnswers();

		try {
			answer =
				(AnswerMultipleChoice) DataAccess.retrieveAnswer(
					Integer.parseInt(
						tempAnswers.get(answerNumber).toString().substring(1)));
		} catch (ClassCastException e) {
			System.out.println(
				"Wrong answer type returned from database to answer" + e);
		}

		tempQuestion =
			(QuestionMultipleChoice) DataAccess.retrieveQuestion(
				answer.getQuestionID());
		String[] choices = tempQuestion.getChoice();
		int[] choiceDistribution = new int[choices.length];

		for (int i = 0; i <= innerAnswerMultipleChoice.size(); i++) {
			if (i == innerAnswerMultipleChoice.size()) {
				choiceDistribution[answer.getChoice()]++;
				new Report.InnerAnswerMultipleChoice(
					tempQuestion.getText(),
					tempQuestion.getChoice(),
					choiceDistribution,
					answer.getQuestionID());
			}
			InnerAnswerMultipleChoice tempInnerAnswerMultipleChoice =
				(InnerAnswerMultipleChoice) innerAnswerMultipleChoice.get(i);

			if (tempInnerAnswerMultipleChoice
				.getInnerAnswerMultipleChoiceQuestionID()
				== answer.getQuestionID()) {
				break;
			}
		}
	}

	/**
	 * This class contains all the values needed from the
	 * MultipleChoiceAnswers, like how the answers are distributed over each
	 * choice
	 */
	public class InnerAnswerMultipleChoice {
		/**
		 * Field questionText
		 */
		private String questionText;
		/**
		 * Field choiceText
		 */
		private String[] choiceText;
		/**
		 * Field choiceDistribution
		 */
		private int[] choiceDistribution;
		/**
		 * Field questionID
		 */
		private int questionID;

		/**
		 * This is the default constructor for InnerAnswerMultipleChoice
		 */
		public InnerAnswerMultipleChoice() {

		}

		/**
		 * This is the most used constructor for InnerAnswerMultipleChoice,
		 * which creates an instance of InnerAnswerMultipleChoice and adds it
		 * to the ArrayList innerAnswerMultipleChoice.
		 * 
		 * @param questionText String
		 * @param choiceText String[]
		 * @param choiceDistribution int[]
		 * @param questionID int
		 */
		public InnerAnswerMultipleChoice(
			String questionText,
			String[] choiceText,
			int[] choiceDistribution,
			int questionID) {
			this.questionText = questionText;
			this.choiceText = choiceText;
			this.choiceDistribution = choiceDistribution;
			this.questionID = questionID;
			innerAnswerMultipleChoice.add(this);
		}

		/**
		 * This method returns the questionText for it's respective instance of
		 * InnerAnswerMultipleChoice.
		 * 
		 * @return String
		 */
		public String getInnerAnswerMultipleChoiceQuestionText() {
			return questionText;
		}

		/**
		 * This method returns a String Array containing each individual text
		 * for each choice
		 * 
		 * @return String[]
		 */
		public String[] getInnerAnswerMultipleChoiceText() {
			return choiceText;
		}

		/**
		 * This method return an int Array of how many answers there is at each
		 * choice
		 * 
		 * @return int[]
		 */
		public int[] getInnerAnswerMultipleChoiceDistribution() {
			return choiceDistribution;
		}
		/**
		 * The method returns the questionID that this is the answer for.
		 * 
		 * @return int
		 */
		public int getInnerAnswerMultipleChoiceQuestionID() {
			return questionID;
		}

	}

	/**
	 * The method retrieves from the database and instantiate a tempAnswer from
	 * the evaluation evaluationNumber, where the tempAnswer is at the position
	 * answerNumber in the evaluations answers list. Then it cycles the
	 * InnerQuestionFreeText comparing if the question exist in the ArrayList
	 * innerQuestionFreeText, adding it if it doesn't with the respective
	 * answer or adds the answer if the question exist.
	 * 
	 * @param answerNumber int
	 * @param evaluationNumber int
	 */
	public void cycleFreeTexts(int answerNumber, int evaluationNumber) {
		AnswerFreeText tempAnswer = new AnswerFreeText();
		QuestionFreeText tempQuestion = new QuestionFreeText();

		Report.InnerQuestionFreeText innerQuestion =
			new Report.InnerQuestionFreeText();

		Evaluation tempEvaluation =
			(Evaluation) usableEvaluations.get(evaluationNumber);
		ArrayList answers = tempEvaluation.getAnswers();
		try {
			tempAnswer =
				(AnswerFreeText) DataAccess.retrieveAnswer(
					Integer.parseInt(
						answers.get(answerNumber).toString().substring(1)));
		} catch (ClassCastException e1) {
			System.err.println(
				"The wrong type of answer is returned from the database to tempAnswer   "
					+ e1);
		}

		tempQuestion =
			(QuestionFreeText) DataAccess.retrieveQuestion(
				tempAnswer.getQuestionID());

		tempEvaluation = (Evaluation) usableEvaluations.get(evaluationNumber);
		answers = tempEvaluation.getAnswers();

		for (int i = 0; i <= innerQuestionFreeText.size(); i++) {

			if (i == innerQuestionFreeText.size()) {
				try {
					innerQuestionFreeText.add(
						innerQuestion =
							(Report
								.InnerQuestionFreeText) new InnerQuestionFreeText(tempQuestion
								.getText(),
								tempAnswer.getQuestionID()));
				} catch (ClassCastException e) {
					System.err.println(
						"Wrong questiontype returned for innerQuestion  " + e);
				}
				innerQuestion.addInnerAnswersFreeText(
					tempEvaluation.getUserName(),
					tempEvaluation.getTimestamp(),
					tempAnswer.getFreeText());
				break;
			}
			Report.InnerQuestionFreeText testQuestion =
				(InnerQuestionFreeText) innerQuestionFreeText.get(i);

			if (tempAnswer.getQuestionID() == testQuestion.getQuestionID()) {
				innerQuestion.addInnerAnswersFreeText(
					tempEvaluation.getUserName(),
					tempEvaluation.getTimestamp(),
					tempAnswer.getFreeText());
			}

		}
	}
	/**
	 * this returns the number of answers for the Question at index i in the
	 * ArrayList innerQuestionFreeText.
	 * 
	 * @param i int
	 * @return int
	 */
	public int getInnerQuestionFreeTextSize(int i) {
		InnerQuestionFreeText tempQuestionFreeText =
			(InnerQuestionFreeText) innerQuestionFreeText.get(i);
		return tempQuestionFreeText.getInnerAnswerSize();
	}

	/**
	 * The method return the Question text for the instance of
	 * InnerQuestionFreeText
	 * 
	 * @param i int
	 * @return String
	 */
	public String getInnerQuestionFreeText(int i) {
		Report.InnerQuestionFreeText o =
			(Report.InnerQuestionFreeText) innerQuestionFreeText.get(i);
		return o.getInnerQuestionText();
	}

	/**
	 * 
	 * The method returns the number of answers to this instance of InnerQuestionFreeText.
	 * 
	 * @param number int
	 * @return int
	 */
	public int getInnerAnswerSize(int number) {
		ArrayList innerQuestionFreeTextArrayList = innerQuestionFreeText;

		InnerQuestionFreeText o =
			(InnerQuestionFreeText) innerQuestionFreeTextArrayList.get(number);
		return o.getInnerAnswerSize();
	}

	/**
	 * The method returns a String Array consisting of all the answers for that
	 * instanceOf InnerQuestionFreeText.
	 * 
	 * @param number int
	 * @return String[]
	 */
	public String[] getInnerAnswerText(int number) {
		ArrayList innerQuestionFreeTextArrayList = innerQuestionFreeText;

		InnerQuestionFreeText o =
			(InnerQuestionFreeText) innerQuestionFreeTextArrayList.get(number);
		for (int index = 0;
			index < innerQuestionFreeTextArrayList.size();
			index++)
			o =
				(
					Report
						.InnerQuestionFreeText) innerQuestionFreeTextArrayList
						.get(
					number);

		String[] freeTextAnswers = o.getAnswers();
		return freeTextAnswers;
	}

	/**
	 * The method returns a String Array consisting of all the users for that
	 * instanceOf InnerQuestionFreeText.
	 * 
	 * @param number int
	 * @return String[]
	 */
	public String[] getInnerUserText(int number) {
		ArrayList innerQuestionFreeTextArrayList = innerQuestionFreeText;

		InnerQuestionFreeText o =
			(InnerQuestionFreeText) innerQuestionFreeTextArrayList.get(number);
		for (int index = 0;
			index < innerQuestionFreeTextArrayList.size();
			index++)
			o =
				(
					Report
						.InnerQuestionFreeText) innerQuestionFreeTextArrayList
						.get(
					number);

		String[] freeTextUser = o.getUsers();
		return freeTextUser;
	}

	/**
	 */
	public class InnerQuestionFreeText {
		/**
		 * Field innerQuestionText
		 */
		private String innerQuestionText;
		/**
		 * Field questionID
		 */
		private int questionID;
		/**
		 * Field innerAnswersFreeText
		 */
		private ArrayList innerAnswersFreeText = new ArrayList();

		/**
		 * The default constructor for InnerQuestionFreeText
		 */
		public InnerQuestionFreeText() {
		}

		/**
		 * The Constructor creates an instance of InnerQuestionFreeText
		 * 
		 * @param innerQuestionText String
		 * @param questionID int
		 */
		public InnerQuestionFreeText(
			String innerQuestionText,
			int questionID) {
			this.innerQuestionText = innerQuestionText;
			this.questionID = questionID;
		}

		/**
		 * Method toString
		 * 
		 * @return String
		 */
		public String toString() {
			return ("\tinnerQuestionText: " + innerQuestionText);
		}

		/**
		 * The method instantiate and adds an answer to the instance of
		 * InnerQuestionFreeText's ArrayList innerAnswersFreeText.
		 * 
		 * @param userName String
		 * @param timestamp long
		 * @param answer String
		 */
		public void addInnerAnswersFreeText(
			String userName,
			long timestamp,
			String answer) {
			Report.InnerAnswerFreeText tempAnswer =
				new Report.InnerAnswerFreeText(userName, timestamp, answer);
			innerAnswersFreeText.add(tempAnswer);
		}

		/**
		 * The method returns the Question Text.
		 * 
		 * @return String
		 */
		public String getInnerQuestionText() {
			return innerQuestionText;
		}

		/**
		 * The method returns the number of answers in the ArrayList
		 * innerAnswersFreeText.
		 * 
		 * @return int
		 */
		public int getInnerAnswerSize() {
			return innerAnswersFreeText.size();
		}
		/**
		 * The method returns a String Array with the text for each answer, in the ArrayList innerAnswersFreeText for this instance of
		 * InnerQuestionFreeText.
		 * 
		 * @return String[]
		 */
		public String[] getAnswers() {
			String[] Answers;
			Answers = new String[innerAnswersFreeText.size()];
			for (int i = 0; i < innerAnswersFreeText.size(); i++) {
				Report.InnerAnswerFreeText tempAnswer =
					(InnerAnswerFreeText) innerAnswersFreeText.get(i);

				Answers[i] = tempAnswer.getAnswer();
			}
			return Answers;
		}

		/**
		 * The method returns a String Array with the username for each answer, in the ArrayList innerAnswersFreeText for this instance of
		 * InnerQuestionFreeText.
		 * @return String[]
		 */
		public String[] getUsers() {
			String[] Users;
			Users = new String[innerAnswersFreeText.size()];
			for (int i = 0; i < innerAnswersFreeText.size(); i++) {
				Report.InnerAnswerFreeText tempAnswer =
					(InnerAnswerFreeText) innerAnswersFreeText.get(i);

				Users[i] = tempAnswer.getUserName();
			}
			return Users;

		}

		/**
		 * The method returns the questionID
		 * 
		 * @return int
		 */
		public int getQuestionID() {
			return questionID;
		}
	}

	/**
	 */
	public class InnerAnswerFreeText {
		/**
		 * Field userName
		 */
		private String userName;
		/**
		 * Field timestamp
		 */
		private long timestamp;
		/**
		 * Field answer
		 */
		private String answer;

		/**
		 * The only constructor for InnerAnswerFreeText
		 * 
		 * @param userName String
		 * @param timestamp long
		 * @param answer String
		 */
		public InnerAnswerFreeText(
			String userName,
			long timestamp,
			String answer) {
			this.userName = userName;
			this.timestamp = timestamp;
			this.answer = answer;
		}

		/**
		 * The method returns the username for the person who wrote this answer.
		 * 
		 * @return String
		 */
		public String getUserName() {
			return userName;
		}
		/**
		 * The method returns the answer for the person who wrote this answer.
		 * 
		 * @return String
		 */
		public String getAnswer() {
			return answer;
		}
	}
}