private boolean parseEvenLineOfMetaInfo(
     String line, Task task, List<String> errorMessages, int lineNumber, TestGroup group) {
   String[] testIndexes = line.split(" ");
   List<Integer> testsCases = new LinkedList<Integer>();
   for (String index : testIndexes) {
     try {
       int test = Integer.parseInt(index);
       if (test <= 0 || test > task.getNumberOfTests()) {
         addMessageOnLine(
             errorMessages,
             lineNumber,
             "Incorrect index " + index + " must be between 1 and " + task.getNumberOfTests());
         return false;
       }
       testsCases.add(test);
     } catch (NumberFormatException e) {
       addMessageOnLine(errorMessages, lineNumber, "Index " + index + " is not a number.");
       return false;
     }
   }
   if (testsCases.isEmpty()) {
     addMessageOnLine(errorMessages, lineNumber, "Cannot create a test group with no test cases.");
     return false;
   }
   group.setTestCases(testsCases);
   return true;
 }
  protected String parseZipEntry(
      ZipEntry zipEntry,
      ZipInputStream zipStream,
      Task task,
      String contestId,
      ContestManager contestManager) {
    String fileName = new File(zipEntry.getName()).getName().toLowerCase();
    if (fileName.equals(task.getName() + ".txt")) {
      return null;
    }

    String[] fileNameParts = fileName.split("\\.");

    if (fileNameParts.length != 3) {
      return getErrorMessage(zipEntry, "is not named properly and will be ignored.");
    }
    if (!fileNameParts[0].equals(task.getName())) {
      return getErrorMessage(
          zipEntry,
          "seems like a test case but does not seem to start with the task name:" + task.getName());
    }
    Task.TestType testType;
    if ("in".equals(fileNameParts[2])) {
      testType = Task.TestType.IN;
    } else if ("sol".equals(fileNameParts[2])) {
      testType = Task.TestType.SOL;
    } else {
      return getErrorMessage(
          zipEntry, " is neither .in nor .sol file but is ." + fileNameParts[2] + " ?");
    }

    int testNumber = -1;
    try {
      testNumber = Integer.parseInt(fileNameParts[1]);
      if (testNumber < 1 || testNumber > task.getNumberOfTests()) {
        testNumber = -1;
      }
    } catch (NumberFormatException e) {
    } finally {
      if (testNumber < 0) {
        return getErrorMessage(
            zipEntry,
            " has incorrect value for a test number :"
                + fileNameParts[1]
                + " . Must be an integer between 1 and "
                + Integer.toString(task.getNumberOfTests()));
      }
    }

    if (contestManager.uploadTaskData(contestId, task, testNumber, testType, zipStream)) {
      return null;
    } else {
      return getErrorMessage(
          zipEntry, " was recognized as a test data file but the server was unable to store it.");
    }
  }
 private void setUpDefaultMetaInfo(Task task, ContestManager contestManager, String contestId) {
   task.setTestGroups(new LinkedList<TestGroup>());
   for (int i = 1; i <= task.getNumberOfTests(); ++i) {
     TestGroup group = new TestGroup();
     group.setFeedbackEnabled(i * 5 <= task.getNumberOfTests());
     group.setTestCases(Arrays.asList(i));
     group.setPoints(new BigDecimal(100 / task.getNumberOfTests()));
     task.addTestGroup(group);
   }
   contestManager.updateTask(contestId, task);
 }
  @SuppressWarnings("unchecked")
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    ServletFileUpload servletFileUpload = setUpServletFileUpload();
    ContestManager contestManager = SessionUtil.getInstance().getContestManager();

    List<FileItem> fileItemsList = null;
    try {
      fileItemsList = servletFileUpload.parseRequest(request);
    } catch (FileUploadException e) {
      setError(
          request,
          response,
          "File upload did not finish successfully.  Or you might be using an unsupported browser.");
      return;
    }

    InputStream inputStream = null;
    Map<String, String> fieldValues = new HashMap<String, String>();
    for (FileItem fileItem : fileItemsList) {
      if (fileItem.isFormField()) {
        fieldValues.put(fileItem.getFieldName(), fileItem.getString());
      } else {
        inputStream = fileItem.getInputStream();
        break;
      }
    }
    if (inputStream == null) {
      setError(request, response, "No file seems to be uploaded.");
      return;
    }
    Task task = getTastInfo(fieldValues, contestManager);
    if (task == null) {
      setError(request, response, "Error reading task infomation.");
      return;
    }
    try {
      List<String> messages =
          unzipStream(
              request, response, inputStream, task, contestManager, fieldValues.get("contestId"));
      request.getSession().setAttribute("messages", messages);
    } finally {
      try {
        inputStream.close();
      } catch (IOException e) {
      }
    }
    response.sendRedirect(
        "editTask?contestId=" + fieldValues.get("contestId") + "&taskId=" + task.getId());
  }
  List<String> unzipStream(
      HttpServletRequest request,
      HttpServletResponse response,
      InputStream inputStream,
      Task task,
      ContestManager contestManager,
      String contestId) {
    LinkedList<String> errorMessages = new LinkedList<String>();

    boolean foundMetaInfo = false;
    ZipInputStream zipStream = new ZipInputStream(inputStream);
    ZipEntry zipEntry = null;
    try {
      while ((zipEntry = zipStream.getNextEntry()) != null) {
        if (zipEntry.isDirectory()) continue;
        System.out.println("Unzipping " + zipEntry.getName());
        if (handleMetaInfo(zipEntry, task, zipStream, errorMessages, contestManager, contestId)) {
          if (foundMetaInfo) {
            errorMessages.add(
                "Found more than one file named "
                    + task.getName()
                    + ".txt . Will be using + "
                    + zipEntry.getName());
          }
          foundMetaInfo = true;
        } else {
          String message = parseZipEntry(zipEntry, zipStream, task, contestId, contestManager);
          if (message != null) {
            errorMessages.add(message);
          }
        }
      }
    } catch (IOException e) {
      errorMessages.add("Could not read next entry from zip file");
    }
    if (!foundMetaInfo) {
      errorMessages.add(
          "Could not find valid file named "
              + task.getName()
              + ".txt . Will use default settings - all test cases form separate test groups and the first 20% of the test groups will be feedback enabled.");
      setUpDefaultMetaInfo(task, contestManager, contestId);
    }
    return errorMessages;
  }
  private boolean handleMetaInfo(
      ZipEntry zipEntry,
      Task task,
      ZipInputStream zipStream,
      List<String> errorMessages,
      ContestManager contestManager,
      String contestId) {
    String fileName = new File(zipEntry.getName()).getName().toLowerCase();
    if (!fileName.equals(task.getName() + ".txt")) return false;

    List<TestGroup> testGroups = new LinkedList<TestGroup>();
    BufferedReader reader = new BufferedReader(new InputStreamReader(zipStream));
    String line = null;
    int lineNumber = 0;
    try {
      while ((line = reader.readLine()) != null) {
        String secondLine = reader.readLine();
        lineNumber += 2;
        if (secondLine == null) {
          if ("".equals(line)) {
            break;
          } else {
            addMessageOnLine(errorMessages, lineNumber, "Line appears to be empty.");
            return false;
          }
        }

        TestGroup group = new TestGroup();
        if (!parseOddLineOfMetaInfo(errorMessages, line, lineNumber, group)
            || !parseEvenLineOfMetaInfo(secondLine, task, errorMessages, lineNumber, group)) {
          return false;
        }
        testGroups.add(group);
      }
    } catch (IOException e) {
      addMessageOnLine(errorMessages, lineNumber, "Cannot read the file after this line.");
      return false;
    }
    task.setTestGroups(testGroups);
    contestManager.updateTask(contestId, task);

    return true;
  }