/**
   * Checks whether the user has access to the specified billing account by id.
   *
   * @param billingAccountId the billing account id
   * @return true if has access, false otherwise
   * @throws Exception if any error
   * @since 1.6
   */
  private boolean canAccessBillingAccount(long billingAccountId) throws Exception {
    final List<ProjectData> billingProjects = getBillingProjects();

    // 1) check billing accounts the user has direct permission
    for (ProjectData bp : billingProjects) {
      if (bp.getProjectId() == billingAccountId) {
        return true;
      }
    }

    GroupSearchCriteria groupSearchCriteria = new GroupSearchCriteria();
    groupSearchCriteria.setUserId(DirectUtils.getTCSubjectFromSession().getUserId());

    List<Group> userGroups = getGroupService().search(groupSearchCriteria, 0, 0).getValues();

    // 2) check security groups the user has permission with
    for (Group g : userGroups) {
      for (BillingAccount ba : g.getBillingAccounts()) {
        if (ba.getId() == billingAccountId) {
          return true;
        }
      }
    }

    return false;
  }
  /**
   * Executes the action.
   *
   * <p>Create the project based on the input parameters.
   *
   * <p>Validation: not present, already completely done by the annotations in the setters.
   *
   * <p>
   *
   * @throws IllegalStateException if the project service facade is not set.
   * @throws Exception if any other error occurs
   * @see ProjectServiceFacade#createProject(com.topcoder.security.TCSubject, ProjectData)
   */
  protected void executeAction() throws Exception {
    ProjectServiceFacade projectServiceFacade = getProjectServiceFacade();

    if (null == projectServiceFacade) {
      throw new IllegalStateException("The project service facade is not initialized");
    }

    // create the project data with the input parameters.
    ProjectData projectData = new ProjectData();
    projectData.setName(getProjectName());
    projectData.setDescription(getProjectDescription());

    // delegate to ProjectServiceFacade to create the project.
    projectData =
        projectServiceFacade.createProject(
            DirectStrutsActionsHelper.getTCSubjectFromSession(), projectData);

    setResult(projectData);
  }
  /**
   * Create a draft copilot contest for the new created Presentation Project.
   *
   * @param projectData the new created Presentation Project.
   * @throws Exception if any error occurs.
   */
  private void createPPTCopilotDraftPosting(ProjectData projectData) throws Exception {
    setTcDirectProjectId(projectData.getProjectId());
    Date startDate = new Date();
    startDate.setTime(new Date().getTime() + COPILOT_CONTEST_START_DATE_LAG);
    GregorianCalendar gc = new GregorianCalendar();
    gc.setTimeInMillis(startDate.getTime());
    DatatypeFactory df = DatatypeFactory.newInstance();
    getAssetDTO().setProductionDate(df.newXMLGregorianCalendar(gc));

    super.executeAction();
  }
  /**
   * Creates draft copilot posting for the newly created project.
   *
   * @param directProject the direct project.
   * @return the created competition
   * @throws Exception if error happens when creating the contest.
   * @since 1.1
   */
  private SoftwareCompetition createCopilotDraftPosting(ProjectData directProject)
      throws Exception {
    SoftwareCompetition cp = new SoftwareCompetition();
    cp.setAssetDTO(getAssetDTOForNewSoftware());

    String name = getAssetDTO().getName();
    if (name == null || name.equals("")) {
      name = directProject.getName();
    }
    cp.getAssetDTO().setName(name);

    GregorianCalendar c = new GregorianCalendar();
    c.setTime(new Date());
    c.add(Calendar.DAY_OF_MONTH, 2);
    XMLGregorianCalendar contestStartDate =
        DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
    cp.getAssetDTO().setProductionDate(contestStartDate);

    // build the project header
    Project projectHeader = new Project();
    ProjectCategory projectCategory = new ProjectCategory();
    projectCategory.setId(29);
    projectCategory.setName("Copilot Posting");
    projectCategory.setProjectType(ProjectType.APPLICATION);
    projectHeader.setProjectCategory(projectCategory);
    projectHeader.setId(-1L);
    if (projectData.getProjectBillingAccountId() > 0) {
      projectHeader.setProperty(
          ProjectPropertyType.BILLING_PROJECT_PROJECT_PROPERTY_KEY,
          String.valueOf(projectData.getProjectBillingAccountId()));
    } else {
      projectHeader.setProperty(ProjectPropertyType.BILLING_PROJECT_PROJECT_PROPERTY_KEY, "0");
    }
    projectHeader.setProperty("Confidentiality Type", "public");
    projectHeader.setProperty("Copilot Cost", "0");
    projectHeader.setProperty("Project Name", name);
    projectHeader.setTcDirectProjectId(directProject.getProjectId());
    projectHeader.setTcDirectProjectName(directProject.getName());

    // set spec info - do not need spec review
    ProjectSpec projectSpec = new ProjectSpec();
    projectSpec.setProjectSpecId(0L);
    if (getProjectHeader() != null && getProjectHeader().getProjectSpec() != null) {
      projectSpec.setDetailedRequirements(
          getProjectHeader().getProjectSpec().getDetailedRequirements());
    }
    projectHeader.setProjectSpec(projectSpec);

    // add prize
    List<Prize> prizes = new ArrayList<Prize>();
    Prize firstPlace = new Prize();
    firstPlace.setNumberOfSubmissions(1);
    firstPlace.setPlace(1);
    firstPlace.setPrizeAmount(150);
    firstPlace.setProjectId(directProject.getProjectId());

    Prize secondPlace = new Prize();
    secondPlace.setNumberOfSubmissions(1);
    secondPlace.setPlace(2);
    secondPlace.setPrizeAmount(75);
    secondPlace.setProjectId(directProject.getProjectId());

    com.topcoder.management.project.PrizeType prizeType =
        new com.topcoder.management.project.PrizeType();
    prizeType.setDescription("Contest Prize");
    prizeType.setId(15L);

    firstPlace.setPrizeType(prizeType);
    prizes.add(firstPlace);
    secondPlace.setPrizeType(prizeType);
    prizes.add(secondPlace);

    projectHeader.setPrizes(prizes);
    projectHeader.setProperty(ProjectPropertyType.ADMIN_FEE_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.COPILOT_COST_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.DR_POINTS_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.PAYMENTS_PROJECT_PROPERTY_KEY, "150");
    projectHeader.setProperty(ProjectPropertyType.FIRST_PLACE_COST_PROJECT_PROPERTY_KEY, "150");
    projectHeader.setProperty(ProjectPropertyType.RELIABILITY_BONUS_COST_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.CHECKPOINT_BONUS_COST_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.SPEC_REVIEW_COSTS_PROJECT_PROPERTY_KEY, "0");
    projectHeader.setProperty(ProjectPropertyType.SECOND_PLACE_COST_PROJECT_PROPERTY_KEY, "75");
    projectHeader.setProperty(ProjectPropertyType.REVIEW_COSTS_PROJECT_PROPERTY_KEY, "0");

    cp.setId(-1L);
    cp.setProjectHeader(projectHeader);

    initializeCompetition(cp);
    populateCompetition(cp);

    cp =
        getContestServiceFacade()
            .createSoftwareContest(
                DirectUtils.getTCSubjectFromSession(),
                cp,
                directProject.getProjectId(),
                null,
                null);

    return cp;
  }
  /**
   * The main logic to create the new project and assign permissions to the new project.
   *
   * @throws Exception if there is any error.
   */
  @Override
  protected void executeAction() throws Exception {
    TCSubject currentUser = DirectStrutsActionsHelper.getTCSubjectFromSession();

    Map<String, String> result = new HashMap<String, String>();

    // create new project first
    ProjectServiceFacade projectServiceFacade = getProjectServiceFacade();

    if (null == projectServiceFacade) {
      throw new IllegalStateException("The project service facade is not initialized");
    }

    // create the project data with the input parameters.
    ProjectData projectData = new ProjectData();
    projectData.setName(getProjectName());
    projectData.setDescription(getProjectDescription());
    // prepare the project answer.
    for (ProjectAnswer answer : getProjectData().getProjectAnswers()) {
      if (answer.getOptionAnswers() != null) {
        for (ProjectAnswerOption answerOption : answer.getOptionAnswers()) {
          answerOption.setProjectAnswer(answer);
        }
      }
      // replace XWorkList by ArrayList.
      if (answer.getMultipleAnswers() != null) {
        List<String> s = new ArrayList<String>();
        for (String mAnswer : answer.getMultipleAnswers()) {
          s.add(mAnswer);
        }
        answer.setMultipleAnswers(s);
      }
    }
    projectData.setProjectAnswers(getProjectData().getProjectAnswers());

    // set project billing account id if exists
    if (getProjectData().getProjectBillingAccountId() > 0) {

      // check if user has access to the billing account
      if (!canAccessBillingAccount(getProjectData().getProjectBillingAccountId())) {
        throw new IllegalArgumentException(
            "You don't have permission to access the billing account you set");
      }
      projectData.setProjectBillingAccountId(getProjectData().getProjectBillingAccountId());
    }

    if (forums != null) {
      Map<String, String> forumsMap = new HashMap<String, String>();
      for (ProjectForumTemplateDTO forum : forums) {
        forumsMap.put(forum.getForumName(), forum.getForumDescription());
      }
      // delegate to ProjectServiceFacade to create the project.
      projectData =
          projectServiceFacade.createTCDirectProject(
              currentUser, projectData, getPermissions(), forumsMap);
    } else {
      // delegate to ProjectServiceFacade to create the project.
      projectData =
          projectServiceFacade.createTCDirectProject(currentUser, projectData, getPermissions());
    }

    if (getProjectData().getProjectBillingAccountId() > 0) {
      DirectUtils.updateDirectProjectBugContestFee(
          DirectUtils.getTCSubjectFromSession(),
          projectData.getProjectId(),
          getProjectServiceFacade(),
          getProjectContestFeeService(),
          getProjectContestFeePercentageService());
    }

    // put data into result
    result.put("projectName", projectData.getName());
    result.put("projectId", String.valueOf(projectData.getProjectId()));

    if (!isCreateCopilotPosting()) {
      // check whether has copilots to add
      if (getCopilotIds() != null && getCopilotIds().length > 0) {
        // add the copilot into the new project
        List<CopilotProject> copilotProjects = new ArrayList<CopilotProject>();
        List<Boolean> removeFlags = new ArrayList<Boolean>();

        for (long id : getCopilotIds()) {
          removeFlags.add(false);

          CopilotProject copilotProject = new CopilotProject();
          copilotProject.setTcDirectProjectId(projectData.getProjectId());
          copilotProject.setCopilotProfileId(id);
          copilotProject.setId(0);
          copilotProjects.add(copilotProject);
        }

        // update copilots projects
        getContestServiceFacade().updateCopilotProjects(currentUser, copilotProjects, removeFlags);
      }

      if (presentationProject) {
        // create the draft copilot contest
        createPPTCopilotDraftPosting(projectData);
        // create JIRA issue
        Map<String, Object> conetstResult = (Map<String, Object>) getResult();
        String description =
            "Copilot Opportunities: " + copilotURLPrefix + conetstResult.get("projectId");
        JiraRpcServiceWrapper.createIssue(
            pptJIRAProject, pptJIRAIssueTypeId, projectName, description, pptJIRAIssueReporter);
      }
    } else {
      createCopilotDraftPosting(projectData);
    }

    setResult(result);
  }