/**
   * takes a query object and calls the appropriate sub component that answers the given query
   *
   * @param query the query that has to be answered
   * @return a string in the answer exchange format that will be sent to the frontend
   */
  public static String handleQuery(Query query) {
    // interval search
    String answer;
    if (query.x_Search == null) {
      // check if necessary fields are given
      if (query.i_Start == -1 || query.i_End == -1) {
        // query.response_format = "Wrong interval given";
        return "Wrong interval given";
      } else if (query.s_Chromosome == -1) {
        // query.response_format = "No chromosome given";
        return "No chromosome given";
      } else if (query.s_Source == -1) {
        // query.response_format = "No source given";
        return "No source given";
      }
      // correct query format
      else {
        // Send query to IndexController
        // Translation from query to intervalst.query
        // needs to be unified
        /*
        short s_SourceNo=(short)0;
        if (query.source.equals("dbSNP")) {
          				s_SourceNo = (short) 0;
          			}
          			if (query.source.equals("1000GenomesProject")){
          				s_SourceNo =(short) 1;
          			}
          			*/

        Query[] q_Query = {query};
        QueryAnswer temp_answer = indexController.answerQuery(q_Query);
        answer = answerQuery(temp_answer);

        /*
          		//	byte temp = query.chromosome.get();
          		//	byte[] b={temp};
          			//CRITICAL PART. change query format into intervallst.query . answerquery throws nullpointer
          			byte[] b=new byte[0];
          			byte[] c=new byte[0];
          			int i=query.position[0];
          			int j=query.position[1];
        IntervalST.Query intervalst_query=new IntervalST.Query(1,i,j,s_SourceNo,Integer.toString(query.chromosome).getBytes(),null,null);
        IntervalST.Query[] queries={intervalst_query};
        IntervalST.Answer x_Result=indexController.answerQuery(queries);
                    System.out.println("Length of AnswerList: "+x_Result.x_List.size());
                    if (query.hasDetail) {
                    	String sequence = Chromosome_reader.retrieve_sequence(i,j,Integer.toString(query.chromosome));
                    }
                    return query;
                    */
      }
    }
    // gene name search
    else {
      // test for prefix query
      if (query.b_isPrefix) {
        /*
        // This needs to be replaced!
        String[] genenames = GeneTranslator.completeGeneName(query.search);
        */
        String[] genenames = {"FOXP2", "FOXP4"};
        JSONObject obj = new JSONObject();
        obj.put("source", query.s_Source);
        obj.put("chromosome", query.s_Chromosome);
        JSONArray names = new JSONArray();
        for (int i = 0; i < genenames.length; i++) {
          names.add(genenames[i]);
        }
        obj.put("prefix", names);
        StringWriter out = new StringWriter();
        try {
          obj.writeJSONString(out);
        } catch (IOException e) {
          e.printStackTrace();
        }
        answer = out.toString();

      } else {
        if (query.x_Search == "getInitialSources") {
          System.out.println("getInitialSources");
          return null;
        } else {
          String[] interval = GeneTranslator.translateToIntervall(query.x_Search);
          JSONObject pos_obj = new JSONObject();
          JSONObject obj = new JSONObject();
          pos_obj.put("from", Integer.valueOf(interval[0]));
          pos_obj.put("to", Integer.valueOf(interval[1]));
          obj.put("search", query.x_Search);
          obj.put("position", pos_obj);

          StringWriter out = new StringWriter();
          try {
            obj.writeJSONString(out);
          } catch (IOException e) {
            e.printStackTrace();
          }
          answer = out.toString();
        }
      }
    }
    // queryID_pool.add(query.queryID);
    return answer;
  }
  /** @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */
  @SuppressWarnings("unchecked")
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    response.setContentType("application/json");
    response.setHeader("Cache-Control", "nocache");
    response.setCharacterEncoding("utf-8");
    PrintWriter out = response.getWriter();
    StringWriter result = new StringWriter();

    // get received JSON data from request
    BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
    String postData = "";
    if (br != null) {
      postData = br.readLine();
    }

    try {
      JSONObject json = (JSONObject) new JSONParser().parse(postData);
      JSONObject resultObj = new JSONObject();
      JSONArray list = new JSONArray();
      List<Tracking> trackingList = new ArrayList<Tracking>();

      // get the website list
      if (json.get("type").equals("websiteslist")) {
        trackingList = trackingDao.websiteList(pool);
        for (Tracking item : trackingList) {
          list.add(item.getWebsite());
        }
      }
      // render report
      else if (json.get("type").equals("submit")) {
        if (json.get("criteria").equals("date")) {
          // render repoty by date
          trackingList = trackingDao.getListByDate(pool, json.get("date").toString());
        } else if (json.get("criteria").equals("daterange")) {
          // render repoty by date range
          trackingList =
              trackingDao.getListByDateRange(
                  pool, json.get("fromdate").toString(), json.get("todate").toString());
        } else if (json.get("criteria").equals("website")) {
          // render repoty by website
          String website = (json.get("website") == null ? "" : json.get("website").toString());
          trackingList = trackingDao.getListByWebsite(pool, website);
        }

        for (Tracking item : trackingList) {
          JSONObject trackingObj = new JSONObject();
          trackingObj.put("date", item.getDate());
          trackingObj.put("website", item.getWebsite());
          trackingObj.put("visit", item.getVisit());
          list.add(trackingObj);
        }
      }
      resultObj.put("result", list);
      resultObj.writeJSONString(result);
      // finally output the json string
      out.print(result.toString());
    } catch (ParseException | SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  /**
   * parses an answer object into the json exchange format for an answer
   *
   * @param answer the answer object that should be translated
   * @return json string in the exchange format between frontend and middleware
   */
  public static String answerQuery(QueryAnswer answer) {
    JSONObject obj = new JSONObject();
    obj.put("source", answer.source);
    // add chromosome attribute to json answer
    obj.put("chromosome", answer.chromosome);
    JSONObject from_to = new JSONObject();
    from_to.put("from", answer.position[0]);
    from_to.put("to", answer.position[1]);
    obj.put("position", from_to);
    String response;
    if (answer.hasDetail) {
      JSONObject details = new JSONObject();
      details.put("refseq", answer.refseq);
      // create json_array for found mutations
      JSONArray mutations_array = new JSONArray();
      for (IntervalST.Mutation x : answer.mutations) {
        // json object for single mutation, that was found
        JSONObject mut = new JSONObject();

        // name of mutation, need to convert from byte array to string
        mut.put("name", new String(x.b_RefName));

        // json object for position of mutation's interval, with "to" and "from" as attributes
        JSONObject mut_pos = new JSONObject();
        mut_pos.put("from", x.i_Low);
        mut_pos.put("to", x.i_High);
        mut.put("position", mut_pos);

        // json object for metadata
        JSONObject meta = new JSONObject();

        // json object for gender
        JSONObject gender = new JSONObject();
        // -1 for no filter on gender, 0 for male and 1 for female
        if (x.s_Gender == -1) {
          gender.put("m", true);
          gender.put("w", true);
        } else if (x.s_Gender == 0) {
          gender.put("m", true);
          gender.put("w", false);
        } else if (x.s_Gender == 1) {
          gender.put("m", false);
          gender.put("w", true);
        } else {
          gender = null;
        }
        meta.put("gender", gender);

        // add country
        meta.put("origin", IndexController.getCountry(x.s_Country));

        // downloadtime
        meta.put("downloadtime", x.s_Date);

        // add metadata json object to mutation json object
        mut.put("metadata", meta);

        // add sequence of basis pairs, first need to convert integer to string
        if (answer.chromosome == 23) {
          mut.put("mutationseq", Chromosome_reader.retrieve_sequence(x.i_Low, x.i_High, "X"));
        } else if (answer.chromosome == 24) {
          mut.put("mutationseq", Chromosome_reader.retrieve_sequence(x.i_Low, x.i_High, "Y"));
        } else if (answer.chromosome == 25) {
          mut.put("mutationseq", Chromosome_reader.retrieve_sequence(x.i_Low, x.i_High, "MT"));
        } else {
          mut.put(
              "mutationseq",
              Chromosome_reader.retrieve_sequence(x.i_Low, x.i_High, answer.chromosome.toString()));
        }
        // add json object for mutation x to json array for all mutations that were found
        mutations_array.add(mut);
      }
      details.put("mutations", mutations_array);
      obj.put("details", details);
      StringWriter out = new StringWriter();
      try {
        obj.writeJSONString(out);
      } catch (IOException e) {
        e.printStackTrace();
      }
      response = out.toString();

    } else {
      obj.put("details", null);
      // function to count occurrences of mutations in subintervals
      Integer[] counts = count_mutations(answer);
      JSONArray mutation_counts = new JSONArray();
      for (int i = 0; i < counts.length; i++) {
        mutation_counts.add(counts[i]);
      }
      obj.put("graph", mutation_counts);
      StringWriter out = new StringWriter();
      try {
        obj.writeJSONString(out);
      } catch (IOException e) {
        e.printStackTrace();
      }
      response = out.toString();
    }
    if (response != null) {
      return response;
    } else {
      return "Something went wrong while creating answer";
    }
  }