/**
 * @(#)BoxControlPanel.java
 * @author JLMJ
 * @date 2001-10-09
 */
package minoids1.counter;

import minoids1.Box;

public class MinoidsCounterMotor implements Runnable
{
    public static final String POLYOMINOES_TYPE_STRING = "Polyominoes";
    public static final String POLYOMINOIDS_TYPE_STRING = "Polyominoids";
    
    public static final String ANY_CONNECTIONS_TYPE_STRING = "Any";
    public static final String HARD_CONNECTIONS_TYPE_STRING = "Hard";
    public static final String SOFT_CONNECTIONS_TYPE_STRING = "Soft";

    public static final String COUNT_TRANSLATIONS_REPORT = "Count Translations";
    public static final String STORE_TRANSLATIONS_REPORT = "Store Translations";

    private String minoidsType;
    private int minoidsOrder;
    private String reportType;
    private Box[] boxes;
    private Box onlyThisBox;
    
    private MinoidsCounterListener listener;
    private MinoidsCounterEvent[] anyMinoidsCounterEvents;
    private MinoidsCounterEvent[] hardMinoidsCounterEvents;
    private MinoidsCounterEvent[] softMinoidsCounterEvents;
    
    private int anyMinoidsTotalCount;
    private int hardMinoidsTotalCount;
    private int softMinoidsTotalCount;
    private int polyominoesTotalCount;
    
    private Thread thread;
    
    private boolean countFinished = false;
    private long time1, time2;
    
    public MinoidsCounterMotor(
        String minoidsType, int minoidsOrder, String reportType,
        Box[] boxes, Box onlyThisBox)
    {
        this.minoidsType = minoidsType;
        this.minoidsOrder = minoidsOrder;
        this.reportType = reportType;
        this.boxes = boxes;
        this.onlyThisBox = onlyThisBox;
        
        if (boxes != null) {
            anyMinoidsCounterEvents = new MinoidsCounterEvent[boxes.length];
            hardMinoidsCounterEvents = new MinoidsCounterEvent[boxes.length];
            softMinoidsCounterEvents = new MinoidsCounterEvent[boxes.length];
        }
    }

    public float getVersion() {
        return (float)1.0;
    }
    
    public void start() {
        thread = new Thread(this);
        thread.start();
    }
    
    public void stop() {
        if (thread != null && thread.isAlive())
            thread.stop();
        time2 = System.currentTimeMillis() - time1;
        if (listener != null) // Notify counter's listener
            listener.countingAborted();
    }
    
    public MinoidsCounterEvent getAnyMinoidsCounterEvent(int boxIndex) {
        if (anyMinoidsCounterEvents.length > boxIndex)
            return anyMinoidsCounterEvents[boxIndex];
        return null;
    }
    
    public MinoidsCounterEvent getHardMinoidsCounterEvent(int boxIndex) {
        if (hardMinoidsCounterEvents.length > boxIndex)
            return hardMinoidsCounterEvents[boxIndex];
        return null;
    }
    
    public MinoidsCounterEvent getSoftMinoidsCounterEvent(int boxIndex) {
        if (softMinoidsCounterEvents.length > boxIndex)
            return softMinoidsCounterEvents[boxIndex];
        return null;
    }
    
    public boolean isCountFinished() {
        return countFinished;
    }
    
    public void run() {
        time1 = System.currentTimeMillis();
        countFinished = false;
        if (boxes == null) {
            countFinished = true;
            return;
        }
        if (listener != null)
            listener.countingStarted();
        anyMinoidsTotalCount = 0;
        softMinoidsTotalCount = 0;
        hardMinoidsTotalCount = 0;
        polyominoesTotalCount = 0;
        
        MinoidsCounterEvent event;
        for (int i=0; i < boxes.length; i++) {
            if (onlyThisBox != null && onlyThisBox != boxes[i])
                continue;
            
            int factor = boxes[i].getNumberOfRotations();
            boolean storeTranslationsMinoids =
                reportType.equals(STORE_TRANSLATIONS_REPORT);
            TranslationsCounter tc =
                new TranslationsCounter(boxes[i], storeTranslationsMinoids);
            
            if (minoidsType.equals(POLYOMINOIDS_TYPE_STRING)) {
                tc.countAnyMinoidsTranslations(minoidsOrder);
                event = new MinoidsCounterEvent(this, tc);
                anyMinoidsCounterEvents[i] = event;
                anyMinoidsTotalCount += event.getNumberOfMinoids() * factor;
                if (listener != null) // Notify counter's listener
                    listener.anyMinoidsCountingFinished(event);
                
                if (boxes[i].getX() == 0) {
                    event = new MinoidsCounterEvent(this, 0);
                } else {
                    tc.countHardMinoidsTranslations(minoidsOrder);
                    event = new MinoidsCounterEvent(this, tc);
                }
                hardMinoidsCounterEvents[i] = event;
                hardMinoidsTotalCount += event.getNumberOfMinoids() * factor;
                if (listener != null)
                    listener.hardMinoidsCountingFinished(event);
            }
            if (boxes[i].getX() == 0) {
                tc.countSoftMinoidsTranslations(minoidsOrder);
                event = new MinoidsCounterEvent(this, tc);
            } else {
                event = new MinoidsCounterEvent(this, 0);
            }
            softMinoidsCounterEvents[i] = event;
            softMinoidsTotalCount += event.getNumberOfMinoids() * factor;
            polyominoesTotalCount += event.getNumberOfMinoids() * factor / 3;
            if (listener != null)
                listener.softMinoidsCountingFinished(event);
            
            if (listener != null)
                listener.boxCountingFinished(boxes[i]);
        }
        countFinished = true;
        time2 = System.currentTimeMillis() - time1;
        if (listener != null)
            listener.countingFinished();
    }
    
    public long getElapsedTime() {
        return time2;
    }
    
    public int getAnyMinoidsTotalCount() {
        return anyMinoidsTotalCount;
    }
    
    public int getHardMinoidsTotalCount() {
        return hardMinoidsTotalCount;
    }
    
    public int getSoftMinoidsTotalCount() {
        return softMinoidsTotalCount;
    }
    
    public int getPolyominoesTotalCount() {
        return polyominoesTotalCount;
    }

    public void addMinoidsCounterListener(MinoidsCounterListener listener) {
        this.listener = listener;
    }
    
    public void removeMinoidsCounterListener() {
        this.listener = null;
    }
    
    public Box getOnlyThisBox() {
        return onlyThisBox;
    }
}


