private FamilyMember get(int id, FamilyMember defaultMember) throws MemeberExistsException {
   for (FamilyMember m : members) {
     if (m != null && m.getHf().getId() == id)
       throw new MemeberExistsException(m, defaultMember);
   }
   return defaultMember;
 }
 public float getWidth() {
   float widthDown;
   if (father != null)
     widthDown = (float) father.children().mapToDouble(FamilyMember::getWidthDown).sum();
   else if (mother != null)
     widthDown = (float) father.children().mapToDouble(FamilyMember::getWidthDown).sum();
   else widthDown = getWidthDown();
   return Math.max(widthDown, getWidthUp());
 }
 public void layoutDown() {
   float off = offset;
   for (FamilyMember c : children().collect(Collectors.toList())) {
     c.offset = off;
     c.layoutDown();
     off += c.getWidthDown();
   }
   if (spouse == null) {
     x = offset + (getWidthDown() - 1) / 2;
   } else {
     x = offset - 0.5f + (getWidthDown() - 1) / 2;
     spouse.x = offset + 0.5f + (getWidthDown() - 1) / 2;
   }
 }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      if (convertView == null) {
        convertView =
            getActivity().getLayoutInflater().inflate(R.layout.list_item_family_member, null);
      }

      FamilyMember f = getItem(position);

      TextView nameTextView =
          (TextView) convertView.findViewById(R.id.family_member_list_item_nameTextView);
      nameTextView.setText(f.getFirstName() + " " + f.getLastName());

      return convertView;
    }
 private void analyzeSpouse(FamilyMember m) {
   HistoricalFigure spouse = m.hf.getHfLink("spouse");
   if (spouse.getId() != -1) {
     FamilyMember m2;
     try {
       m2 = get(spouse.getId(), new FamilyMember(spouse, m.generation, m.distance + 1));
       if (!m2.getRelation().equals("")) {
         m.spouse = m2;
         m2.spouse = m;
         links.add(new FamilyLink("spouse", m, m2));
         addMember(m2, m);
       }
     } catch (MemeberExistsException e) {
     }
   }
 }
    public void layout() {
      float widthDown;
      if (father != null)
        widthDown = (float) father.children().mapToDouble(FamilyMember::getWidthDown).sum();
      else if (mother != null)
        widthDown = (float) father.children().mapToDouble(FamilyMember::getWidthDown).sum();
      else widthDown = getWidthDown();

      float diff = (getWidthUp() - widthDown) / 2f;

      if (diff > 0) offset = diff;
      else offset = 0;

      if (father != null) {
        float off = offset;
        for (FamilyMember m : father.children().collect(Collectors.toList())) {
          m.offset = off;
          m.layoutDown();
          off += m.getWidthDown();
        }

      } else layoutDown();

      if (getWidthUp() < widthDown) offset = Math.max(0, x - (getWidthUp() - 1) / 2);
      else offset = 0;

      layoutUp();
    }
 private void analyzeChildren(FamilyMember m) {
   List<HistoricalFigure> children = m.hf.getHfLinks("child");
   for (HistoricalFigure c : children) {
     FamilyMember m3;
     try {
       m3 = get(c.getId(), new FamilyMember(c, m.generation + 1, m.distance + 1));
       if (!m3.getRelation().equals("")) {
         m.children.add(m3);
         links.add(new FamilyLink("child", m, m3));
         m3.strongLink = true;
         addMember(m3);
         analyzeSpouse(m3);
         analyzeChildren(m3);
       }
     } catch (MemeberExistsException e) {
     }
   }
 }
    private void analyzeBites(FamilyMember m) {
      if (members.contains(m)) return;
      members.add(m);

      World.getHistoricalEvents()
          .stream()
          .collect(
              Filters.filterEvent(
                  HfDoesInteractionEvent.class,
                  e ->
                      e.getDoerHfId() == m.hf.getId()
                          && e.getInteraction().startsWith(interaction)))
          .map(HfDoesInteractionEvent::getTargetHfId)
          .map(World::getHistoricalFigure)
          .forEach(
              hf -> {
                FamilyMember m2 = new FamilyMember(hf, m.getGeneration() + 1, m.getDistance() + 1);
                m2.father = m;
                m.children.add(m2);
                links.add(new FamilyLink("child", m, m2));
                analyzeBites(m2);
              });
    }
    private void analyzeParents(FamilyMember m) {
      HistoricalFigure father = m.hf.getHfLink("father");
      FamilyMember m1 = null, m2 = null;
      if (father.getId() != -1) {
        try {
          m1 = get(father.getId(), new FamilyMember(father, m.generation - 1, m.distance + 1));
          if (!m1.getRelation().equals("")) {
            m.father = m1;
            analyzeParents(m1);
            addMember(m1);

            if (m.generation == 0) analyzeChildren(m1);
          } else {
            m1 = null;
          }
        } catch (MemeberExistsException e) {
        }
      }
      HistoricalFigure mother = m.hf.getHfLink("mother");
      if (mother.getId() != -1) {
        try {
          m2 = get(mother.getId(), new FamilyMember(mother, m.generation - 1, m.distance + 1));
          if (!m2.getRelation().equals("")) {
            m.mother = m2;
            analyzeParents(m2);
            addMember(m2);
          } else {
            m2 = null;
          }
        } catch (MemeberExistsException e) {
        }
      }
      if (m1 != null && m2 != null) {
        m1.spouse = m2;
        m2.spouse = m1;
        links.add(new FamilyLink("spouse", m1, m2));
      }
      if (m1 != null) {
        links.add(new FamilyLink("child", m1, m));
        m1.children.add(m);
      }
      if (m2 != null) {
        links.add(new FamilyLink("child", m2, m));
        m2.children.add(m);
      }
    }
    public Family(HistoricalFigure hf, boolean curse) {
      this.curse = curse;

      FamilyMember m = new FamilyMember(hf, 0, 0);
      root = m;

      if (!curse) {
        members.add(m);
        analyzeFamily();
      } else {
        analyzeCurse();
      }

      root.layout();
    }
 public void layoutUp() {
   float off = offset;
   if (father != null) {
     father.offset = off;
     father.layoutUp();
     off += father.getWidthUp();
   }
   if (mother != null) {
     mother.offset = off;
     mother.layoutUp();
     off += mother.getWidthUp();
   }
   if (generation != 0) x = offset + (getWidthUp() - 1) / 2;
 }
 @Override
 public int hashCode() {
   return Math.max(m1.hashCode(), m2.hashCode()) << 16 + Math.min(m1.hashCode(), m2.hashCode());
 }
 public float getWidthUp() {
   return Math.max(
       1,
       (father != null ? father.getWidthUp() : 0) + (mother != null ? mother.getWidthUp() : 0));
 }