package userfinder;

import com.sun.deploy.util.StringUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;

public class FindUserByGroups {
    private static final int USERS_PEER_PAGE = 1000;
    private final static String SORT_TYPE = "id_desc";
    private static int TOTAL_ITERATIONS_COUNT;
    private static int totalIterationsCount = 0;
    private static int GROUPS_COUNT = 0;
    private static List<String> AllIDs = new ArrayList<>();
    private static int percent = -1;

    public static void main(String[] args) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("List the each public links at new line or public IDs separated by commas: ");
        StringBuilder ids = new StringBuilder(reader.readLine());
        while (ids.indexOf("\u0020") != -1)
            ids.deleteCharAt(ids.indexOf("\u0020"));
        String publicIDs[];
        if (ids.indexOf("vk.com") != -1) {
            ArrayList<String> links = new ArrayList<>();
            while (true) {
                StringBuilder read = new StringBuilder(reader.readLine());
                while (read.indexOf("\u0020") != -1)
                    read.deleteCharAt(read.indexOf("\u0020"));
                if (read.toString().isEmpty())
                    break;
                links.add(read.substring(read.indexOf("vk.com/") + 7, read.length()));
            }
            links.add(ids.substring(ids.indexOf("vk.com/") + 7, ids.length()));
            publicIDs = new String[links.size()];
            for (int i = 0; i < publicIDs.length; i++) {
                publicIDs[i] = links.get(i);
            }
        } else {
            String[] idsSplitted = StringUtils.splitString(ids.toString(), "\u002c");
            publicIDs = new String[idsSplitted.length];
            for (int i = 0; i < idsSplitted.length; i++) {
                try {
                    if (idsSplitted[i].contains("id") || idsSplitted[i].contains("ID")) {
                        publicIDs[i] = idsSplitted[i].substring(2, idsSplitted[i].length());
                        continue;
                    }
                    publicIDs[i] = idsSplitted[i];
                } catch (NumberFormatException e) {
                    System.out.println("The value \"" + idsSplitted[i] + "\" is not a valid and it has not been considered.");
                }
            }

            if (publicIDs.length == 1 && publicIDs[0] == null) {
                throw new RuntimeException("No correct IDs");
            }
            if (publicIDs.length <= 1) {
                throw new RuntimeException("You should list 2 or more public IDs");
            }
        }

        System.out.print("Publics: ");
        for (String publicID : publicIDs) {
            if (publicID != null)
                System.out.print("\"" + publicID + "\" ");
        }
        System.out.println("accepted.");
        System.out.println("******************************************\n\n");
        for (String publicID : publicIDs) {
            TOTAL_ITERATIONS_COUNT += getMembersCount(publicID, false) / 1000;
        }
        TOTAL_ITERATIONS_COUNT--;
        for (String publicID : publicIDs) {
            if (publicID != null) {
                processPublic(publicID);
                GROUPS_COUNT++;
            }
        }
        System.out.println("******************************************");
        findMatches();
    }

    private static void findMatches() {
        System.out.println("Finding matches...");
        boolean mFound = false;
        Collections.sort(AllIDs);
        int m = 1;
        int f = 0;
        for (int i = 1; i < AllIDs.size(); i++) {
            if (AllIDs.get(i - 1).equals(AllIDs.get(i))) {
                m++;
            } else if (m >= GROUPS_COUNT) {
                System.out.println("# match found: http://content-available-to-author-only.com/id" + (AllIDs.get(i - 1).contains("\n") ?
                        AllIDs.get(i - 1).substring(1, AllIDs.get(i - 1).length()) : AllIDs.get(i - 1)));
                mFound = true;
                m = 1;
                f++;
            } else m = 1;
        }
        if (!mFound)
            System.out.println("No matches found.");
        else System.out.println("Total matches found: " + f);
    }

    private static void processPublic(String publicID) {
        System.out.println("# processing public " + publicID + "...");
        SaveUserIdsToList(publicID);
        System.out.println("");
    }

    private static int getMembersCount(String publicID, boolean show) {
        int mCount;
        String s = getJSON("https://a...content-available-to-author-only...k.com/method/groups.getById?group_id=" + publicID + "&fields=members_count");
        int cPos = 0;
        for (int i = s.indexOf("\"members_count\":"); i < s.length(); i++) {
            try {
                if (s.charAt(i) == ',') {
                    cPos = i;
                    break;
                }
            } catch (StringIndexOutOfBoundsException e) {
                System.out.println("Processing public " + publicID + " caused an error.");
            }
        }
        mCount = Integer.parseInt(s.substring(s.indexOf("\"members_count\":") + 16, cPos));
        if (show) System.out.println("# members in " + publicID + ": " + mCount);
        return mCount;
    }


    private static void SaveUserIdsToList(String publicID) {
        int membersCount = getMembersCount(publicID, true);
        final int iterCount = membersCount / 1000 + 1;
        System.out.println("# iterations required: " + iterCount);
        for (int i = 0; i < iterCount; i++) {
            StringBuilder g = new StringBuilder(getJSON("https://a...content-available-to-author-only...k.com/method/groups.getMembers?group_id=" + publicID + "&offset=" + (i * USERS_PEER_PAGE) + "&sort=" + SORT_TYPE));
            g.delete(0, g.indexOf("\"users\":[") + 9);
            g.delete(g.length() - 3, g.length());
            totalIterationsCount++;
            int curP = (int) Math.floor(totalIterationsCount * 1.0 / TOTAL_ITERATIONS_COUNT * 100);
            if (curP > percent && curP <= 100) {
                System.out.println("# progress: " + curP + "%");
                percent = curP;
            }
            String[] splitted = StringUtils.splitString(g.toString().replace("\u002c", "\u002c\n"), "\u002c");
            for (String aSplitted : splitted) {
                try {
                    AllIDs.add(aSplitted);
                } catch (NumberFormatException e) {
                    System.out.println("# wrong number format: " + aSplitted);
                }
            }
        }
    }

    private static String getJSON(String url) {
        URLConnection connection = null;
        try {
            connection = new URL(url).openConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }

        InputStream is = null;
        try {
            is = connection.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        InputStreamReader reader = new InputStreamReader(is);
        char[] buffer = new char[256];
        int rc;

        StringBuilder sb = new StringBuilder();

        try {
            while ((rc = reader.read(buffer)) != -1)
                sb.append(buffer, 0, rc);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return sb.toString();
    }
}