package analyzer;

import analyzer.models.Client;
import analyzer.models.Group;
import analyzer.models.Round;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Grouping {

    private static List<Client> clients;
    private static List<Round> rounds;
    private static List<Group> groups;

    private static final int threshold = 20;
    private static final int learningRounds = 20;

    public static void main(String[] args) throws InterruptedException {
        Analyzer a = new Analyzer();
        clients = new ArrayList<>();
        groups = new ArrayList<>();
        rounds = new ArrayList<>(ServerLogParser.rounds.values());
        rounds.sort(Comparator.comparingInt(Round::getNo));
        rounds = rounds.subList(0, learningRounds);
        run();
    }

    public static void run(){
        System.out.println("threshold: " + threshold);
        System.out.println("learningRounds: " + learningRounds);
        for(int i = 1; i <ServerLogParser.rounds.values().size(); i++) {
            Round r = ServerLogParser.rounds.get(i);
            rounds.add(r);
            ClientLogParser.clients.values().forEach(c -> {
                if(c.getRounds().containsKey(r))
                    if(c.getTotalPosts() >= 100 && !clients.contains(c))
                        clients.add(c);
            });
            if(i >= learningRounds) {
                group(i);
                int progress =  (int) (((float) i /(float) ServerLogParser.rounds.values().size()) * 100F);
                System.out.print("\r");
                System.out.print(progress + " %");
            }
        }
        System.out.println();
        System.out.println("Group no: " + groups.size());
        int ungrouped = 0;
        for (Client c : clients) {
            if(c.getGroup() == null)
                ungrouped++;
        }
        System.out.println("ungrouped: " + ungrouped);
        int sumSize = 0;
        for(Group g : groups) {
            sumSize += g.clients().size();
            System.out.print(g.clients().size() + ",");
        }
        System.out.println();
        System.out.println("Avg Size of Groups: " + sumSize/groups.size());
        System.out.println("Avg No of Cover Messages: " + coverMessagesCount()/(clients.size() - ungrouped));
    }

    private static void group(int currentRound) {
        for(Client c1 : clients) {
            for(Client c2 : clients) {
                if(c1.equals(c2) || c2.getGroup() != null)
                    continue;
                else {
                    int distance = euclideanDistance(c1, c2, currentRound);
                    Group group = c1.getGroup();
                    if(group == null && distance < threshold) {
                        group = new Group(0);
                        group.addClient(c1);
                        group.addClient(c2);
                        groups.add(group);
                    }
                    else {
                        if(group != null && suitable(c2, group, currentRound))
                            group.addClient(c2);
                    }
                }
            }
        }
    }

    private static boolean suitable(Client client, Group group, int currentRound) {
        int sum = 0;
        for(Client c : group.clients()) {
            if(euclideanDistance(c, client, currentRound) >= threshold)
                return false;
        }
        return true;
    }

    private static int coverMessagesCount() {
        int sum = 0;
        for(Group g : groups) {
            for(Client c : g.clients())
                for(Round r : ServerLogParser.rounds.values()) {
                    Integer value1 = g.getRounds().get(r);
                    Integer value2 = c.getRounds().get(r);
                    if(value1 == null)
                        value1 = 0;
                    if(value2 == null)
                        value2 = 0;
                    int diff = value1 - value2;
                    sum += diff;
                }
        }
        return sum;
    }

    private static int euclideanDistance(Client c1, Client c2, int currentRound) {
        int sum = 0;
        List<Round> subset = rounds.subList(currentRound - learningRounds, currentRound + 1);

        for(Round r : subset) {
            Integer value1 = c1.getRounds().get(r);
            Integer value2 = c2.getRounds().get(r);
            if(value1 == null)
                value1 = 0;
            if(value2 == null)
                value2 = 0;
            int diff = Math.abs(value1 - value2);
            sum += diff;
        }
        return sum;
    }
}
