package uk.ac.stir.cs.terrawiz;

import java.awt.Color;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.JCheckBox;

import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSSerializer;

/**
  Class to holds common definitions for the entire program.

  @author	Tao (Fred) Lu, Kenneth J. Turner
  @version	1.0 (6th April 2009)
*/

public class Common {

  /** Program version */
  public final static String programVersion = "1.0 (6th April 2009)";

  /** Program version colour*/
  public final static Color versionColour = new Color(0, 170, 204);

  /** How long the start-up banner is shown (milliseconds) */
  public final static int bannerTime = 2000;

  /** Width of start-up banner */
  public final static int startupWidth = 600;

  /** Height of start-up banner */
  public final static int startupHeight = 300;

  /** Width of initial window */
  public final static int initWidth = 400;

  /** Height of initial window */
  public final static int initHeight = 350;

  /** Width of beginner window */
  public final static int beginnerWidth = 400;

  /** Height of beginner window */
  public final static int beginnerHeight = 350;

  /** Width of this application */
  public final static int frameWidth = 450;

  /** Height of this application */
  public final static int frameHeight = 500;

  /** Width of tabbed pane */
  public final static int tabWidth = 430;

  /** Height of tabbed pane */
  public final static int tabHeight = 430;

  /** Width of help content */
  public final static int helpWidth = 500;

  /** Height of help content */
  public final static int helpHeight = 500;

  /** Initial window title */
  public final static String initTitle = "First Time Language & Mode setting";

  /** File path of icon */
  public final static String iconPath = "res/icon.png";

  /** Setting file */
  public final static String settingsFile = "/.terrawiz.xml";

  /** Standard file path */
  public final static String terragenTemplate = "res/terragen.xml";

  /** Schema file path */
  public final static String wizardURL =
    "http://www.cs.stir.ac.uk/schemas/terragen_wizard.xsd";

  /** Created file status */
  public final static int createdFile = 0;

  /** Opened file status */
  public final static int openedFile = 1;

  /** TGW (wizard) file status */
  public final static int tgwfile = 0;

  /** TGD (Terragen) file status */
  public final static int tgdfile = 1;

  /** File state */
  public static int fileState = createdFile;

  /** File category */
  public static int fileCategory = tgwfile;

  public static boolean fileChanged = false;

  //// TGD values ////

  // lake
  public final static int tgdLakeLevel1 = 10;
  public final static int tgdLakeLevel2 = 300;
  public final static int tgdLakeRadius1 = 50000;
  public final static int tgdLakeRadius2 = 100000;
  public final static double tgdLakeRoughness1 = 0.02;
  public final static double tgdLakeRoughness2 = 0.3;
  public final static int tgdLakeScale1 = 5;
  public final static int tgdLakeScale2 = 80;
  public final static double tgdLakeReflec1 = 0.05;
  public final static double tgdLakeReflec2 = 0.8;

  // Mountain
  public final static int tgdMountainRoughness1 = 20000;
  public final static int tgdMountainRoughness2 = 1000;
  public final static double tgdMountainFlat1 = 0.002;
  public final static double tgdMountainFlat2 = 0.2;

  // surface
  public final static String tgdSurfaceSkin1 = "1 1 1";
  public final static String tgdSurfaceSkin2 = "0.0236995 0.18125 0.00057709";
  public final static int tgdSurfaceMaxAlt1 = 800;
  public final static int tgdSurfaceMaxAlt2 = 1000;
  public final static int tgdSurfaceMinAlt1 = 100;
  public final static int tgdSurfaceMinAlt2 = 400;

  // cloud
  public final static String tgdCloudCategory1 = "Altocumulus layer 01";
  public final static int tgdCloudCategory1_3 = 1;
  public final static double tgdCloudCategory1_4 = 0.289898;
  public final static int tgdCloudCategory1_5 = 6;
  public final static int tgdCloudCategory1_6 = 150;
  public final static int tgdCloudCategory1_7 = 20000;
  public final static int tgdCloudCategory1_8 = 13;
  public final static double tgdCloudCategory1_9 = 1.75;
  public final static int tgdCloudCategory1_10 = 2;
  public final static double tgdCloudCategory1_11 = 0.5;
  public final static int tgdCloudCategory1_12 = 1;
  public final static String tgdCloudCategory2 = "Cirrus layer 01";
  public final static int tgdCloudCategory2_3 = 0;
  public final static double tgdCloudCategory2_4 = 0.510478;
  public final static int tgdCloudCategory2_5 = 5;
  public final static int tgdCloudCategory2_6 = 20000;
  public final static int tgdCloudCategory2_7 = 50000;
  public final static int tgdCloudCategory2_8 = 14;
  public final static double tgdCloudCategory2_9 = 1.5;
  public final static int tgdCloudCategory2_10 = 1;
  public final static double tgdCloudCategory2_11 = 1;
  public final static int tgdCloudCategory2_12 = 0;
  public final static String tgdCloudColor1 = "1 1 1";
  public final static String tgdCloudColor2 = "0.2 0.2 0.2";
  public final static int tgdCloudAlt1 = 2000;
  public final static int tgdCloudAlt2 = 5000;
  public final static int tgdCloudDepth1 = 100;
  public final static int tgdCloudDepth2 = 200;
  public final static double tgdCloudDensity1 = 0.01;
  public final static double tgdCloudDensity2 = 0.07;

