import theater.*;

import java.io.Serializable;

import java.util.ArrayList;


/**
 * Die Klasse stellt eine Repraesentation des Einkaufwagens dar.
 *
 * @author Dietrich Boles (Universitaet Oldenburg)
 * @version 1.0 (22.10.2009)
 *
 */
public class Trolley extends Actor {
    private ArrayList<FruitProp> capturedFruits;
    boolean setLocPossible;

    // Default-Konstruktor (muss implementiert werden!)
    public Trolley() {
        super(); // nicht loeschen!
        setImage("einkaufswagen.gif");
        setZCoordinate(1);
        capturedFruits = new ArrayList<FruitProp>();
        setLocPossible = true;
    }

    // Copy-Konstruktor (muss implementiert werden!)
    public Trolley(Trolley actor) {
        super(actor); // nicht loeschen!
        capturedFruits = new ArrayList<FruitProp>();
        setLocPossible = true;
    }

    @Invisible
    @Override
    public void addedToStage(Stage stage) {
        setLocPossible = false;
    }

    @Description("<html>Liefert die aktuelle Spalte des Einkaufswagens.</html>")
    public int getColumn() {
        return super.getColumn();
    }

    @Description("<html>Liefert die Reihe des Einkaufswagens.</html>")
    public int getRow() {
        return super.getRow();
    }

    @Description("<html>getNumberOfCapturedFruits: Liefert die Anzahl an gefangenen Früchten.</html>")
    public int getNumberOfCapturedFruits() {
        Performance.getPerformance().lock();

        try {
            return capturedFruits.size();
        } finally {
            Performance.getPerformance().unlock();
        }
    }

    @Description("<html>getNumberOfNotCapturedFruits: Liefert die Anzahl an nicht gefangenen Früchten,<br>" +
    "das sind Früchte, die auf dem Boden liegen.</html>")
    public int getNumberOfNotCapturedFruits() {
        Performance.getPerformance().lock();

        try {
            return FruitProp.getNotCapturedFruits();
        } finally {
            Performance.getPerformance().unlock();
        }
    }

    @Description("<html>Bewegt den Einkaufswagen um eine Spalte nach links.<br>" +
    "Dabei fallen auch alle fallenden Früchte um eine Reihe nach unten.<br>" +
    "Geliefert werden alle fallenden Früchte.</html>")
    public Fruit[] left() {
        Performance.getPerformance().lock();
        Performance.getPerformance().freeze();

        try {
            setLoc(getColumn() - 1, getRow());
            FruitProp.downCycle();
            repositionCapturedFruits();

            return getFallingFruits();
        } finally {
            Performance.getPerformance().unfreeze();
            Performance.getPerformance().unlock();
        }
    }

    @Description("<html>Bewegt den Einkaufswagen um eine Spalte nach rechts.<br>" +
    "Dabei fallen auch alle fallenden Früchte um eine Reihe nach unten.<br>" +
    "Geliefert werden alle fallenden Früchte.</html>")
    public Fruit[] right() {
        Performance.getPerformance().lock();
        Performance.getPerformance().freeze();

        try {
            setLoc(getColumn() + 1, getRow());
            FruitProp.downCycle();
            repositionCapturedFruits();

            return getFallingFruits();
        } finally {
            Performance.getPerformance().unfreeze();
            Performance.getPerformance().unlock();
        }
    }

    @Description("<html>Der Einkauswagen bleibt an der aktuellen Spalte stehen.<br>" +
    "Alle fallenden Früchte fallen um eine Reihe nach unten.<br>" +
    "Geliefert werden alle fallenden Früchte.</html>")
    public Fruit[] stay() {
        Performance.getPerformance().lock();
        Performance.getPerformance().freeze();

        try {
            FruitProp.downCycle();
            repositionCapturedFruits();

            return getFallingFruits();
        } finally {
            Performance.getPerformance().unfreeze();
            Performance.getPerformance().unlock();
        }
    }

    @Description("<html>Versucht eine Frucht zu fangen.<br>" +
    "Fehler, wenn es keine Frucht f gibt, für die gilt: f.row == getRow() && f.column == getColumn().</html>")
    public void captureFruit() {
        Performance.getPerformance().lock();
        Performance.getPerformance().freeze();

        try {
            FruitProp f = FruitProp.tryCapture();
            captureFruit(f);
        } finally {
            Performance.getPerformance().unfreeze();
            Performance.getPerformance().unlock();
        }
    }

    @Invisible
    private void setLoc(int col, int row) {
        setLocPossible = true;
        setLocation(col, row);
        setLocPossible = false;
    }

    @Invisible
    @Override
    public void setLocation(int col, int row) {
        if (!setLocPossible &&
                ((GPerformance) Performance.getPerformance()).isRunning()) {
            return;
        }

        row = getStage().getNumberOfRows() -
            ((getImage().getHeight() / 2) + 10);
        super.setLocation(col, row);
    }

    @Invisible
    private Fruit[] getFallingFruits() {
        ArrayList<FruitProp> fs = FruitProp.getFallingFruits();
        Fruit[] res = new Fruit[fs.size()];

        int i = 0;

        for (FruitProp f : fs) {
            res[i++] = new Fruit(f.getRow(), f.getColumn());
        }

        return res;
    }

    @Invisible
    void captureFruit(FruitProp f) {
        capturedFruits.add(f);
        f.setZCoordinate(0);
        ((World) getStage()).getCapturedCounter().add(1);
    }

    @Invisible
    void repositionCapturedFruits() {
        for (FruitProp f : capturedFruits) {
            f.setLoc(getColumn(), f.getRow());
        }
    }
}


class Fruit implements Serializable {
    final int row;
    final int column;

    Fruit(int r, int c) {
        row = r;
        column = c;
    }

    public int getRow() {
        return row;
    }

    public int getColumn() {
        return column;
    }

    @Override
    public String toString() {
        return "Fruit(row=" + row + ", column=" + column + ")";
    }
}
