@RequestMapping(value = "/grids/{id}")
  public String getGrid(@PathVariable("id") int id, Model model) {
    model.addAttribute("pageTitle", "Lista Grids");
    this.setActiveButton(1, model);
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String email = auth.getName(); // get logged in username
    Practitioner p = this.practitionerService.getPractitionerByEmail(email);
    List<Project> projects = this.practitionerService.getProjectsForPractitioner(p);
    Grid tempGrid = null;
    String chart = "";
    try {
      tempGrid = this.gridService.getGridById(id);
      if (projects.contains(tempGrid.getProject())) {
        chart = createChart(tempGrid);
        model.addAttribute("grid", tempGrid);
        model.addAttribute("gridTreeString", chart);

      } else {
        model.addAttribute("error", "You cannot acces to this grid");
      }
    } catch (Exception e) {
      model.addAttribute("error", "Grid not found");
    }
    return "grids";
  }
 private String createChart(Grid g) {
   if (g.getMainGoals().size() != 0) {
     List<Object> stack = new ArrayList<Object>();
     stack.addAll(g.getMainGoals());
     String chart =
         "chart_config = {chart: { connectors: {type: \"bCurve\",style: {\"stroke-width\": 2}}, container: \"#gridChart\", siblingSeparation:70, rootOrientation:'WEST',  subTeeSeparation:70, animateOnInit: true,node: {collapsable: true, HTMLclass: 'nodeExample1'},animation: {nodeAnimation: \"easeOutBounce\",nodeSpeed: 500,connectorsAnimation: \"bounce\",connectorsSpeed: 700}},";
     chart =
         chart
             + "nodeStructure: {HTMLclass: 'project',innerHTML:\"<div class='nodeTxt'><div class='txtProjectTitle'>"
             + g.getProject().getProjectId()
             + "</div><div class='txtElement'>"
             + g.getProject().getDescription()
             + "</div></div>\",children: [";
     chart = chart + updateChart(stack) + "]}};";
     return chart;
   } else {
     JSONObject jsonObject = new JSONObject();
     jsonObject.put("msg", "error");
     jsonObject.put("resp", "grid main goal error");
     return jsonObject.toString();
   }
 }
  @RequestMapping(value = "/grids/add", method = RequestMethod.POST)
  public @ResponseBody String addGrid(@RequestBody String jsonData) {
    Grid temp;
    try {
      temp = aFactory.loadFromJson(jsonData, this.projectService);
      if (temp == null) {
        logger.info("in blocco null");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "error");
        jsonObject.put("msg", "Wrong format");
        return jsonObject.toString();
      }
      Grid latest = this.gridService.getLatestGrid(temp.getProject().getId());
      if (latest == null) {
        this.gridService.addGrid(temp);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "success");
        jsonObject.put("msg", "Grid successfully uploaded");
        Firebase myFirebaseRef = new Firebase("https://fiery-torch-6050.firebaseio.com/");
        myFirebaseRef.child("ISSSR/" + temp.getProject().getProjectId()).setValue("timestamp");

        return jsonObject.toString();
      } else {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "error");
        jsonObject.put("msg", "Already exists a gird for this project");
        return jsonObject.toString();
      }
    } catch (Exception e) {
      e.printStackTrace();
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("type", "error");
      jsonObject.put("msg", "Generic exception");
      return jsonObject.toString();
    }
  }
  @RequestMapping(value = "/MGResolution/{pid}/{gid}", method = RequestMethod.GET)
  public String mainGoalResolution(
      @PathVariable("gid") int gid, @PathVariable("pid") int pid, Model model) {
    model.addAttribute("pageTitle", "Lista Grids");
    this.setActiveButton(2, model);
    Grid working = this.gridService.getLatestWorkingGrid(pid);
    Grid current = this.gridService.getGridById(gid);
    List<String> mergedGoalLabels = new ArrayList<String>();
    if (working == null) {
      model.addAttribute("error", "The working Grid is not available");
    } else if (current == null) {
      model.addAttribute("error", "The requested Grid is not available");
    } else if ((!current.isMainGoalsChanged())) {
      model.addAttribute("error", "The requested Grid is not in pending state");
    } else {
      String workingMGList = "['" + pid + "', '" + current.getId() + "', ";
      List<Goal> temp = working.getMainGoals();
      for (int i = 0; i < temp.size(); i++) {
        if (!mergedGoalLabels.contains(temp.get(i).getLabel())) {
          mergedGoalLabels.add(temp.get(i).getLabel());
        }
        if (i < temp.size() - 1) {
          workingMGList = workingMGList + "'" + temp.get(i).getLabel() + "',";
        } else {
          workingMGList = workingMGList + "'" + temp.get(i).getLabel() + "'";
        }
      }
      workingMGList = workingMGList + "]";

      String currentMGList = "['" + pid + "', '" + current.getId() + "', ";
      temp = current.getMainGoals();
      for (int i = 0; i < temp.size(); i++) {
        if (!mergedGoalLabels.contains(temp.get(i).getLabel())) {
          mergedGoalLabels.add(temp.get(i).getLabel());
        }
        if (i < temp.size() - 1) {
          currentMGList = currentMGList + "'" + temp.get(i).getLabel() + "',";
        } else {
          currentMGList = currentMGList + "'" + temp.get(i).getLabel() + "'";
        }
      }
      currentMGList = currentMGList + "]";
      model.addAttribute("mergedGoalLabels", mergedGoalLabels);
      model.addAttribute("workingGrid", working);
      model.addAttribute("currentGrid", current);
      model.addAttribute("workingMGList", workingMGList);
      model.addAttribute("currentMGList", currentMGList);
      model.addAttribute("GEService", this.gridElementService);
    }
    return "MGResolution";
  }
  @RequestMapping(value = "/projects/{id}")
  public String getProject(@PathVariable("id") int id, Model model) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String email = auth.getName(); // get logged in username
    Practitioner p = this.practitionerService.getPractitionerByEmail(email);
    Project temp = null;
    try {
      temp = this.projectService.getProjectById(id);
      List<Practitioner> practs = this.gridService.getInvolvedPractitioners(id, true);
      if (practs.contains(p)) {
        model.addAttribute("reqproject", temp);
        List<Grid> templist = this.gridService.getGridLog(id);
        model.addAttribute("nProjectGrids", templist.size());
        model.addAttribute("listProjectGrids", templist);
        Map<String, String> status = new HashMap<String, String>();
        for (Grid g : templist) {
          Grid tempWorking = this.gridService.getLatestWorkingGrid(g.getProject().getId());
          String state = "";
          if (g.isMainGoalsChanged()) {
            state = state + "MGC";
            if (g.obtainGridState() == Grid.GridState.UPDATING) {
              state = state + "-UPDATING";
            }
          } else {
            if (g.obtainGridState() == Grid.GridState.WORKING) {
              if (g.getVersion() < tempWorking.getVersion()) {
                state = state + "ARCHIVED";
              } else {
                state = state + g.obtainGridState().name();
              }
            } else {
              state = state + g.obtainGridState().name();
            }
          }
          status.put(g.getId() + "", state);
        }
        model.addAttribute("status", status);
      } else {
        model.addAttribute("error", "You cannot access to this project");
      }
    } catch (Exception e) {
      model.addAttribute("error", "The requested project is not available");
    }

    return "projects";
  }
  @RequestMapping(value = "/grids", method = RequestMethod.GET)
  public String listAllGrids(Model model) {
    model.addAttribute("pageTitle", "Lista Grids");
    this.setActiveButton(1, model);
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String email = auth.getName(); // get logged in username
    Practitioner p = this.practitionerService.getPractitionerByEmail(email);
    List<Project> projects = this.practitionerService.getProjectsForPractitioner(p);
    List<Grid> temp = new ArrayList<Grid>();
    Map<String, String> status = new HashMap<String, String>();
    for (Project current : projects) {
      List<Grid> temp2 = this.gridService.getGridLog(current.getId());
      for (Grid g : temp2) {
        Grid tempWorking = this.gridService.getLatestWorkingGrid(g.getProject().getId());
        String state = "";
        if (g.isMainGoalsChanged()) {
          state = state + "MGC";
          if (g.obtainGridState() == Grid.GridState.UPDATING) {
            state = state + "-UPDATING";
          }
        } else {
          if (g.obtainGridState() == Grid.GridState.WORKING) {
            if (g.getVersion() < tempWorking.getVersion()) {
              state = state + "ARCHIVED";
            } else {
              state = state + g.obtainGridState().name();
            }
          } else {
            state = state + g.obtainGridState().name();
          }
        }

        status.put(g.getId() + "", state);
      }
      temp.addAll(temp2);
    }
    if (temp.size() > 0) {
      model.addAttribute("listGrids", temp);
      model.addAttribute("status", status);

    } else {
      model.addAttribute("error", "No grids available");
    }
    return "grids";
  }
  @RequestMapping(value = "/MGListUpdate", method = RequestMethod.POST)
  public @ResponseBody String updateMainGoalList(@RequestBody String jsonData) {
    System.out.println(jsonData);
    // Array format: [projId, gridSolved, {MaingoalList}]
    JSONArray jsonArray = new JSONArray(jsonData);
    int prjId = 0;
    int gridToSolveId = 0;
    List<Goal> mainGoalList = new ArrayList<Goal>();
    for (int i = 0; i < jsonArray.length(); i++) {
      if (i == 0) prjId = Integer.parseInt(jsonArray.getString(i));
      else if (i == 1) {
        gridToSolveId = Integer.parseInt(jsonArray.getString(i));
      } else {
        Goal current =
            (Goal) this.gridElementService.getLatestWorking(jsonArray.getString(i), "Goal");
        if (current != null && !mainGoalList.contains(current)) {
          mainGoalList.add(current);
        } else if (current == null) {
          JSONObject jsonObject = new JSONObject();
          jsonObject.put("type", "error");
          jsonObject.put("msg", "Cannot get working element with label: " + jsonArray.getString(i));
          // System.out.println("error, cannot get working element with label: "+
          // jsonArray.getString(i));
          return jsonObject.toString();
        }
      }
    }
    Grid workingGrid = this.gridService.getLatestWorkingGrid(prjId);
    Grid gridToSolve = this.gridService.getGridById(gridToSolveId);
    if (workingGrid == null) {
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("type", "error");
      jsonObject.put("msg", "Cannot get latest working grid for project: " + prjId);
      // System.out.println("error, cannot get latest working grid for project: "+ prjId);
      return jsonObject.toString();
    } else if (gridToSolve == null) {
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("type", "error");
      jsonObject.put("msg", "error, cannot get grid with id: " + gridToSolveId);
      System.out.println("error, cannot get grid with id: " + gridToSolveId);
      return jsonObject.toString();
    } else if ((!gridToSolve.isMainGoalsChanged())) {
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("type", "error");
      jsonObject.put("msg", "grid with id: " + gridToSolveId + " has been already solved");
      System.out.println("error, cannot get grid with id: " + gridToSolveId);
      return jsonObject.toString();
    } else if (mainGoalList.size() == 0) {
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("type", "error");
      jsonObject.put("msg", "Main goal list can't be empty");
      System.out.println("error, Main goal list can't be empty");
      return jsonObject.toString();
    } else {
      boolean solvable = true;
      for (Goal ge : mainGoalList) {
        if (solvable) {
          List<GridElement> pending =
              this.gridElementService.getElementByLabelAndState(
                  ge.getLabel(), "Goal", GridElement.State.MAJOR_CONFLICTING);
          pending.addAll(
              this.gridElementService.getElementByLabelAndState(
                  ge.getLabel(), "Goal", GridElement.State.MAJOR_UPDATING));
          pending.addAll(
              this.gridElementService.getElementByLabelAndState(
                  ge.getLabel(), "Goal", GridElement.State.MINOR_CONFLICTING));
          if (pending.size() > 0) {
            solvable = false;
          }
          if (solvable) {
            if (this.gridModificationService.isEmbeddedPending(ge)) solvable = false;
          }
        }
      }
      if (solvable) {
        for (GridElement ge : mainGoalList) {
          System.out.println(ge.getLabel() + "-" + ge.getVersion() + "-" + ge.getState());
        }
        Grid newGrid = workingGrid.clone();
        newGrid.setVersion(this.gridService.getLatestGrid(prjId).getVersion() + 1);
        newGrid.setMainGoals(mainGoalList);
        newGrid = this.gridModificationService.refreshLinks(newGrid);
        this.gridService.addGrid(newGrid);
        gridToSolve.setMainGoalsChanged(false);
        this.gridService.updateGrid(gridToSolve);
        this.gridModificationService.sendJSONToPhases(gridToSolve);
        this.gridModificationService.sendNewGridVersionNotification(newGrid);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "success");
        jsonObject.put("msg", "Main goal list updated");
        return jsonObject.toString();

      } else {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "error");
        jsonObject.put("msg", "Other pending elements to solve before");
        return jsonObject.toString();
      }
    }
  }
  @RequestMapping(
      value = "/resolutionDashBoard",
      method =
          RequestMethod
              .GET) // stati WORKING, MAJOR_UPDATING,MAJOR_CONFLICTING, MINOR_CONFLICTING, FINAL_KO
  public String resolutionDashBoardView(Model model) {
    model.addAttribute("pageTitle", "Grids Versioning System");
    this.setActiveButton(2, model);
    List<String> pendingLabels = new ArrayList<String>();
    int nPendingChanges = 0;
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String email = auth.getName(); // get logged in username
    Practitioner p = this.practitionerService.getPractitionerByEmail(email);

    List<Project> projList = this.practitionerService.getProjectsForPractitioner(p);

    List<Project> projPending = new ArrayList<Project>();
    Map<String, List<Grid>> projectPendingGrids = new HashMap<>(); // map projid, list pending grids
    Map<String, List<GridElement>> projectGridsMajorPendingElements = new HashMap<>();
    Map<String, List<GridElement>> projectGridsMajorConflictElements = new HashMap<>();
    Map<String, List<GridElement>> projectGridsMinorConflictElements = new HashMap<>();
    Map<String, String> projectGridsMainGoalListChanged = new HashMap<>();
    if (projList.size() > 0) {
      for (int i = 0; i < projList.size(); i++) {
        List<Grid> projGrids = this.gridService.getGridLog(projList.get(i).getId());
        List<Grid> gridPending = new ArrayList<Grid>();
        boolean addedGrid = false;
        for (Grid g : projGrids) {
          if (g.isMainGoalsChanged()) {
            addedGrid = true;
            String temp = projList.get(i).getId() + "-" + g.getId();
            projectGridsMainGoalListChanged.put(temp, "changed");
            gridPending.add(g);
          }
          if (g.obtainGridState() == Grid.GridState.UPDATING) {
            addedGrid = true;
            HashMap<String, GridElement> elements = g.obtainAllEmbeddedElements();
            Set<String> keySet = elements.keySet();
            Iterator<String> anIterator = keySet.iterator();
            boolean addedMPElement = false;
            boolean addedMCElement = false;
            boolean addedmCElement = false;
            List<GridElement> majpendingElements = new ArrayList<GridElement>();
            List<GridElement> majconflElements = new ArrayList<GridElement>();
            List<GridElement> minconflElements = new ArrayList<GridElement>();
            while (anIterator.hasNext()) {
              String key = anIterator.next();
              State aState = elements.get(key).getState();
              if (aState == GridElement.State.MAJOR_CONFLICTING) {
                majconflElements.add(elements.get(key));
                addedMCElement = true;
              }
              if (aState == GridElement.State.MAJOR_UPDATING) {
                majpendingElements.add(elements.get(key));
                addedMPElement = true;
              }
              if (aState == GridElement.State.MINOR_CONFLICTING) {
                minconflElements.add(elements.get(key));
                addedmCElement = true;
              }
            }
            String temp = projList.get(i).getId() + "-" + g.getId();
            if (addedMCElement || addedMPElement || addedmCElement) {
              addedGrid = true;
              if (!g.isMainGoalsChanged()) gridPending.add(g);
            }
            if (addedMCElement) {
              projectGridsMajorConflictElements.put(temp, majconflElements);
            }
            if (addedMPElement) {
              projectGridsMajorPendingElements.put(temp, majpendingElements);
            }
            if (addedmCElement) {
              projectGridsMinorConflictElements.put(temp, minconflElements);
            }
          }
        }
        if (addedGrid) {
          projPending.add(projList.get(i));
          projectPendingGrids.put(projList.get(i).getId() + "", gridPending);
        }
      }
    }

    System.out.println(projectPendingGrids.toString());

    model.addAttribute("PendingProjects", projPending);
    model.addAttribute("PendingProjectsGrids", projectPendingGrids);
    model.addAttribute("MajorPendingProjectsGridsElements", projectGridsMajorPendingElements);
    model.addAttribute("MajorConflictProjectsGridsElements", projectGridsMajorConflictElements);
    model.addAttribute("MinorConflictProjectsGridsElements", projectGridsMinorConflictElements);
    model.addAttribute("GridsMainGoalListChanged", projectGridsMainGoalListChanged);
    model.addAttribute("GridModificationServiceInstance", this.gridModificationService);
    model.addAttribute("GridElementServiceInstance", this.gridElementService);
    model.addAttribute("DefaultResponsibleServiceInstance", this.defaultResponsibleService);
    model.addAttribute("Practitioner", p);
    return "resolutionDashBoard";
  }