  // lighting
  public final static int tgdLightingHead1 = 90;
  public final static int tgdLightingHead2 = 180;
  public final static int tgdLightingHead3 = 270;
  public final static int tgdLightingHead4 = 360;
  public final static int tgdLightingElevation1 = 10;
  public final static int tgdLightingElevation2 = 50;
  public final static int tgdLightingElevation3 = 90;

  // camera
  public final static String tgdCameraView1 = "0 1000 -1300";
  public final static String tgdCameraView2 = "0 5000 -1300";

  public final static String tgdCameraHeading1 = "-20 90 0";
  public final static String tgdCameraHeading2 = "-20 180 0";
  public final static String tgdCameraHeading3 = "-20 270 0";
  public final static String tgdCameraHeading4 = "-20 360 0";

  //// TGW values ////

  // lake
  public final static String tgwLakeLevel1 = "shallow";
  public final static String tgwLakeLevel2 = "deep";
  public final static String tgwLakeRadius1 = "narrow";
  public final static String tgwLakeRadius2 = "broad";
  public final static String tgwLakeRoughness1 = "smooth";
  public final static String tgwLakeRoughness2 = "rough";
  public final static String tgwLakeScale1 = "small";
  public final static String tgwLakeScale2 = "big";
  public final static String tgwLakeReflect1 = "low";
  public final static String tgwLakeReflect2 = "high";

  // mountain
  public final static String tgwMountainFeature1 = "smooth";
  public final static String tgwMountainFeature2 = "rough";
  public final static String tgwMountainFlat1 = "flat";
  public final static String tgwMountainFlat2 = "bumpy";

  // surface
  public final static String tgwSurfaceSkin1 = "snow";
  public final static String tgwSurfaceSkin2 = "grass";
  public final static String tgwSurfaceMaxAlt1 = "low";
  public final static String tgwSurfaceMaxAlt2 = "high";
  public final static String tgwSurfaceMaxAlt3 = "none";
  public final static String tgwSurfaceMinAlt1 = "low";
  public final static String tgwSurfaceMinAlt2 = "high";
  public final static String tgwSurfaceMinAlt3 = "none";

  // cloud
  public final static String tgwCloudCategory1 = "Altocumulus";
  public final static String tgwCloudCategory2 = "Cirrus";
  public final static String tgwCloudColour1 = "white";
  public final static String tgwCloudColour2 = "gray";
  public final static String tgwCloudAlt1 = "low";
  public final static String tgwCloudAlt2 = "high";
  public final static String tgwCloudDepth1 = "thin";
  public final static String tgwCloudDepth2 = "thick";
  public final static String tgwCloudDensity1 = "low";
  public final static String tgwCloudDensity2 = "high";

  // lighting
  public final static String tgwLightingHeading1 = "East";
  public final static String tgwLightingHeading2 = "North";
  public final static String tgwLightingHeading3 = "West";
  public final static String tgwLightingHeading4 = "South";
  public final static String tgwLightingElevation1 = "Low";
  public final static String tgwLightingElevation2 = "Medium";
  public final static String tgwLightingElevation3 = "High";

  // camera
  public final static String tgwCameraView1 = "Low";
  public final static String tgwCameraView2 = "High";
  public final static String tgwCameraHeading1 = "East";
  public final static String tgwCameraHeading2 = "North";
  public final static String tgwCameraHeading3 = "West";
  public final static String tgwCameraHeading4 = "South";

  // other constants
  public static LSParser builder;
  public static int indent = 0;
  public static int openedFileNum = 0;

  /**
    Change an element.

    @param root 	root element
    @param nodeName	node to change
    @param value 	value to change to
  */

  public static void changeElem(Element root, String nodeName, String value) {
    NodeList lakeNode = root.getElementsByTagName(nodeName);
    for (int i = 0; i < lakeNode.getLength(); i++) {
      Node aNode = lakeNode.item(0);
      aNode.getFirstChild().setNodeValue(value);
    }
  }

  /**
    Get the extension of a File object.

    @param selectedFile	File	object to get extension
    @return			file extension value
  */

  public static String getFileExtension(File selectedFile) {
    String extension = selectedFile.getAbsolutePath();
    int pos = extension.lastIndexOf('.');
    if (pos == -1)
      return("");
    else
      return(extension.substring(pos + 1));
  }

  /**
    Get the extension of a String object.

    @param path		String to get extension
    @return 		file extension value
  */

  public static String getFileExtension(String path) {
    String extension = path.substring(path.length() - 3, path.length());
    return extension;
  }

  /**
    Change an attribute.

    @param root		root element
    @param nodeName	node to change
    @param attribute	attribute to change
    @param value	value (String) to change to
    @param skipTimes	how many times to skip
  */

