// Path: src/worlds/planet/Surface.java
// public abstract class Surface extends SurfaceMap<PlanetCell> {
// 
//   /**
//    * The number of years that pass for each step of erosion
//    */
//   public static long GEOUPDATE;
//   private long geologicalTimeStamp;
// 
//   /**
//    * The age of the planet in years
//    */
//   public static AtomicLong planetAge;
//   
//   /**
//    * The number of years that pass for each update to the geosphere
//    */
//   public static long timeStep;
// 
//   public final static int HEIGHTMAP = 0;
//   public final static int STRATAMAP = 1;
//   public final static int LANDOCEAN = 2;
// 
//   private static final int DEFAULT_THREAD_DELAY = 50;
// 
//   private final MinMaxHeightFactory mhFactory;
// 
//   static {
//     timeStep = 7125000;
//   }
// 
//   /**
//    * Constructs a new Surface with an empty map.
//    *
//    * @param totalSize The size of the surface
//    * @param threadsDelay The amount of time to delay each frame in milliseconds.
//    * @param threadCount The number of threads that will work on the map
//    */
//   public Surface(int totalSize, int threadsDelay, int threadCount) {
//     super(totalSize, DEFAULT_THREAD_DELAY);
//     setupThreads(threadCount, threadsDelay);
//     setupDefaultMap(threadCount);
//     mhFactory = new MinMaxHeightFactory(this);
//     produceTasks(mhFactory);
//     reset();
//   }
// 
//   /**
//    * Resets the surface to an empty map and resets the planet's age. This method
//    * should be calling the <code>buildMap()</code> method.
//    */
//   @Override
//   public final void reset() {
//     planetAge = new AtomicLong(0);
//     geologicalTimeStamp = 0;
//     pauseThreads();
//     buildMap();
//     addTaskToThreads(new SetParentThreads());
//     playThreads();
//   }
// 
//   public long getPlanetAge() {
//     return planetAge.get();
//   }
// 
//   public void updatePlanetAge() {
//     long curPlanetAge = planetAge.getAndAdd(timeStep);
//     if (curPlanetAge - geologicalTimeStamp > GEOUPDATE) {
//       geologicalTimeStamp = curPlanetAge;
//     }
//   }
// 
//   @Override
//   public PlanetCell generateCell(int x, int y) {
//     return new PlanetCell(x, y);
//   }
// 
//   public float getHighestHeight() {
//     return mhFactory.getHighestHeight();
//   }
// 
//   public float getLowestHeight() {
//     return mhFactory.getLowestHeight();
//   }
// 
// }
// 
// Path: src/worlds/planet/geosphere/tasks/MantleConduction.java
// public class MantleConduction extends Task {
// 
//   private final Geosphere surface;
//   private final Delay delay;
//   
//   public MantleConduction(Geosphere surface) {
//     this.surface = surface;
//     delay = new Delay(250);
//   }
//   
//   @Override
//   public void construct() {}
// 
//   @Override
//   public boolean check() throws Exception {
//     return delay.check();
//   }
// 
//   @Override
//   public void before() throws Exception {
//   }
// 
//   @Override
//   public void perform(int x, int y) throws Exception {
//     GeoCell cell = surface.getCellAt(x, y);
//     Vec2[] cells = Util.getCellIndexesFrom(cell.getGridPosition(), surface.getTerrainSize());
//     float temp = cell.getMantleTemperature(); 
//     for (Vec2 pos : cells) {
//       GeoCell neighborCell = surface.getCellAt(pos);
//       float cellTemp = neighborCell.getMantleTemperature();
//       float tempChange = (PlanetCell.length * (temp - cellTemp)) / (1e7f);
//       cell.addToMantleHeat(-tempChange);
//     }
//   }
// 
//   @Override
//   public void after() throws Exception {
//   }
//   
// }
// 
// Path: src/worlds/planet/geosphere/tasks/MantleRadiation.java
// public class MantleRadiation extends Task {
// 
//   private final Geosphere geosphere;
//   private final Delay delay;
//   
//   
//   public MantleRadiation(Geosphere geosphere) {
//     this.geosphere = geosphere;
//     delay = new Delay(400);
//   }
//   
//   @Override
//   public void before() {
//   }
// 
//   @Override
//   public void perform(int x, int y) {
//     GeoCell cell = geosphere.getCellAt(x, y);
//     float heatFromMantle = Util.calcHeatRadiation(cell.getMantleTemperature());
//     float denom = (cell.getTotalMass() * cell.getSpecificHeat());
//     denom = denom == 0 ? 1 : denom;
//     float tempChangeToMantle = heatFromMantle / denom;
//     
//     cell.addToMantleHeat(-tempChangeToMantle * 0.001f);
//   }
// 
//   @Override
//   public void after() {
//   }
// 
//   @Override
//   public void construct() {
//   }
// 
//   @Override
//   public boolean check() {
//     return delay.check();
//   }
//   
// }


import worlds.planet.Surface;
import worlds.planet.geosphere.tasks.MantleConduction;
import worlds.planet.geosphere.tasks.MantleRadiation;
package worlds.planet.geosphere;

/**
 * Contains all logic that works on the geology of the planet.
 *
 * @author Richard DeSilvey
 */
public abstract class Geosphere extends Surface {

  private long ageStamp;
  
