package electrosphere.game.server.terrain.generation;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

/**
 *
 * @author satellite
 */
class TerrainGenerator {
    static int DIMENSION = 200;
    static int[][] asthenosphere_Heat;
    static int[][] rock_Hardness;
    static int[][] elevation;
    static int[][] smoothed_elevation;
    static int new_Elevation[][];
    static Vector[][] currents;
    static ArrayList<Hotspot> spots = new ArrayList();
    static int Time = 0;
    static final int ELEVATION_DATA_LENGTH = 50;
    static int[] elevation_Data;
    static int current_Max_Elevation_Data = 1;
    static int lifespan = 75000;
    
    public TerrainGenerator(){
        
    }
    
    public void set_Dimension(int new_Dim){
        DIMENSION = new_Dim;
    }
    
    public void set_Lifespan(int new_Lifespan){
        lifespan = new_Lifespan;
    }
    
    
    public void run(){
        asthenosphere_Heat = new int[DIMENSION][DIMENSION];
        elevation = new int[DIMENSION][DIMENSION];
        smoothed_elevation = new int[DIMENSION][DIMENSION];
        new_Elevation = new int[DIMENSION][DIMENSION];
        currents = new Vector[DIMENSION][DIMENSION];
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                currents[x][y] = new Vector();
            }
        }
        elevation_Data = new int[ELEVATION_DATA_LENGTH];
        for(int x = 0; x < ELEVATION_DATA_LENGTH; x++){
            elevation_Data[x] = 0;
        }
        
        
        
        
        long last_Time = System.currentTimeMillis();
        
        
        while(true){
            Time++;
            if(spots.size() >= 1){
                ArrayList<Hotspot> to_Remove = new ArrayList();
                Iterator<Hotspot> spot_Iterator = spots.iterator();
                while(spot_Iterator.hasNext()){
                    Hotspot current_Spot = spot_Iterator.next();
                    if(current_Spot.life_current >= current_Spot.life_max){
                        to_Remove.add(current_Spot);
                    }
                }
                spot_Iterator = to_Remove.iterator();
                while(spot_Iterator.hasNext()){
                    Hotspot current_Spot = spot_Iterator.next();
                    spots.remove(current_Spot);
                }
            }
            if(spots.size() < 5){
                spots.add(new Hotspot(electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.server.terrain.generation.Utilities.random_Integer(6000, 10000), electrosphere.game.server.terrain.generation.Utilities.random_Integer(3, 5), this));
            }
            for(int x = 0; x < DIMENSION; x++){
                for(int y = 0; y < DIMENSION; y++){
                    asthenosphere_Heat[x][y] = 0;
                }
            }
            if(spots.size() >= 1){
                Iterator<Hotspot> spot_Iterator = spots.iterator();
                while(spot_Iterator.hasNext()){
                    Hotspot current_Spot = spot_Iterator.next();
                    current_Spot.simulate();
                }
            }
//            try {
//                TimeUnit.MILLISECONDS.sleep(1);
//            } catch (InterruptedException ex) {
//            }
            heat_To_Elevation();
            construct_Convection_Cells();
            apply_Vectors_To_Elevation();
            calculate_Smoothed_Elevations();
            if(Time % 500 == 0) {
                long new_Time = System.currentTimeMillis();
                long time_Delta = new_Time - last_Time;
                last_Time = new_Time;
                System.out.println("Progress: " + Time + "/" + lifespan + " ETA: " + (time_Delta * (lifespan - Time) / 1000 / 500) + "S");
            }
            if(Time > lifespan){
                break;
            }
        }
    }
    
    public int[][] get_Terrain(){
        return elevation;
    }
    
    public int[][] get_Terrain_Smoothed(){
        return smoothed_elevation;
    }
    
    static void heat_To_Elevation(){
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                if(asthenosphere_Heat[x][y] > 25){
                    if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 10) == 10){
                        elevation[x][y] = elevation[x][y] + 1;
                        if(elevation[x][y] > 100){
                            elevation[x][y] = 100;
                        }
                    }
                }
            }
        }
    }
    
    static void construct_Convection_Cells(){
        boolean is_cell_type_1 = false;
        int fourth = DIMENSION / 4;
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                int normalized_x = x;
                int normalized_y = y;
                if(y < fourth || (y < fourth * 3 && y > (fourth * 2) - 1)){
                    is_cell_type_1 = true;
                    if(normalized_y > fourth){
                        normalized_y = normalized_y - fourth * 2;
                    }
                } else {
                    is_cell_type_1 = false;
                    if(normalized_y > fourth * 2 + 1){
                        normalized_y = normalized_y - fourth * 3;
                    } else {
                        normalized_y = normalized_y - fourth;
                    }
                }
                while(normalized_x > fourth){
                    normalized_x = normalized_x - fourth;
                }
                if(normalized_x < 0){
                    normalized_x = 0;
                }
                if(normalized_y < 0){
                    normalized_y = 0;
                }
                int eigth = fourth / 2;
                normalized_y = normalized_y - eigth;
                normalized_x = normalized_x - eigth;
                float magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2));
                if(magnitude < fourth / 10){
                    normalized_x = normalized_x + fourth / 10;
                    magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2));
                }
                double offset_angle = Math.atan2(normalized_y / magnitude, normalized_x / magnitude);
                if(offset_angle < 0){
                    offset_angle = offset_angle + Math.PI * 2;
                }
                double vector_angle = offset_angle;
                if(is_cell_type_1){
                    offset_angle = offset_angle + Math.PI / 2;
                } else {
                    offset_angle = offset_angle - Math.PI / 2;
                }
                while(offset_angle > Math.PI * 2){
                    offset_angle = offset_angle - Math.PI * 2;
                }
                while(offset_angle < 0){
                    offset_angle = offset_angle + Math.PI * 2;
                }
                currents[x][y].x = (int)(99 * Math.cos(offset_angle));
                currents[x][y].y = (int)(99 * Math.sin(offset_angle));
            }
        }
    }
    
    static void apply_Vectors_To_Elevation(){
        int current_Elev[][] = new int[DIMENSION][DIMENSION];
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                new_Elevation[x][y] = 0;
                current_Elev[x][y] = elevation[x][y];
            }
        }
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                    boolean transfer = false;
                    if (electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 50) == 1) {
                        transfer = true;
                    }
                    int transfer_goal;
                    if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 2)==1){
                        transfer_goal = electrosphere.game.server.terrain.generation.Utilities.random_Integer(20, 60);
                    } else {
                        transfer_goal = electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, 60);
                    }
                    if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 2)==1){
                    if (currents[x][y].x >= 0) {
                            if (transfer) {
                                if (x + 1 < DIMENSION) {
                                    while(new_Elevation[x + 1][y] + current_Elev[x + 1][y] < 99 && current_Elev[x][y] > transfer_goal){
                                        new_Elevation[x + 1][y]++;
                                        current_Elev[x][y]--;
                                    }
                                } else {
                                }
                            }
                        } else {
                            if (transfer) {
                                if (x - 1 >= 0) {
                                    while(new_Elevation[x - 1][y] + current_Elev[x - 1][y] < 99 && current_Elev[x][y] > transfer_goal){
                                        new_Elevation[x - 1][y]++;
                                        current_Elev[x][y]--;
                                    }
                                } else {
                                }
                            }
                        }
                    } else {
                        if (currents[x][y].y >= 0) {
                            if (transfer) {
                                if (y + 1 < DIMENSION) {                                   //  V    REPLACE THIS WITH GOAL
                                    while(new_Elevation[x][y + 1] + current_Elev[x][y + 1] < 99 && current_Elev[x][y] > transfer_goal){
                                        new_Elevation[x][y + 1]++;
                                        current_Elev[x][y]--;
                                    }
                                } else {
                                }
                            }
                        } else {
                            if (transfer) {
                                if (y - 1 >= 0) {
                                        while(new_Elevation[x][y - 1] + current_Elev[x][y - 1] < 99 && current_Elev[x][y] > transfer_goal){
                                        new_Elevation[x][y - 1]++;
                                        current_Elev[x][y]--;
                                    }
                                } else {
                                }
                            }
                        }
                    }
            }
        }
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                new_Elevation[x][y] = new_Elevation[x][y] + current_Elev[x][y];
                while(new_Elevation[x][y] > 99){
                    new_Elevation[x][y] = 99;
                }
                elevation[x][y] = new_Elevation[x][y];
            }
        }
    }
    
    static void grab_Elevation_Data(){
        int new_Elevation_Data_Val = 0;
        for(int x = 0; x < DIMENSION; x++){
            for(int y = 0; y < DIMENSION; y++){
                new_Elevation_Data_Val = new_Elevation_Data_Val + elevation[x][y];
            }
        }
        for(int x = 1; x < ELEVATION_DATA_LENGTH; x++){
            elevation_Data[x-1] = elevation_Data[x];
        }
        elevation_Data[ELEVATION_DATA_LENGTH - 1] = new_Elevation_Data_Val;
        if(new_Elevation_Data_Val > current_Max_Elevation_Data){
            current_Max_Elevation_Data = new_Elevation_Data_Val;
        }
    }
    
    static void calculate_Smoothed_Elevations(){
        int[][] buffer = new int[DIMENSION][DIMENSION];
        for(int x = 1; x < DIMENSION - 2; x++){
            for(int y = 1; y < DIMENSION - 2; y++){
                buffer[x][y] = elevation[x][y] * 4 * elevation[x+1][y] * 2 + elevation[x-1][y] * 2 + elevation[x][y+1] * 2 +
                        elevation[x][y-1] * 2 + elevation[x+1][y+1] + elevation[x+1][y-1] + elevation[x-1][y+1] + elevation[x-1][y-1];
                buffer[x][y] = (int)(buffer[x][y] / 16.0);
                while(buffer[x][y] > 100){
                    buffer[x][y] = buffer[x][y]/2;
                }
                smoothed_elevation[x][y] = buffer[x][y];
            }
        }
        for(int x = 1; x < DIMENSION - 2; x++){
            for(int y = 1; y < DIMENSION - 2; y++){
                buffer[x][y] = smoothed_elevation[x][y] * 4 * smoothed_elevation[x+1][y] * 2 + smoothed_elevation[x-1][y] * 2 + smoothed_elevation[x][y+1] * 2 +
                        smoothed_elevation[x][y-1] * 2 + smoothed_elevation[x+1][y+1] + smoothed_elevation[x+1][y-1] + smoothed_elevation[x-1][y+1] + smoothed_elevation[x-1][y-1];
                buffer[x][y] = (int)(buffer[x][y] / 16.0);
                while(buffer[x][y] > 100){
                    buffer[x][y] = buffer[x][y]/2;
                }
                smoothed_elevation[x][y] = buffer[x][y];
            }
        }
    }
}
