package iDSS.grids;


import java.util.*;

import iDSS.*;
import iDSS.utils.*;




public class Flood implements Runnable {


    private double floodDepth;
    private Grid floodDepthGrid;
    private Grid demGrid;
    private int floodRow;
    private int floodColumn;
    private double unknownFloodDepth;
    private int origRow;
    private int origColumn;

    private static int recursionLevel = 0;
    private static final int MAX_RECURSION_LEVEL = 10;
    private Vector floodGridVector;

    private int nRows;
    private int nColumns;
    private boolean statusNotified = false;





    public Flood(double floodDepth,Grid floodDepthGrid,Grid demGrid,int floodRow,
                                int floodColumn,double unknownFloodDepth,int origRow,int origColumn) {



        this.floodDepth = floodDepth;
        this.floodDepthGrid = floodDepthGrid;
        this.floodDepthGrid = floodDepthGrid;
        this.demGrid = demGrid;
        this.floodRow = floodRow;
        this.floodColumn = floodColumn;
        this.unknownFloodDepth = unknownFloodDepth;
        this.origRow = origRow;
        this.origColumn = origColumn;

        nRows = demGrid.getNRows();
        nColumns = demGrid.getNColumns();


    } //



    public synchronized void run() {


        //System.out.println("Grid.startFlooding()");

        recursionLevel++;
        System.out.println(recursionLevel + "  " + floodRow + "  " + floodColumn);

        boolean gridComplete;

        if(recursionLevel < MAX_RECURSION_LEVEL) {


            if(isWithinRange(floodRow,floodColumn)) {

                double floodValue = (double) floodDepthGrid.getValue(floodColumn,floodRow);
                //System.out.println("flood grid value  = " + floodValue);

                if(Math.abs(floodValue-unknownFloodDepth) < 0.01) {

                    double demValue = (double) demGrid.getValue(floodColumn,floodRow);

                    //System.out.println("WL = " + floodDepth + ", DEM = " + demValue + " at " + floodRow + "," + floodColumn);

                    double nodataValue = (double)demGrid.getNoDataValue();

                    if(Math.abs(demValue-nodataValue)<0.01) {
                        floodDepthGrid.setDataAt(floodColumn,floodRow,nodataValue);
                        //System.out.println("Nodata");
                    }

                    else if(demValue >= floodDepth) {
                        floodDepthGrid.setDataAt(floodColumn,floodRow,0);
                        //System.out.println("Dry");
                    }

                    else {

                        double fd = floodDepth-demValue;
                        //System.out.println(floodRow + "  " + floodColumn);
                        floodDepthGrid.setDataAt(floodColumn,floodRow,fd);

                        for(int i=(floodRow-1);i<=(floodRow+1);i++) {

                            for(int j=(floodColumn-1);j<=(floodColumn+1);j++) {

                                if((i == (origRow-1)) && (j == (origColumn-1))) {}
                                else if((i == (origRow-1)) && (j == (origColumn-0))) {}
                                else if((i == (origRow-1)) && (j == (origColumn+1))) {}
                                else if((i == (origRow-0)) && (j == (origColumn-1))) {}
                                else if((i == (origRow-0)) && (j == (origColumn-0))) {}
                                else if((i == (origRow-0)) && (j == (origColumn+1))) {}
                                else if((i == (origRow+1)) && (j == (origColumn-1))) {}
                                else if((i == (origRow+1)) && (j == (origColumn-0))) {}
                                else if((i == (origRow+1)) && (j == (origColumn+1))) {}
                                else if((i == (floodRow)) && (j == (floodColumn))) {}

                                else {

                                    if(isWithinRange(i,j)) {

                                        double fValue = (double) floodDepthGrid.getValue(i,j);

                                        if(Math.abs(fValue-unknownFloodDepth) < 0.01) {

                                            Thread thread2 = Thread.currentThread();
                                            try {
                                                thread2.sleep(1);
                                            }
                                            catch(InterruptedException intExc) {
                                                System.out.println("Flood.run(), " + intExc);
                                            }

                                            Flood flood =
                                                new Flood(floodDepth,floodDepthGrid,
                                                            demGrid,i,j,unknownFloodDepth,
                                                            floodRow,floodColumn);
                                            Thread thread = new Thread(flood);
                                            thread.start();

                                        }
                                    
                                    } //if(isWithinRange(i,j))

                                } //else




                            } //for(int j=jMin;j<=jMax;j++)

                        } //for(int i=iMin;i<=iMax;i++)

                    } //else

                } //if(Math.abs(floodValue-unknownFloodDepth) < 0.01)

            } //if((floodRow >= 0) && (floodRow <= (nRows-1)) && (floodColumn >= 0) && (floodColumn <= (nColumns-1)))


            recursionLevel = 0;
            gridComplete = true;
            floodGridVector.add(floodDepthGrid);
            floodGridVector.add(new Boolean(gridComplete));
            floodGridVector.add(new Integer(0));
            floodGridVector.add(new Integer(0));
            floodGridVector.add(new Integer(0));
            floodGridVector.add(new Integer(0));

        } //if(recursionLevel < MAX_RECURSION_LEVEL)


        else {  //if(recursionLevel < MAX_RECURSION_LEVEL)

            recursionLevel = 0;
            gridComplete = false;

            floodGridVector.add(floodDepthGrid);
            floodGridVector.add(new Boolean(gridComplete));
            floodGridVector.add(new Integer(floodRow));
            floodGridVector.add(new Integer(floodColumn));
            floodGridVector.add(new Integer(origRow));
            floodGridVector.add(new Integer(origColumn));

        } //if(recursionLevel < MAX_RECURSION_LEVEL)


        notifyAll();
        statusNotified = true;

        //return floodDepthGrid;
        //return floodGridVector;

    } //public void run();





    public synchronized Vector getFloodGridVector() {

        try {

            wait();

        } //try

        catch(InterruptedException e) {

            System.out.println("Flood.run(), " + e.toString());

        } //

        catch(IllegalMonitorStateException e) {

            System.out.println("Flood.run(), " + e.toString());

        } //

        catch(IllegalArgumentException e) {

            System.out.println("Flood.run(), " + e.toString());

        } //


        return floodGridVector;



    } //public Vector getFloodGridVector()





    private boolean isWithinRange(int i,int j) {

        return ((i >= 0) && (i <= (nRows-1)) && (j >= 0) && (j <= (nColumns-1)));

    } //private boolean isWithinRange(int i,int j)



} //
