package edu.ucsd.cse124;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Random;
import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Comparator;

public class TwitterHandler implements Twitter.Iface {
    protected Map<String,Account> accounts;
    protected Random rnd;
    public TwitterHandler() {
        this.rnd = new Random();
        this.accounts = new HashMap<String, Account>();
    }


    @Override
    public void ping() {
    }

    @Override
    public void createUser(String handle) throws AlreadyExistsException
    {
        if(accounts.containsKey(handle)){
            throw new AlreadyExistsException(handle);
        }
        accounts.put(handle, new Account(handle));
    }

    @Override
    public void subscribe(String handle, String theirhandle)
        throws NoSuchUserException
    {
        if(!accounts.containsKey(handle)) {
            throw new NoSuchUserException(handle);
        }

        if (!accounts.containsKey(theirhandle)) {
            throw new NoSuchUserException(theirhandle);
        }

        Account target = accounts.get(handle);
        if(!target.check_subscribed_accounts(theirhandle)){
            target.add_to_subscribed_accounts(theirhandle);
        }


    }

    @Override
    public void unsubscribe(String handle, String theirhandle)
        throws NoSuchUserException
    {
        if(!accounts.containsKey(handle)) {
            throw new NoSuchUserException(handle);
        }

        if (!accounts.containsKey(theirhandle)) {
            throw new NoSuchUserException(theirhandle);
        }

        Account target = accounts.get(handle);
        if(target.check_subscribed_accounts(theirhandle)){
            target.remove_to_subscribed_accounts(theirhandle);
        }
    }

    @Override
    public void post(String handle, String tweetString)
        throws NoSuchUserException, TweetTooLongException
    {
        if (tweetString.length() > 140) {
            throw new TweetTooLongException();
        }

        if(!accounts.containsKey(handle)){
            throw new NoSuchUserException(handle);
        }

        Account target = accounts.get(handle);

        Tweet new_tweet = new Tweet(
            (long)rnd.nextInt(Integer.MAX_VALUE),
            handle,
            System.currentTimeMillis(),
            0,
            tweetString
        );

        target.push_to_tweet_list(new_tweet);
    }

    @Override
    public List<Tweet> readTweetsByUser(String handle, int howmany)
        throws NoSuchUserException
    {
        if(!accounts.containsKey(handle)){
            throw new NoSuchUserException(handle);
        }
        Account target = accounts.get(handle);
        ArrayList<Tweet> alist = target.getTweetArrayList();
        List<Tweet>  output = new ArrayList<Tweet>(); 
        for(int i = alist.size()-1; i >= 0 && i >= (alist.size() - howmany); --i){
            output.add(alist.get(i));
        }
        return output;
    }

    //self-defined comparator for Tweet class
    public static Comparator<Tweet> timestanpComparator = new Comparator<Tweet>(){
        @Override
        public int compare(Tweet c1, Tweet c2) {
            return (int) (c1.posted - c2.posted);
        }
    };

    @Override
    public List<Tweet> readTweetsBySubscription(String handle, int howmany)
        throws NoSuchUserException
    {   
        if(!accounts.containsKey(handle)){
            throw new NoSuchUserException(handle);
        }
        Account target = accounts.get(handle);
        ArrayList<String> tarlist = target.get_subscribed_accounts();

        PriorityQueue<Tweet> priorityQ = new PriorityQueue<Tweet>(howmany, timestanpComparator);

        LinkedList<Tweet>  output = new LinkedList<Tweet>(); 
        ArrayList<Tweet> alist;

        Tweet tw;
        int count = 0;

        for(int j = 0; j < tarlist.size(); ++j){
            alist = accounts.get(tarlist.get(j)).getTweetArrayList();
            for(int i = alist.size()-1; i >= 0 && i >= (alist.size()-howmany); --i){
                tw = alist.get(i);
                if(count < howmany){
                    count++;
                    priorityQ.add(tw);
                }
                else{
                    if( timestanpComparator.compare(tw, priorityQ.peek()) > 0 ){
                        priorityQ.poll();
                        priorityQ.add(tw);
                    }
                }
            }
        }

        for(int i = priorityQ.size() - 1; i >= 0; --i){
            Tweet temp = priorityQ.poll();
            System.out.println(temp);

            output.addFirst(temp);            
        }

        return output;
    }

    @Override
    public void star(String handle, long tweetId) throws
        NoSuchUserException, NoSuchTweetException
    {
        if(!accounts.containsKey(handle)){
            throw new NoSuchUserException(handle);
        }

        Account target = accounts.get(handle);
        target.favoriting_tweet(tweetId);

    }
}

@@ -2859,32 +2859,108 @@
 yList%3CTweet%3E(); 
+%0A%0A        //collect the last %3Chowmany%3E tweets from the list in reverse order
 %0A        for(int
@@ -3721,24 +3721,104 @@
 ccounts();%0A%0A
+        //matain a minimum heap to keep tracking on the latest %3Chowmany%3E tweets%0A
         Prio
@@ -4040,16 +4040,57 @@
 t = 0;%0A%0A
+        //traverse user's following_list%0A
         
@@ -4192,32 +4192,99 @@
 eetArrayList();%0A
+            //Only process the last %3Chowmany%3E entries in each list%0A
             for(
@@ -4423,16 +4423,69 @@
 owmany)%7B
+//If the heap size is smaller than %3Chowmany%3E, add it.
 %0A       
@@ -4555,32 +4555,269 @@
               %7D%0A
+                //If the heap size equals %3Chowmany%3E, then compare the new node with the top node.%0A                //If the new node is greater than the top node, pop out the top node and%0A                //add the new node into the heap.%0A
                 
@@ -5044,32 +5044,66 @@
     %7D%0A        %7D%0A
+        //collect the output list.
 %0A        for(int

add some comments