  public Geosphere(int totalSize, int threadsDelay, int threadCount) {
    super(totalSize, threadsDelay, threadCount);
    ageStamp = 0;
    produceTasks(() -> {
// Path: src/worlds/planet/Surface.java
// public abstract class Surface extends SurfaceMap<PlanetCell> {
// 
//   /**
//    * The number of years that pass for each step of erosion
//    */
//   public static long GEOUPDATE;
//   private long geologicalTimeStamp;
// 
//   /**
//    * The age of the planet in years
//    */
//   public static AtomicLong planetAge;
//   
//   /**
//    * The number of years that pass for each update to the geosphere
//    */
//   public static long timeStep;
// 
//   public final static int HEIGHTMAP = 0;
//   public final static int STRATAMAP = 1;
//   public final static int LANDOCEAN = 2;
// 
//   private static final int DEFAULT_THREAD_DELAY = 50;
// 
//   private final MinMaxHeightFactory mhFactory;
// 
//   static {
//     timeStep = 7125000;
//   }
// 
//   /**
//    * Constructs a new Surface with an empty map.
//    *
//    * @param totalSize The size of the surface
//    * @param threadsDelay The amount of time to delay each frame in milliseconds.
//    * @param threadCount The number of threads that will work on the map
//    */
//   public Surface(int totalSize, int threadsDelay, int threadCount) {
//     super(totalSize, DEFAULT_THREAD_DELAY);
//     setupThreads(threadCount, threadsDelay);
//     setupDefaultMap(threadCount);
//     mhFactory = new MinMaxHeightFactory(this);
//     produceTasks(mhFactory);
//     reset();
//   }
// 
//   /**
//    * Resets the surface to an empty map and resets the planet's age. This method
//    * should be calling the <code>buildMap()</code> method.
//    */
//   @Override
//   public final void reset() {
//     planetAge = new AtomicLong(0);
//     geologicalTimeStamp = 0;
//     pauseThreads();
//     buildMap();
//     addTaskToThreads(new SetParentThreads());
//     playThreads();
//   }
// 
//   public long getPlanetAge() {
//     return planetAge.get();
//   }
// 
//   public void updatePlanetAge() {
//     long curPlanetAge = planetAge.getAndAdd(timeStep);
//     if (curPlanetAge - geologicalTimeStamp > GEOUPDATE) {
//       geologicalTimeStamp = curPlanetAge;
//     }
//   }
// 
//   @Override
//   public PlanetCell generateCell(int x, int y) {
//     return new PlanetCell(x, y);
//   }
// 
//   public float getHighestHeight() {
//     return mhFactory.getHighestHeight();
//   }
// 
//   public float getLowestHeight() {
//     return mhFactory.getLowestHeight();
//   }
// 
// }
// 
// Path: src/worlds/planet/geosphere/tasks/MantleConduction.java
// public class MantleConduction extends Task {
// 
//   private final Geosphere surface;
//   private final Delay delay;
//   
//   public MantleConduction(Geosphere surface) {
//     this.surface = surface;
//     delay = new Delay(250);
//   }
//   
//   @Override
//   public void construct() {}
// 
//   @Override
//   public boolean check() throws Exception {
//     return delay.check();
//   }
// 
//   @Override
//   public void before() throws Exception {
//   }
// 
//   @Override
//   public void perform(int x, int y) throws Exception {
//     GeoCell cell = surface.getCellAt(x, y);
//     Vec2[] cells = Util.getCellIndexesFrom(cell.getGridPosition(), surface.getTerrainSize());
//     float temp = cell.getMantleTemperature(); 
//     for (Vec2 pos : cells) {
//       GeoCell neighborCell = surface.getCellAt(pos);
//       float cellTemp = neighborCell.getMantleTemperature();
//       float tempChange = (PlanetCell.length * (temp - cellTemp)) / (1e7f);
//       cell.addToMantleHeat(-tempChange);
//     }
//   }
// 
//   @Override
//   public void after() throws Exception {
//   }
//   
// }
// 
// Path: src/worlds/planet/geosphere/tasks/MantleRadiation.java
// public class MantleRadiation extends Task {
// 
//   private final Geosphere geosphere;
//   private final Delay delay;
//   
//   
//   public MantleRadiation(Geosphere geosphere) {
//     this.geosphere = geosphere;
//     delay = new Delay(400);
//   }
//   
//   @Override
//   public void before() {
//   }
// 
//   @Override
//   public void perform(int x, int y) {
//     GeoCell cell = geosphere.getCellAt(x, y);
//     float heatFromMantle = Util.calcHeatRadiation(cell.getMantleTemperature());
//     float denom = (cell.getTotalMass() * cell.getSpecificHeat());
//     denom = denom == 0 ? 1 : denom;
//     float tempChangeToMantle = heatFromMantle / denom;
//     
//     cell.addToMantleHeat(-tempChangeToMantle * 0.001f);
//   }
// 
//   @Override
//   public void after() {
//   }
// 
//   @Override
//   public void construct() {
//   }
// 
//   @Override
//   public boolean check() {
//     return delay.check();
//   }
//   
// }


// Path: src/worlds/planet/geosphere/Geosphere.java
import worlds.planet.Surface;
import worlds.planet.geosphere.tasks.MantleConduction;
import worlds.planet.geosphere.tasks.MantleRadiation;

package worlds.planet.geosphere;

/**
 * Contains all logic that works on the geology of the planet.
 *
 * @author Richard DeSilvey
 */
public abstract class Geosphere extends Surface {

  private long ageStamp;
  
  public Geosphere(int totalSize, int threadsDelay, int threadCount) {
    super(totalSize, threadsDelay, threadCount);
    ageStamp = 0;
    produceTasks(() -> {
      return new MantleRadiation(this);