import Exceptions.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Comparator;
public class SocialNetwork implements SocialNetworkInterface {
/* TYPICAL ELEMENT: <followers, posts>
*
* FUNZIONE DI ASTRAZIONE: <followers, posts> dove:
* followers(Map<String, Set<String>> rappresenta l'insieme delle persone che seguono l'autore (key)
* posts(Set<Post> rappresenta l'insieme dei post inseriti nella rete sociale
*
* INVARIANTE DI RAPPRESENTAZIONE:
* followers != null && posts != null && forall(p,x).(p e x appartengono a posts) ==> p.id != x.id
*/
protected Map<String, Set<String>> followers;
protected Set<Post> posts;
public SocialNetwork(){
this.followers = new HashMap<>();
this.posts = new TreeSet<>();
}
//Questo metodo restituisce la rete sociale derivata dalla lista di post (parametro del metodo)
public Map<String, Set<String>> guessFollowers(List<Post> ps) throws NullPointerException{
if(ps==null) throw new NullPointerException("La lista non può essere null");
for(Post p : ps){
if(p==null) continue;
try{
addpost(p);
// oppure addpost(new Post(p.getId(), p.getAuthor(), p.getText()));
// ho scelto di memorizzare nella rete sociale solo il puntatore per
// aggiornare il numero di likes direttamente nella lista immessa come parametro.
}
catch(NullPointerException | Sameindexception e){
e.printStackTrace();
}
}
return followers;
}
//Questo metodo restiutisce una lista degli utenti in ordine decrescente in base
//al numero di like ricevuti. Sono esclusi gli utenti che non hanno ottenuto nessun like
public List<String> influencers(Map<String, Set<String>> followers) throws NullPointerException{
if(followers==null) throw new NullPointerException("La rete sociale non può essere null");
Map<String, Integer> follownumber = new HashMap<>();
for(Map.Entry<String, Set<String>> entry : followers.entrySet()){
if(!entry.getValue().isEmpty()){
follownumber.put(entry.getKey(), entry.getValue().size());
}
}
List<Map.Entry<String, Integer>> templist = new ArrayList<>(follownumber.entrySet());
templist.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));
List<String> influencerslist = new ArrayList<>();
for(Map.Entry<String, Integer> entry : templist){
influencerslist.add(entry.getKey());
}
return influencerslist;
}
//Questo metodo restituisce l'insieme degli utenti menzionati nella rete sociale, ovvero gli autori
//dei post e gli utenti che hanno messo almeno un like ai post nella rete sociale
public Set<String> getMentionedUsers(){
Set<String> MentionedUsers = new TreeSet<>();
for(Map.Entry<String, Set<String>> entry : followers.entrySet()){
MentionedUsers.add(entry.getKey());
if(!entry.getValue().isEmpty()){
MentionedUsers.addAll(entry.getValue());
}
}
return MentionedUsers;
}
//Questo metodo restituisce l'insieme degli utenti menzionati nella lista parametro del metodo, ovvero
// gli autori dei post e gli utenti che hanno messo almeno un like ai post nella lista
public Set<String> getMentionedUsers(List<Post> ps) throws NullPointerException{
if(ps==null) throw new NullPointerException("La lista in ingresso non può essere null");
Set<String> MentionedUsers = new TreeSet<>();
for(Post p : ps){
if(p==null) continue;
MentionedUsers.add(p.getAuthor());
if(p.Likenumber() > 0){
Set<String> likeslist = p.getLikeslist();
MentionedUsers.addAll(likeslist);
}
}
return MentionedUsers;
}
//Questo metodo restituisce la lista dei post effettuati dall'utente (parametro del metodo)
//nella rete sociale
public List<Post> writtenBy(String username) throws Missinguserexception, NullPointerException{
if(username == null) throw new NullPointerException("Il campo username non può essere null");
int found = 0;
List<Post> writtenbyauthor = new ArrayList<>();
for(Post p : posts){
if(p.getAuthor().equals(username)){
writtenbyauthor.add(p);
found = 1;
}
}
if(found == 0) throw new Missinguserexception("Non esiste nessun Post pubblicato da questo utente");
return writtenbyauthor;
}
//Questo metodo restituisce la lista dei post effettuati dall'utente (paramentro del metodo)
//nella lista parametro del metodo
public List<Post> writtenBy(List<Post> ps, String username) throws Missinguserexception,
NullPointerException{
if(username == null) throw new NullPointerException("Il campo username non può essere null");
if(ps == null) throw new NullPointerException("La lista ps non può essere null");
int found = 0;
List<Post> writtenbyauthor = new ArrayList<>();
for(Post p : ps){
if(p == null) continue;
if(p.getAuthor().equals(username)){
writtenbyauthor.add(p);
found = 1;
}
}
if(found == 0) throw new Missinguserexception("Non esiste nessun Post pubblicato da questo utente");
return writtenbyauthor;
}
//Questo metodo restituisce una lista dei post che contengono una delle parole presenti nella
//lista parametro del metodo. La ricerca non è case-sensitive
public List<Post> containing(List<String> words) throws Missingwordexception, NullPointerException{
if(words == null) throw new NullPointerException("La lista words non può essere null");
int found = 0;
List<Post> foundedposts = new ArrayList<>();
for(Post p : posts){
for(String word : words){
if(word == null || word.isEmpty()) continue;
if(p.getText().toLowerCase().contains(word.toLowerCase())){
found = 1;
foundedposts.add(p);
}
}
}
if(found == 0) throw new Missingwordexception("Non esiste nessun Post che contenga queste parole");
return foundedposts;
}
//Questo metodo inserisce il post parametro del metodo all'interno della rete sociale
// solo se non è già presente un post con lo stesso ID.
public void addpost(Post p) throws Sameindexception, NullPointerException{
if(p == null) throw new NullPointerException("Il post non può essere null");
for(Post ptemp : posts) {
if (ptemp.getId() == p.getId()) throw new Sameindexception("Esiste già un post con questo ID");
}
posts.add(p);
//Se l'autore non è presente nella rete sociale, lo aggiungo
if(!followers.containsKey(p.getAuthor())) {
Set<String> temp = new TreeSet<>();
followers.put(p.getAuthor(), temp);
}
//Se il post ha almeno un like, inserisco nella rete sociale gli utenti che hanno messo like
if(p.Likenumber() > 0){
Set<String> tempfollowers = followers.get(p.getAuthor());
Set<String> templikes = p.getLikeslist();
for(String s : templikes){
tempfollowers.add(s);
if(!followers.containsKey(s)){
Set<String> temp = new TreeSet<>();
followers.put(s, temp);
}
}
}
}
//Questo metodo permette di aggiungere un like ad un post (tramite il suo ID) all'interno della
//rete sociale. Inserisce inoltre l'utente (parametro del metodo) nella rete sociale
public void addPostlike(int id, String user) throws Missingindexception, IllegalArgumentException {
if(user==null) throw new IllegalArgumentException("Il campo user non può essere null");
int found = 0;
for (Post p : posts) {
if (p.getId() == id) {
found = 1;
try {
p.addLike(user);
} catch (IllegalArgumentException | Sameuserexception e) {
e.printStackTrace();
break;
}
Set<String> temp = followers.get(p.getAuthor());
temp.add(user);
if(!followers.containsKey(user)){
Set<String> tempfollowers = new TreeSet<>();
followers.put(user, tempfollowers);
}
}
} if(found == 0) throw new Missingindexception("Non esiste nessun Post con questo ID");
}
//Questo metodo stampa i post all'interno della rete sociale
public void printPosts(){
if(posts.isEmpty()) System.out.println("Rete sociale vuota.");
else{
for(Post p : posts)
System.out.println(p.tostring());
}
}
}