package ru.spb.kpit.kivan.Networking.AsyncCrawler.Proxy;

import ru.spb.kpit.kivan.General.DataStructures.HMCounter;
import ru.spb.kpit.kivan.Networking.AsyncCrawler.AsyncSiteRequestExecutor;
import ru.spb.kpit.kivan.Randomizer.SSRand;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * IntelliJ IDEA. Best IDE in entire Universe.
 * CodeGod: Kivan
 * ContinuumBreak: 23.09.13
 * MomentOfSilence: 16:36
 */
public class ProxyPool {
    /**
     * String - name of prismer
     */
    HashMap<String, ProxyPrismer> prismers = new HashMap<String, ProxyPrismer>();

    /**
     * List of o4erednostj of executions
     */
    HashMap<AsyncSiteRequestExecutor, Set<ProxyPrismer>> o4erednostj = new HashMap<AsyncSiteRequestExecutor, Set<ProxyPrismer>>();

    int maxBadCountForPrismer = 5;
    HMCounter<ProxyPrismer> badPrismers = new HMCounter<ProxyPrismer>();

    ReentrantLock lock = new ReentrantLock();

    public ProxyPool(ProxyPrismer ... prismers) {
        for (ProxyPrismer prismer : prismers) {
            this.prismers.put(prismer.getInfo(), prismer);
        }
    }

    public ProxyPool(int maxBadCountForPrismer, ProxyPrismer ... prismers) {
        this.maxBadCountForPrismer = maxBadCountForPrismer;
        for (ProxyPrismer prismer : prismers) {
            this.prismers.put(prismer.getInfo(), prismer);
        }
    }

    public ProxyPrismer getPrismer(AsyncSiteRequestExecutor executor){
        try {
            lock.lock();
            Set<ProxyPrismer> proPri = o4erednostj.get(executor);
            if(proPri==null || proPri.size()==0) {
                proPri = new HashSet<ProxyPrismer>();
                for (ProxyPrismer proxyPrismer : prismers.values()) {
                    proPri.add(proxyPrismer);
                }
                o4erednostj.put(executor, proPri);
            }

            ProxyPrismer pp = (ProxyPrismer) SSRand.thrdSf().randElFromCollection(proPri);
            proPri.remove(pp);

            return pp;
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } finally {
            lock.unlock();
        }
        return null;
    }

    public void prismerDoneBad(ProxyPrismer prismer) {
        try {
            lock.lock();
            badPrismers.put(prismer);
            if(badPrismers.get(prismer)>maxBadCountForPrismer) {
                prismers.remove(prismer.getInfo());
                badPrismers.remove(prismer);
            }
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } finally {
            lock.unlock();
        }
    }
}
