package analyzer;


import analyzer.models.Hashtag;
import analyzer.models.Round;
import analyzer.models.User;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

/**
 * This class reads the server logs, creates objects and organizes them into data structures.
 * An instance of this class must run cooperatively with an instance of class ClientLogParser
 */
public class ServerLogParser {

    private static long startRoundTime = 0;

    public static volatile int serverRoundNo = 0;
    public static volatile boolean DONE = false;
    public static volatile List<Integer> roundLineCounters = new ArrayList<>();
    public static volatile int serverLineCounter = 0;
    public static volatile int lineTotal = 0;

    public static volatile Map<Long, User> users = new Hashtable<>(Analyzer.clientNo, 1);
    public static volatile Map<Integer, Round> rounds = new Hashtable<>(1000);
    public static volatile Map<String, Hashtag> hashtags = new Hashtable<>(Analyzer.clientNo);

    public static void run() throws IOException {
        parse();
    }

    private static void traceUser() {
        //parseUserID(path);
    }

    private static void countLines() throws IOException {
        FileReader fr = new FileReader(Analyzer.serverLogPath);
        BufferedReader br= new BufferedReader(fr);
        while(br.readLine() != null) {
            lineTotal++;
        }
        br.close();
    }

    private static void parse() throws IOException {
        countLines();
        FileReader fr = new FileReader(Analyzer.serverLogPath);
        BufferedReader br= new BufferedReader(fr);
        String line;
        int roundLinesCount = 0;
        while((line = br.readLine()) != null) {
            serverLineCounter++;
            roundLinesCount++;
            String[] elements = line.trim().split("\t");//timestamp user_id hashtags
            long timestamp = Long.parseLong(elements[0]);
            //get log start time
            if(serverLineCounter == 1){
                startRoundTime = timestamp;
                serverRoundNo = 1;
            }
            //next round
            if(timestamp > startRoundTime + Analyzer.roundLength - 50) {
                startRoundTime = timestamp;
                roundLineCounters.add(roundLinesCount - 1);
                serverRoundNo++;
                roundLinesCount = 1;
            }
            parseData(elements, serverRoundNo);

            int progress =  (int) (((float) serverLineCounter /(float) lineTotal) * 100F);
            System.out.print("\r");
            System.out.print(progress + " %");
        }
        roundLineCounters.add(roundLinesCount);
        System.out.println();
        System.out.println("No of Rounds " + serverRoundNo);
        System.out.println(users.size() + " users found");
        System.out.println(hashtags.size() + " hashtags found");
        //printOut();
        System.out.println();
        br.close();
        DONE = true;
    }

    private static void parseData(String[] elements, int onRound) {

        Round r = rounds.get(onRound);
        if(r == null) {
            r = new Round(onRound);
            rounds.put(onRound, r);
        }

        long id = Long.parseLong(elements[1]);
        User u = users.get(id);
        if(u == null) {
            u = new User(id);
            users.put(id, u);
        }

        String[] hashtagNames = elements[2].split(" ");
        Hashtag[] parsedHashtags = new Hashtag[hashtagNames.length];
        for(int i = 0; i < hashtagNames.length; i++) {
            parsedHashtags[i] = hashtags.get(hashtagNames[i]);
            if(parsedHashtags[i] == null) {
                parsedHashtags[i] = new Hashtag(hashtagNames[i]);
                hashtags.put(hashtagNames[i], parsedHashtags[i]);
            }
        }

        r.addUser(u);
        u.addRound(r);
        for(Hashtag h : parsedHashtags) {
            r.addHashtag(h);
            u.addHashtag(h);
            h.addUser(u);
            h.addRound(r);
        }
    }

    private static void printOut() {
        System.out.println("Users with hashtag " + Analyzer.toTraceHashtag + ": ");
        System.out.println("user_id\t\t" + "hashtags\t\t" + "rounds\t\t" + "total" );
        for(User u: users.values()) {
            System.out.print(u.getId() + "\t");
            System.out.print(u.hashtagsToString());
            System.out.print("\t" + u.getRounds());
            System.out.println("\t" + u.totalPosts());
        }
    }
}