  public static void changeAttr(Element root, String nodeName, String attribute, String value, int skipTimes) {
    NodeList lakeNode = root.getElementsByTagName(nodeName);

    for (int i = skipTimes; i < lakeNode.getLength(); i++) {
      Node aNode = lakeNode.item(i);
      NamedNodeMap attributes = aNode.getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals(attribute))
	  theAttribute.setNodeValue(value);
      }
    }
  }

  /**
    Change an attribute.

    @param root		root element
    @param nodeName	node to change
    @param attribute	attribute to change
    @param value	value (int) to change to
    @param skipTimes	how many times to skip
  */

  public static void changeAttr(Element root, String nodeName, String attribute, int value, int skipTimes) {
    NodeList lakeNode = root.getElementsByTagName(nodeName);

    for (int i = skipTimes; i < lakeNode.getLength(); i++) {
      Node aNode = lakeNode.item(i);
      NamedNodeMap attributes = aNode.getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals(attribute))
	  theAttribute.setNodeValue(Integer.toString(value));
      }
    }
  }

  /**
    Change an attribute.

    @param root		root element
    @param nodeName	node to change
    @param attribute	attribute to change
    @param value	value (Double) to change to
    @param skipTimes	how many times to skip
  */

  public static void changeAttr(Element root, String nodeName, String attribute, Double value, int skipTimes) {
    NodeList lakeNode = root.getElementsByTagName(nodeName);

    for (int i = skipTimes; i < lakeNode.getLength(); i++) {
      Node aNode = lakeNode.item(i);
      NamedNodeMap attributes = aNode.getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals(attribute))
	  theAttribute.setNodeValue(Double.toString(value));
      }
    }
  }

  /**
    Check how many elements exist with a node name.

    @param root		root element
    @param nodeName	node name to check
    @return		count with name
  */

  public static int checkNodeExistNum(Element root, String nodeName) {
    NodeList aList = root.getElementsByTagName(nodeName);
    return aList.getLength();
  }

  /**
    Get the value of an attribute.

    @param root		root element
    @param nodeName	node to get
    @param attribute	attribute to get
    @param skipTimes	how many times to skip
    @return		attribute value
  */

  public static String getValue(Element root, String nodeName, String attribute, int skipTimes) {
    NodeList nodes = root.getElementsByTagName(nodeName);

    for (int i = skipTimes; i < nodes.getLength(); i++) {
      Node aNode = nodes.item(i);
      NamedNodeMap attributes = aNode.getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals(attribute))
	  return theAttribute.getNodeValue();
      }
    }
    return null;
  }

  /**
    Write DOM tree to XML file.

    @param dom		document object
    @param fileName 	file name and path to write to
    @return 		true if file successfully written
  */

  public static boolean writeXML(Document dom, String fileName) {
    DOMImplementationRegistry registry;
    try {
      registry = DOMImplementationRegistry.newInstance();
      DOMImplementationLS impl =
	(DOMImplementationLS) registry.getDOMImplementation("LS");
      LSSerializer domWriter = impl.createLSSerializer();
      builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);

      DOMConfiguration config = builder.getDomConfig();
      config = domWriter.getDomConfig();
      config.setParameter("xml-declaration", Boolean.FALSE);

      LSOutput dOut = impl.createLSOutput();
      BufferedWriter output = new BufferedWriter(new FileWriter(fileName));
      dOut.setCharacterStream(output);
      domWriter.write(dom, dOut);
      return true;
    }
    catch (Exception exception) {
      System.err.println("File writing exception - " + exception);
      // exception.printStackTrace();
      return false;
    }
  }

  /**
    Add lake node into DOM.

    @param rootTGD		root of TGD
    @param domTGD		document element of TGD
    @param lakeTGD		lake element
    @param waterShader		water shader element
  */

  public static void enableTGDLakeNodes(Element rootTGD, Document domTGD,
   Element lakeTGD, Element waterShader) {
    lakeTGD = domTGD.createElement("lake");
    waterShader = domTGD.createElement("water_shader");
    lakeTGD.setAttribute("name", "Lake 01");
    lakeTGD.setAttribute("gui_use_node_pos", "1");
    lakeTGD.setAttribute("gui_node_pos", "0 600 0");
    lakeTGD.setAttribute("gui_group", "Water");
    lakeTGD.setAttribute("enable", "1");
    lakeTGD.setAttribute("handle_in_preview", "1");
    lakeTGD.setAttribute("visible_to_camera", "1");
    lakeTGD.setAttribute("visible_to_other_rays", "1");
    lakeTGD.setAttribute("cast_shadows", "0");
    lakeTGD.setAttribute("water_level", "100");
    lakeTGD.setAttribute("centre", "0 100 0");
    lakeTGD.setAttribute("max_radius", "100000");
    lakeTGD.setAttribute("rotate", "0 0 0");
    lakeTGD.setAttribute("import_motion_filename", "");
    lakeTGD.setAttribute("planet", "Planet 01");
    lakeTGD.setAttribute("surface_shader", "Water shader 01");
    waterShader.setAttribute("name", "Water shader 01");
    waterShader.setAttribute("gui_use_node_pos", "1");
    waterShader.setAttribute("gui_node_pos", "0 660 0");
    waterShader.setAttribute("gui_group", "Water");
    waterShader.setAttribute("enable", "1");
    waterShader.setAttribute("input_node", "");
    waterShader.setAttribute("gui_use_preview_patch_size", "0");
    waterShader.setAttribute("gui_preview_patch_size", "1000 1000");
    waterShader.setAttribute("roughness", "0.02");
    waterShader.setAttribute("wave_scale", "10");
    waterShader.setAttribute("smallest_scale", "0.1");
    waterShader.setAttribute("wind_patch_effect", "1");
    waterShader.setAttribute("wind_patch_size", "100");
    waterShader.setAttribute("wind_patch_sharpness", "5");
    waterShader.setAttribute("master_reflectivity", "1");
    waterShader.setAttribute("index_of_refraction", "1.33");
    waterShader.setAttribute("horizon_shift", "0.5");
    waterShader.setAttribute("highlight_intensity", "0.5");
    waterShader.setAttribute("min_highlight_spread", "0.01");
    waterShader.setAttribute("transparency", "0.75");
    waterShader.setAttribute("decay_distance", "10");
    waterShader.setAttribute("decay_tint", "0.75 1 0.5");
    waterShader.setAttribute("volume_1_density", "0");
    waterShader.setAttribute("volume_1_colour", "0.5 0.5 0.5");
    waterShader.setAttribute("volume_1_density_function", "");
    waterShader.setAttribute("volume_1_colour_function", "");
    waterShader.setAttribute("seed", "48532");

    rootTGD.appendChild(lakeTGD);
    rootTGD.appendChild(waterShader);
  }

  /**
    Add mountain node into DOM

    @param rootTGD 		root of TGD
    @param domTGD		document element of TGD
    @param fractalShader	fractal shader element
  */

  public static void enableTGDMountNodes(Element rootTGD, Document domTGD,
   Element fractalShader) {
    fractalShader = domTGD.createElement("power_fractal_shader_v3");
    fractalShader.setAttribute("name", "Fractal terrain 01");
    fractalShader.setAttribute("gui_use_node_pos", "1");
    fractalShader.setAttribute("gui_node_pos", "-920 600 0");
    fractalShader.setAttribute("gui_group", "Terrain");
    fractalShader.setAttribute("enable", "1");
    fractalShader.setAttribute("input_node", "/Heightfield shader 01");
    fractalShader.setAttribute("gui_use_preview_patch_size", "0");
    fractalShader.setAttribute("gui_preview_patch_size", "1000 1000");
    fractalShader.setAttribute("seed", "27349");
    fractalShader.setAttribute("feature_scale", "5000");
    fractalShader.setAttribute("lead-in_scale", "25000");
    fractalShader.setAttribute("smallest_scale", "0.1");
    fractalShader.setAttribute("noise_octaves", "20");
    fractalShader.setAttribute("apply_high_colour", "0");
    fractalShader.setAttribute("high_colour", "1 1 1");
    fractalShader.setAttribute("apply_low_colour", "0");
    fractalShader.setAttribute("low_colour", "0 0 0");
    fractalShader.setAttribute("colour_contrast", "0.5");
    fractalShader.setAttribute("colour_offset", "0");
    fractalShader.setAttribute("colour_roughness", "5");
    fractalShader.setAttribute("clamp_high_colour", "1");
    fractalShader.setAttribute("clamp_low_colour", "1");
    fractalShader.setAttribute("apply_displacement", "1");
    fractalShader.setAttribute("displacement_direction", "1");
    fractalShader.setAttribute("displacement_amplitude", "2000");
    fractalShader.setAttribute("displacement_offset", "0");
    fractalShader.setAttribute("displacement_roughness", "0.875");
    fractalShader.setAttribute("displacement_spike_limit", "0.25");
    fractalShader.setAttribute("continue_spike_limit", "1");
    fractalShader.setAttribute("adjust_coastline", "0");
    fractalShader.setAttribute("coastline_altitude", "0");
    fractalShader.setAttribute("coastline_smoothing", "30");
    fractalShader.setAttribute("noise_flavour", "3");
    fractalShader.setAttribute("noise_variation", "2");
    fractalShader.setAttribute("variation_method", "2");
    fractalShader.setAttribute("buoyancy_from_variation", "0.5");
    fractalShader.setAttribute("clumping_of_variation", "0.25");
    fractalShader.setAttribute("noise_stretch_XYZ", "1 1 1");
    fractalShader.setAttribute("distort_by_normal", "0");
    fractalShader.setAttribute("distortion_by_normal", "5");
    fractalShader.setAttribute("lead-in_warp_effect", "1");
    fractalShader.setAttribute("lead-in_warp_amount", "0.75");
    fractalShader.setAttribute("less_warp_at_feature_scale", "1");
    fractalShader.setAttribute("allow_vertical_warp", "0");
    fractalShader.setAttribute("blend_by_shader", "0");
    fractalShader.setAttribute("blending_shader", "");
    fractalShader.setAttribute("fit_blendshader_to_this", "0");
    fractalShader.setAttribute("invert_blendshader", "0");

    rootTGD.appendChild(fractalShader);
  }

  /**
    Add surface node into DOM.

    @param rootTGD		root of TGD
    @param domTGD		document element of TGD
    @param surfaceLayer		surface layer element
    @param surfaceShader	surface shader element
    @param cboxMountain		mountain checkbox
  */

  public static void enableTGDSurfaceNodes(Element rootTGD, Document domTGD,
   Element surfaceLayer, Element surfaceShader, JCheckBox cboxMountain) {
    surfaceLayer = domTGD.createElement("surface_layer");
    surfaceShader = domTGD.createElement("power_fractal_shader_v3");
    surfaceLayer.setAttribute("name", "Surface layer 01");
    surfaceLayer.setAttribute("gui_use_node_pos", "1");
    surfaceLayer.setAttribute("gui_node_pos", "-920 600 0");
    surfaceLayer.setAttribute("gui_group", "Shaders");
    surfaceLayer.setAttribute("enable", "1");
    surfaceLayer.setAttribute("input_node", "/Base colours");
    surfaceLayer.setAttribute("gui_use_preview_patch_size", "0");
    surfaceLayer.setAttribute("gui_preview_patch_size", "1000 1000");
    surfaceLayer.setAttribute("apply_colour", "1");
    surfaceLayer.setAttribute("diffuse_colour", "0.5 0.5 0.5");
    surfaceLayer.setAttribute("colour_function", "");
    surfaceLayer.setAttribute("luminous", "0");
    surfaceLayer.setAttribute("luminosity_multiplier", "1");
    surfaceLayer.setAttribute("luminosity_tint", "1 1 1");
    surfaceLayer.setAttribute("luminosity_function", "");
    surfaceLayer.setAttribute("displacement_direction", "1");
    surfaceLayer.setAttribute("displacement_multiplier", "1");
    surfaceLayer.setAttribute("displacement_function", "");
    surfaceLayer.setAttribute("displacement_offset", "0");
    surfaceLayer.setAttribute("smoothing_effect", "0");
    surfaceLayer.setAttribute("smoothing_amount", "1");
    surfaceLayer.setAttribute("child_layers", "");
    surfaceLayer.setAttribute("coverage", "1");
    surfaceLayer.setAttribute("fractal_breakup", "1");
    if (!cboxMountain.isSelected())
      surfaceLayer.setAttribute("breakup_shader", "Fractal breakup 01");
    else
      surfaceLayer.setAttribute("breakup_shader", "Fractal terrain 01");

    surfaceLayer.setAttribute("fractal_contrast", "0.5");
    surfaceLayer.setAttribute("invert_breakup", "0");
    surfaceLayer.setAttribute("only_breakup_colour", "1");
    surfaceLayer.setAttribute("blend_by_shader", "0");
    surfaceLayer.setAttribute("blending_shader", "");
    surfaceLayer.setAttribute("invert_blendshader", "0");
    surfaceLayer.setAttribute("blend_as_coverage", "1");
    surfaceLayer.setAttribute("limit_maximum_altitude", "0");
    surfaceLayer.setAttribute("maximum_altitude", "1000");
    surfaceLayer.setAttribute("max_alt_fuzzy_zone", "200");
    surfaceLayer.setAttribute("limit_minimum_altitude", "0");
    surfaceLayer.setAttribute("minimum_altitude", "200");
    surfaceLayer.setAttribute("min_alt_fuzzy_zone", "200");
    surfaceLayer.setAttribute("use_Y_for_altitude", "0");
    surfaceLayer.setAttribute("limit_maximum_slope", "0");
    surfaceLayer.setAttribute("maximum_slope_angle", "60");
    surfaceLayer.setAttribute("max_slope_fuzzy_zone", "20");
    surfaceLayer.setAttribute("limit_minimum_slope", "0");
    surfaceLayer.setAttribute("minimum_slope_angle", "30");
    surfaceLayer.setAttribute("min_slope_fuzzy_zone", "10");
    surfaceLayer.setAttribute("use_Y_for_slope", "0");
    surfaceLayer.setAttribute("slope_key", "0");
    surfaceLayer.setAttribute("intersect_underlying", "0");
    surfaceLayer.setAttribute("intersection_mode", "0");
    surfaceLayer.setAttribute("intersection_zone", "2");
    surfaceLayer.setAttribute("smoothing_scale", "0");
    surfaceLayer.setAttribute("intersection_shift", "2");
    surfaceLayer.setAttribute("min_intersection_shift", "-2");
    surfaceLayer.setAttribute("fuzzy_zone_softness", "1");

    surfaceShader.setAttribute("name", "Fractal breakup 01");
    surfaceShader.setAttribute("gui_use_node_pos", "1");
    surfaceShader.setAttribute("gui_node_pos", "-720 280 0");
    surfaceShader.setAttribute("gui_group", "Shaders");
    surfaceShader.setAttribute("enable", "1");
    surfaceShader.setAttribute("input_node", "");
    surfaceShader.setAttribute("gui_use_preview_patch_size", "0");
    surfaceShader.setAttribute("gui_preview_patch_size", "1000 1000");
    surfaceShader.setAttribute("seed", "14437");
    surfaceShader.setAttribute("feature_scale", "1");
    surfaceShader.setAttribute("lead-in_scale", "1000");
    surfaceShader.setAttribute("smallest_scale", "0.1");
    surfaceShader.setAttribute("noise_octaves", "15");
    surfaceShader.setAttribute("apply_high_colour", "1");
    surfaceShader.setAttribute("high_colour", "1 1 1");
    surfaceShader.setAttribute("apply_low_colour", "0");
    surfaceShader.setAttribute("low_colour", "0 0 0");
    surfaceShader.setAttribute("colour_contrast", "0.5");
    surfaceShader.setAttribute("colour_offset", "0");
    surfaceShader.setAttribute("colour_roughness", "5");
    surfaceShader.setAttribute("clamp_high_colour", "0");
    surfaceShader.setAttribute("clamp_low_colour", "0");
    surfaceShader.setAttribute("apply_displacement", "0");
    surfaceShader.setAttribute("displacement_direction", "1");
    surfaceShader.setAttribute("displacement_amplitude", "1");
    surfaceShader.setAttribute("displacement_offset", "0");
    surfaceShader.setAttribute("displacement_roughness", "1");
    surfaceShader.setAttribute("displacement_spike_limit", "1");
    surfaceShader.setAttribute("continue_spike_limit", "0");
    surfaceShader.setAttribute("adjust_coastline", "0");
    surfaceShader.setAttribute("coastline_altitude", "0");
    surfaceShader.setAttribute("coastline_smoothing", "30");
    surfaceShader.setAttribute("noise_flavour", "0");
    surfaceShader.setAttribute("noise_variation", "1");
    surfaceShader.setAttribute("variation_method", "2");
    surfaceShader.setAttribute("buoyancy_from_variation", "0");
    surfaceShader.setAttribute("clumping_of_variation", "0.25");
    surfaceShader.setAttribute("noise_stretch_XYZ", "1 1 1");
    surfaceShader.setAttribute("distort_by_normal", "1");
    surfaceShader.setAttribute("distortion_by_normal", "5");
    surfaceShader.setAttribute("lead-in_warp_effect", "1");
    surfaceShader.setAttribute("lead-in_warp_amount", "1");
    surfaceShader.setAttribute("less_warp_at_feature_scale", "0");
    surfaceShader.setAttribute("allow_vertical_warp", "0");
    surfaceShader.setAttribute("blend_by_shader", "0");
    surfaceShader.setAttribute("blending_shader", "");
    surfaceShader.setAttribute("fit_blendshader_to_this", "0");
    surfaceShader.setAttribute("invert_blendshader", "0");

    rootTGD.appendChild(surfaceLayer);
    rootTGD.appendChild(surfaceShader);
  }

  /**
    Add cloud node into DOM

    @param rootTGD 		root of TGD
    @param domTGD		document element of TGD
    @param cloudLayer 		cloud layer element
    @param cloudShader		cloud shader element
  */

  public static void enableTGDCloudNodes(Element rootTGD, Document domTGD, Element cloudLayer, Element cloudShader) {
    cloudLayer = domTGD.createElement("cloud_layer_v2");
    cloudShader = domTGD.createElement("cloud_fractal_shader_v3");
    cloudLayer.setAttribute("name", "Altocumulus layer 01");
    cloudLayer.setAttribute("gui_use_node_pos", "1");
    cloudLayer.setAttribute("gui_node_pos", "-920 600 0");
    cloudLayer.setAttribute("gui_group", "Atmosphere");
    cloudLayer.setAttribute("enable", "1");
    cloudLayer.setAttribute("input_node", "/Atmosphere 01");
    cloudLayer.setAttribute("gui_use_preview_patch_size", "0");
    cloudLayer.setAttribute("gui_preview_patch_size", "1000 1000");
    cloudLayer.setAttribute("enable_primary", "1");
    cloudLayer.setAttribute("enable_secondary", "1");
    cloudLayer.setAttribute("centre", "0 -6.378e+006 0");
    cloudLayer.setAttribute("radius", "6.378e+006");
    cloudLayer.setAttribute("seed", "0");
    cloudLayer.setAttribute("cloud_altitude", "4237");
    cloudLayer.setAttribute("cloud_depth", "150");
    cloudLayer.setAttribute("density_shader", "Density fractal 01");
    cloudLayer.setAttribute("edge_sharpness", "1");
    cloudLayer.setAttribute("cloud_density", "0.01");
    cloudLayer.setAttribute("coverage_adjust", "0");
    cloudLayer.setAttribute("cloud_colour", "0.35 0.35 0.35");
    cloudLayer.setAttribute("scattering_colour", "0.5 0.5 0.5");
    cloudLayer.setAttribute("sun_glow_amount", "1.5");
    cloudLayer.setAttribute("sun_glow_power", "0.75");
    cloudLayer.setAttribute("light_propagation", "2");
    cloudLayer.setAttribute("light_propagation_mix", "0.125");
    cloudLayer.setAttribute("fake_internal_scattering", "0.25");
    cloudLayer.setAttribute("enviro_light", "1");
    cloudLayer.setAttribute("enviro_light_tint", "1 1 1");
    cloudLayer.setAttribute("ambient", "0 0 0");
    cloudLayer.setAttribute("fake_dark_power", "0");
    cloudLayer.setAttribute("fake_dark_sharpness", "10");
    cloudLayer.setAttribute("improved_lighting_model", "1");
    cloudLayer.setAttribute("flatter_base", "0");
    cloudLayer.setAttribute("invert_profile", "0");
    cloudLayer.setAttribute("base_wispiness", "0");
    cloudLayer.setAttribute("base_softness", "0");
    cloudLayer.setAttribute("coverage_gamma", "1");
    cloudLayer.setAttribute("rendering_method", "1");
    cloudLayer.setAttribute("quality", "0.289898");
    cloudLayer.setAttribute("number_of_samples", "6");
    cloudLayer.setAttribute("sample_jitter", "1");
    cloudLayer.setAttribute("acceleration_cache", "2");
    cloudLayer.setAttribute("enable_ray_traced_shadows", "0");

    cloudShader.setAttribute("name", "Density fractal 01");
    cloudShader.setAttribute("gui_use_node_pos", "1");
    cloudShader.setAttribute("gui_node_pos", "200 280 0");
    cloudShader.setAttribute("gui_group", "Atmosphere");
    cloudShader.setAttribute("enable", "1");
    cloudShader.setAttribute("input_node", "");
    cloudShader.setAttribute("gui_use_preview_patch_size", "0");
    cloudShader.setAttribute("gui_preview_patch_size", "1000 1000");
    cloudShader.setAttribute("seed", "45822");
    cloudShader.setAttribute("feature_scale", "150");
    cloudShader.setAttribute("lead-in_scale", "20000");
    cloudShader.setAttribute("smallest_scale", "10");
    cloudShader.setAttribute("noise_octaves", "13");
    cloudShader.setAttribute("apply_high_colour", "1");
    cloudShader.setAttribute("high_colour", "1 1 1");
    cloudShader.setAttribute("apply_low_colour", "0");
    cloudShader.setAttribute("low_color", "0 0 0");
    cloudShader.setAttribute("contrast", "1");
    cloudShader.setAttribute("coverage_adjust", "0");
    cloudShader.setAttribute("roughness", "1.75");
    cloudShader.setAttribute("clamp_high", "0");
    cloudShader.setAttribute("clamp_low", "0");
    cloudShader.setAttribute("apply_displacement", "0");
    cloudShader.setAttribute("displacement_direction", "1");
    cloudShader.setAttribute("displacement_amplitude", "1");
    cloudShader.setAttribute("displacement_offset", "0");
    cloudShader.setAttribute("displacement_roughness", "1");
    cloudShader.setAttribute("displacement_spike_limit", "1");
    cloudShader.setAttribute("continue_spike_limit", "0");
    cloudShader.setAttribute("adjust_coastline", "0");
    cloudShader.setAttribute("coastline_altitude", "0");
    cloudShader.setAttribute("coastline_smoothing", "30");
    cloudShader.setAttribute("noise_flavour", "0");
    cloudShader.setAttribute("noise_variation", "1");
    cloudShader.setAttribute("variation_method", "2");
    cloudShader.setAttribute("buoyancy_from_variation", "0.5");
    cloudShader.setAttribute("clumping_of_variation", "0.25");
    cloudShader.setAttribute("noise_stretch_XYZ", "1 1 1");
    cloudShader.setAttribute("distort_by_normal", "0");
    cloudShader.setAttribute("distortion_by_normal", "5");
    cloudShader.setAttribute("lead-in_warp_effect", "1");
    cloudShader.setAttribute("lead-in_warp_amount", "0.5");
    cloudShader.setAttribute("less_warp_at_feature_scale", "1");
    cloudShader.setAttribute("allow_vertical_warp", "1");
    cloudShader.setAttribute("blend_by_shader", "0");
    cloudShader.setAttribute("blending_shader", "");
    cloudShader.setAttribute("fit_blendshader_to_this", "0");
    cloudShader.setAttribute("invert_blendshader", "0");

    rootTGD.appendChild(cloudLayer);
    rootTGD.appendChild(cloudShader);
  }

  /**
    Remove lake node from DOM.

    @param rootTGD	root of TGD
  */

  public static void disableTGDLakeNodes(Element rootTGD) {
    NodeList aList = rootTGD.getElementsByTagName("lake");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGD.removeChild(aList.item(i));

    NodeList aList1 = rootTGD.getElementsByTagName("water_shader");
    for (int i = 0; i < aList1.getLength(); i++)
      rootTGD.removeChild(aList1.item(i));
  }

  /**
    Remove mountain node from DOM.

    @param rootTGD	root of TGD
  */

  public static void disableTGDMountNodes(Element rootTGD) {
    NodeList aList = rootTGD.getElementsByTagName("power_fractal_shader_v3");
    for (int i = 0; i < aList.getLength(); i++) {
      NamedNodeMap attributes = aList.item(i).getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals("gui_group") &&
	  theAttribute.getNodeValue().equals("Terrain"))
	  rootTGD.removeChild(aList.item(i));
      }
    }
    Common.changeAttr(rootTGD, "compute_terrain", "input_node",
      "Heightfield shader 01", 0);
  }

  /**
    Remove surface node from DOM.

    @param rootTGD	root of TGD
  */

  public static void disableTGDSurfaceNodes(Element rootTGD) {
    NodeList aList = rootTGD.getElementsByTagName("surface_layer");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGD.removeChild(aList.item(i));

    NodeList aList1 = rootTGD.getElementsByTagName("power_fractal_shader_v3");
    for (int i = 1; i < aList1.getLength(); i++) {
      NamedNodeMap attributes = aList1.item(i).getAttributes();
      for (int j = 0; j < attributes.getLength(); j++) {
	Node theAttribute = attributes.item(j);
	if (theAttribute.getNodeName().equals("gui_group") &&
	  theAttribute.getNodeValue().equals("Shaders"))
	  rootTGD.removeChild(aList1.item(i));
      }
    }
    Common.changeAttr(rootTGD, "planet", "surface_shader", "Base colours", 0);
  }

  /**
    Remove cloud node from DOM.

    @param rootTGD	root of TGD
  */

  public static void disableTGDCloudNodes(Element rootTGD) {
    NodeList aList = rootTGD.getElementsByTagName("cloud_layer_v2");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGD.removeChild(aList.item(i));

    NodeList aList1 = rootTGD.getElementsByTagName("cloud_fractal_shader_v3");
    for (int i = 0; i < aList1.getLength(); i++)
      rootTGD.removeChild(aList1.item(i));

    Common.changeAttr(rootTGD, "planet", "atmosphere_shader", "Atmosphere 01", 0);
  }

  /**
    Add lake node into DOM.

    @param rootTGW	root of TGW
    @param domTGW	document element of TGW
    @param lakeTGW	lake TGW element
  */

  public static void enableTGWLakeNodes(Element rootTGW, Document domTGW,
   Element lakeTGW) {
    lakeTGW = domTGW.createElement("lake");
    lakeTGW.setAttribute("water_level", Common.tgwLakeLevel1);
    lakeTGW.setAttribute("max_radius", Common.tgwLakeRadius1);
    lakeTGW.setAttribute("roughness", Common.tgwLakeRoughness1);
    lakeTGW.setAttribute("wave_scale", Common.tgwLakeScale1);
    lakeTGW.setAttribute("reflectivity", Common.tgwLakeReflect1);

    rootTGW.appendChild(lakeTGW);
  }

  /**
    Add mountain node into DOM.

    @param rootTGW	root of TGW
    @param domTGW	document element of TGW
    @param mountain	mountain element
  */

  public static void enableTGWMountNodes(Element rootTGW, Document domTGW, Element mountain) {
    mountain = domTGW.createElement("mountain");
    mountain.setAttribute("feature_scale", Common.tgwMountainFeature1);
    mountain.setAttribute("flat", Common.tgwMountainFlat1);

    rootTGW.appendChild(mountain);
  }

  /**
    Add surface node into DOM.

    @param rootTGW	root of TGW
    @param domTGW	document element of TGW
    @param surface	surface element
  */

  public static void enableTGWSurfaceNodes(Element rootTGW, Document domTGW, Element surface) {
    surface = domTGW.createElement("surface");
    surface.setAttribute("skin", Common.tgwSurfaceSkin2);
    surface.setAttribute("maxAlt", Common.tgwSurfaceMaxAlt3);
    surface.setAttribute("minAlt", Common.tgwSurfaceMinAlt3);

    rootTGW.appendChild(surface);
  }

  /**
    Add cloud node into DOM.

    @param rootTGW	root of TGW
    @param domTGW	document element of TGW
    @param cloud	cloud element
  */

  public static void enableTGWCloudNodes(Element rootTGW, Document domTGW, Element cloud) {
    cloud = domTGW.createElement("cloud");
    cloud.setAttribute("category", Common.tgwCloudCategory1);
    cloud.setAttribute("colour", Common.tgwCloudColour1);
    cloud.setAttribute("altitude", Common.tgwCloudAlt1);
    cloud.setAttribute("depth", Common.tgwCloudDepth1);
    cloud.setAttribute("density", Common.tgwCloudDensity1);

    rootTGW.appendChild(cloud);
  }

  /**
    Remove lake node from DOM.

    @param rootTGW	root of TGW
  */

  public static void disableTGWLakeNodes(Element rootTGW) {
    NodeList aList = rootTGW.getElementsByTagName("lake");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGW.removeChild(aList.item(i));
  }

  /**
    Remove mountain node from DOM.

    @param rootTGW	root of TGW
  */

  public static void disableTGWMountNodes(Element rootTGW) {
    NodeList aList = rootTGW.getElementsByTagName("mountain");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGW.removeChild(aList.item(i));
  }

  /**
    Remove surface node from DOM.

    @param rootTGW	root of TGW
  */

  public static void disableTGWSurfaceNodes(Element rootTGW) {
    NodeList aList = rootTGW.getElementsByTagName("surface");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGW.removeChild(aList.item(i));
  }

  /**
    Remove cloud node from DOM.

    @param rootTGW	root of TGW
  */

  public static void disableTGWCloudNodes(Element rootTGW) {
    NodeList aList = rootTGW.getElementsByTagName("cloud");
    for (int i = 0; i < aList.getLength(); i++)
      rootTGW.removeChild(aList.item(i));
  }

}

