function Gem(vector_ID)
{
   this.RetrieveInfoFromVector = gem_RetrieveInfoFromVector;
   this.RetrieveInfoGemModel = gem_RetrieveInfoGemModel;
   this.ShapeFromFile = gem_ShapeFromFile;
   this.SetPositionFromRelief = gem_SetPositionFromRelief; 
   this.PositionAroundRing = gem_PositionAroundRing;
   this.RetrieveInfoFromVectorObject = gem_RetrieveInfoFromVectorObject;
   this.StoreInfoInVector = gem_StoreInfoInVector;
   this.StoreInfoInVectorObject = gem_StoreInfoInVectorObject;
   this.WriteParamsSelectionHTML = gem_WriteParamsSelectionHTML;
   this.WriteColourSelectionHTML = gem_WriteColourSelectionHTML;
   this.WriteShapeSelectionHTML = gem_WriteShapeSelectionHTML;
   this.WriteSummaryHTML = gem_WriteSummaryHTML;
   this.WriteNavigationButtons = gem_WriteNavigationButtons;

   this.GemIconPath = artcam.HtmlRootDir + "../SharedImages/JewelSmith/GemIcon.gif";

   this.GetNextPropertyPage = gem_GetNextPropertyPage
   this.OnBackButton = gem_OnBackButton;
   this.OnClose = gem_OnClose;

   this.OnSelectType = gem_OnSelectType;
   this.OnSelectColour = gem_OnSelectColour;
   this.OnSetParams = gem_OnSetParams;
   this.OnAcceptChanges = gem_OnAcceptChanges;

   this.DrawVector = gem_DrawVector;

   this.GetReferenceAngle = gem_GetReferenceAngle;

   this.CreateModel = gem_CreateModel;
   this.UpdateGemModel = gem_UpdateGemModel;

   this.OnSizeSelect = gem_OnSizeSelect;
   this.OnStandardSelect = gem_OnStandardSelect;

   this.GetGemVectorLayer = gem_GetGemVectorLayer;
   
   this.DimensionsEdited = gem_DimensionsEdited;

   this.CallbackFunction = "";
   this.TargetDiv  = "";  // Into which all the gem HTML is written
   this.CallingDiv = "";  // Is hidden and only displayed when gem parameter has been set
   //this.ParentDiv  = "";  // Top level div that is displayed if setting gems is cancelled

   this.NextPage ="none"; // Keep track of current property being set (i.e. Shape, Colour, Size)
   this.PreviousPage ="none"; // Keep track of current property being set (i.e. Shape, Colour, Size)
 
   if(typeof(vector_ID)!='undefined')
   {
      this.RetrieveInfoFromVector(vector_ID);
   }
   else
   {
      this.Name = "";
      this.Shape = "";
      this.Width = 2;
      this.Length = 2;
      this.Depth = this.Width*0.42;
      this.Pavilion = 2;

      this.WidthEdit = null;
      this.LengthEdit = null;
      this.DepthEdit = null;

      this.DiffuseRed   = 255;
      this.DiffuseGreen = 255;
      this.DiffuseBlue  = 255;
      this.AmbientRed   = 127;
      this.AmbientGreen = 127;
      this.AmbientBlue  = 127;
      
      this.XPosition = 0;
      this.YPosition = 0;
      this.ZPosition = 0;

      this.XRotation = 0;
      this.YRotation = 0;
      this.ZRotation = 0;

      this.Workplane = null;

      this.InitialAngleReference = 0; // Starting angle (degs) between startpoint and centre for reference

      this.GemModel = null;
      this.VectorID = "";

      this.WizardMode = true;
   }
}

function gem_DrawVector()
{
   var vector;
   var vector_ID;
   switch(this.Shape)
   {
   case "Round":
   case "Brilliant":
   case "Oval":
      artcam.DrawEllipse(0.0, 0.0, this.Width/2, this.Length/2,0, false);
      vector = artcam.VectorSelection.Item(0);
      vector_ID = vector.VectorID;
      break;     
   case "Princess":
      artcam.Drawing.Rectangle(0.0, 0.0, this.Width/2, this.Length/2, false,0,0);
      vector = artcam.VectorSelection.Item(0);
      vector_ID = vector.VectorID;
      break;
   case "Emerald":
      vector = DrawBoxRadiantVector(this.Width, this.Width*0.25);
      vector_ID = vector.VectorID;
      break;
   case "BoxRadiant":
      vector = DrawBoxRadiantVector(this.Width, this.Width*0.25);
      vector_ID = vector.VectorID;
      break;
   case "Marquise":
      vector = DrawMarquiseVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   case "Heart":
      vector = DrawHeartVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   case "Pear":
      vector = DrawPearVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   case "Triangle":
      vector = DrawTriangleVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   case "Trillion":
      vector = DrawTrillionVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   case "Hexagon":
      vector = DrawHexagonVector(this.Width, this.Length);
      vector_ID = vector.VectorID;
      break;
   default:
      artcam.Alert("gem_DrawVector: Unknown Shape - " + this.Shape,0);
      return null;
   }


   // If we have certain variables set then we have to transform the vectors after drawing
   artcam.SelectedVectorID = vector_ID;
   artcam.TransformVectorsAnchorCopy(this.XPosition, this.YPosition, // Position
                                     1.0, 1.0,                       // Scale
                                     this.ZRotation,                 // Angle (Rad)
                                     0.0, 0.0,                       // Shear
                                     0.0, 0.0,                       // About point
                                     false);                         // Make a copy

   this.VectorID = vector_ID;
   this.InitialAngleReference = this.GetReferenceAngle(vector);
   this.StoreInfoInVector(vector_ID);
   return vector_ID;
}

function gem_CreateModel()
{
   switch(this.Shape)
   {
   case "Round":
      this.GemModel = artcam.CreateGem("Round.stl",this.Name);
      break;
   case "Brilliant":
      this.GemModel = artcam.CreateGem("Brilliant.stl",this.Name);
      break;
   case "Princess":
      this.GemModel = artcam.CreateGem("Princess.stl",this.Name);
      break;
   case "BoxRadiant":
      this.GemModel = artcam.CreateGem("BoxRadiant.stl",this.Name);
      break;
   case "Pear":
      this.GemModel = artcam.CreateGem("Pear.stl",this.Name);
      break;
   case "Marquise":
      this.GemModel = artcam.CreateGem("Marquise.stl",this.Name);
      break;
   case "Heart":
      this.GemModel = artcam.CreateGem("Heart.stl",this.Name);
      break;
   case "Oval":
      this.GemModel = artcam.CreateGem("Oval.stl",this.Name);
      break;
   case "Triangle":
      this.GemModel = artcam.CreateGem("Triangle.stl",this.Name);
      break;
   case "Hexagon":
      this.GemModel = artcam.CreateGem("Hexagon.stl",this.Name);
      break;
   case "Trillion":
      this.GemModel = artcam.CreateGem("Trillion.stl",this.Name);
      break;
   case "Emerald":
      this.GemModel = artcam.CreateGem("Emerald.stl",this.Name);
      break;
   default:
      artcam.Alert("Unknown Gem Shape: " + this.Shape,0);
   }

   if(this.GemModel==null)
   {
      artcam.Alert("Failed to create Gem: " + this.Shape,0);
      return null;
   }

   //this.GemModel.Name = this.Shape;
   this.GemModel.Name = this.Name;
   this.UpdateGemModel();
   this.GemModel.Visible = true;
   return this.GemModel;
}

function gem_ShapeFromFile(file)
{
   switch(file)
   {
   case "Round.stl":           return "Round";
   case "Brilliant.stl":       return "Brilliant";
   case "Princess.stl":        return "Princess";
   case "BoxRadiant.stl":      return "BoxRadiant";
   case "Pear.stl":            return "Pear";
   case "Marquise.stl":        return "Marquise";
   case "Heart.stl":           return "Heart";
   case "Oval.stl":            return "Oval";
   case "Triangle.stl":        return "Triangle";
   case "Hexagon.stl":         return "Hexagon";
   case "Trillion.stl":        return "Trillion";
   case "Emerald.stl":         return "Emerald";
   default:
      return ""; // Unknown Gem File
   }
}


function gem_UpdateGemModel()
{
   if(this.GemModel==null)
   {
      artcam.Alert("No Gem Model Available",0);
      return;
   }

   if( this.Workplane != null )
   {
      // Transform according to the work plane and then rotate in Z
      this.GemModel.SetWorkplane(this.Workplane);
      this.GemModel.Transform(
         0,0,0,
         1,1,1,
         0,0,this.ZRotation,
         0,0,0,
         true,false);
   }
   else
   {
      //alert("workplane is null");
      this.GemModel.Transform(
         this.XPosition,
         this.YPosition,
         this.ZPosition,
         1,1,1,
         0,0,0,
         0,0,0,
         false,false);

      this.GemModel.Transform(
         0,0,0,
         1,1,1,
         this.XRotation,this.YRotation,this.ZRotation,
         0,0,0,
         true,false);
   }

   this.GemModel.DiffuseRed   = this.DiffuseRed;
   this.GemModel.DiffuseGreen = this.DiffuseGreen;
   this.GemModel.DiffuseBlue  = this.DiffuseBlue;
   this.GemModel.AmbientRed   = this.AmbientRed;
   this.GemModel.AmbientGreen = this.AmbientGreen;
   this.GemModel.AmbientBlue  = this.AmbientBlue;

   this.GemModel.SetWidthHeightAndDepth(this.Width, this.Length ,this.Depth);
}

function gem_RetrieveInfoFromVector(vector_ID)
{
   var vector = artcam.GetVectorObjectWithId(vector_ID);
   if(typeof(vector) != 'object')
   {
      artcam.Alert("RetrieveGemInfoInVector: Couldn't find vector",0);
      return false;
   }
   this.RetrieveInfoFromVectorObject(vector);
}

function gem_RetrieveInfoFromVectorObject(vector)
{
   if(typeof(vector) != 'object')
   {
      artcam.Alert("gem_RetrieveInfoFromVectorObject: Couldn't find vector",0);
      return false;
   }
   
   for (var props in this)
   {
      var label = "geminfo_" + props;
      if(typeof(this[props]) == "string")
      {
         if(vector.StringExists(label))
         {
            //alert("Found " + label);
            this[props] = vector.GetString(label, "Unspecified");
         }
         
      }
      if(typeof(this[props]) == "number")
      {
         if(vector.DoubleExists(label))
         {
            //alert("Found " + label);
            this[props] = vector.GetDouble(label, 0);
         }
      }
   }

   this.ZRotation = this.InitialAngleReference - this.GetReferenceAngle(vector);
   this.VectorID = vector.VectorID;
   this.XPosition = vector.Centre.X + artcam.CurrentModel.XPosition;
   this.YPosition = vector.Centre.Y + artcam.CurrentModel.YPosition;
}


function gem_StoreInfoInVector(vector_ID)
{
   var vector = artcam.GetVectorObjectWithId(vector_ID);
   if(typeof(vector) != 'object')
   {
      artcam.Alert("StoreGemInfoInVector: Couldn't find vector",0);
      return false;
   }
   this.StoreInfoInVectorObject(vector);
}


   
function gem_StoreInfoInVectorObject(vector)
{
   if(typeof(vector) != 'object')
   {
      artcam.Alert("gem_RetrieveInfoFromVectorObject: Couldn't find vector",0);
      return false;
   }
   
   //var msg = "";
   for (var props in this)
   {
      var label = "geminfo_" + props;
      if(typeof(this[props]) == "string")
      {
         vector.SetString(label, this[props]);
         //msg += label + " = " + this[props] + "\n";
      }
      if(typeof(this[props]) == "number")
      {
         vector.SetDouble(label, this[props]);
         //msg += label + " = " + this[props] + "\n";
      }
   }
   //alert(msg);
}

function gem_WriteParamsSelectionHTML(page)
{
   this.TargetDiv.style.display = "";
   this.CallingDiv.style.display = "none";

   this.OnFinish = this.OnSetParams;
   if(this.WizardMode)
   {
      this.NextPage = "colour";
      this.PreviousPage = "shape";         
   }
   else if(typeof(page)=='string')
   {
      this.PreviousPage = page;         
   }

   //this.PropertyPage = "params";

   var hArr = new Array();
   // Add the back button HTML to the array

   hArr.push("<table width='100%' border=0 cellspacing=0 style='table-layout:auto'>");
   hArr.push("<colgroup><col width=40px><col width=60%><col width=40%></colgroup>");
   hArr.push("<tr><td rowspan=5 valign=top ><img valign=top src='"+ this.GemIconPath + "'></td>");
   hArr.push("<td style='display:none' id=size_standard_row>" + gGemStandard + ":</td><td><div id=size_standard_select onselect='globalStore.ActiveGem.OnStandardSelect()' style='width:120px;display:none'></div></td></tr>");
   hArr.push("<tr><td style='display:none' id=size_options_row>" + gGemSize + ":</td><td><div id=size_options_select onselect='globalStore.ActiveGem.OnSizeSelect()' style='width:120px;display:none'></div></td></tr>");
   hArr.push("<tr><td>" + gGemLength + ":</td><td><input type=edit size=5 maxLength=6 number dp='3' value=2 id=LengthEdit onkeyup='globalStore.ActiveGem.DimensionsEdited()'></td></tr>");
   hArr.push("<tr><td>" + gGemWidth + ":</td><td><input type=edit size=5 maxLength=6 number dp='3' value=2 id=WidthEdit onkeyup='globalStore.ActiveGem.DimensionsEdited()'></td></tr>");
   hArr.push("<tr><td>" + gGemDepth + ":</td><td><input type=edit size=5 maxLength=6 number dp='3' value=2 id=DepthEdit onkeyup='globalStore.ActiveGem.DimensionsEdited()'></td></tr>");
   
   if( this.AddColourChangeButton )
      hArr.push("<tr><td></td><td><input type=button value='" + gGemEditColour + "' onclick=globalStore.ActiveGem.WriteColourSelectionHTML()></td></tr>");


   hArr.push("</table>");

   this.WriteNavigationButtons(hArr);

   // Bung all our HTML into the div and display it
   this.TargetDiv.innerHTML = hArr.join("\n");

   // initialise all the 'special' objects
   InitialiseButtonDivs();
   SubclassNumberEditControls();

   PromoteDivToSelect(size_standard_select);
   PromoteDivToSelect(size_options_select);
   // Keep a global reference to the edit controls
   this.WidthEdit = eval(WidthEdit);
   this.LengthEdit = eval(LengthEdit);
   this.DepthEdit = eval(DepthEdit);
   this.SizeStandardSelect = eval(size_standard_select);
   this.SizeOptionsSelect = eval(size_options_select);

   var DirSelector = artcam.CreateFileSelector();

   var dir_path = artcam.HtmlRootDir + "../GemLibrary/GemWeights/" + this.Shape + "/";
   var path_exists = DirSelector.DirectoryExists(dir_path);
   if (path_exists || this.SizeFromVectorOption)
   {
      size_standard_select.style.display="";
      size_standard_row.style.display="";
      if( path_exists )
      {
         size_options_select.style.display="";
         size_options_row.style.display="";
         FillSelectFromTextFileNames(this.SizeStandardSelect, dir_path, gCustom);
      }
      else
         this.SizeStandardSelect.AddRow(gCustom,"",gCustom);

      // If we have the size from Vector Option requested, add it to the list
      if(this.SizeFromVectorOption)
         this.SizeStandardSelect.AddRow("<NOBR>"+gGemSizeFromVector+"</NOBR>","",gGemSizeFromVector);
      
//      this.SizeStandardSelect.SetSelectedIndex(this.SizeStandardSelect.GetRowCount()-1);
      // Select the 'Carat' size option by default which is the first on the list
      this.SizeStandardSelect.SetSelectedIndex(0);
      this.OnStandardSelect();
   }
   
   // Set their values from the this object
   this.WidthEdit.setValue(this.Width);
   this.LengthEdit.setValue(this.Length);
   this.DepthEdit.setValue(this.Depth);
}

function gem_WriteColourSelectionHTML(page)
{
   var image_size = 50;
   var column_count = 3;
   var gemshape_library_path = artcam.HtmlRootDir + "../GemLibrary/GemColours";

   this.TargetDiv.style.display = "";
   this.CallingDiv.style.display = "none";

   this.OnFinish = this.OnSetParams;
   if(this.WizardMode)
   {
      this.NextPage = "";
      this.PreviousPage = "params";         
   }
   else if(typeof(page)=='string')
   {
      this.PreviousPage = page;         
   }

   //this.PropertyPage = "colour";

   var splitpath = artcam.CreateSplitPath(gemshape_library_path);
   if( splitpath == null )
      return; // If we can't create it we ignore this directory

   // Now loop through all the files in this directory
   var dirList = artcam.CreateDirectoryList(gemshape_library_path);
   dirList.StartList("*.gif"); // Enumerate ALL items. '*' wild card matches everything

   var hArr = new Array();
   hArr.push("<table border=0 width=100% style='margin-left:1px;text-align:center;table-layout:fixed'>");
   hArr.push("<colgroup>");
   for(var index = 0;index<column_count;index++)
   {
      //hArr.push("<col width="+ 100/column_count +"%>");
      hArr.push("<col width=55>");
   }
   hArr.push("</colgroup>");

   var col_index = 0;
   while( dirList.ItemIsValid() )
   {
      splitpath.Path = dirList.ItemPath;
      if(col_index == 0)
      {
         hArr.push("<tr><td>");
      }
      else
      {
         hArr.push("<td>");
      }
      hArr.push("<div class='mouseOut'");
      hArr.push("button_name='" + dirList.ItemPath + "' ");
      hArr.push("targetFunction = 'globalStore.ActiveGem.OnSelectColour' ");
      hArr.push("functionArgs ='" + dirList.ItemPath + "'>");
      hArr.push("<img src='"+dirList.ItemPath+"' align=absmiddle border=0 width="+image_size+" height="+image_size+"><br>");

      // Gets atext name if it exists
      hArr.push(GetPluginTitle(splitpath.Path, false));

      hArr.push("</div>");

      if(col_index >= column_count-1)
      {
         hArr.push("</td></tr>");
         col_index=0;
      }
      else
      {
         hArr.push("</td>");
         col_index++;
      }
      dirList.NextItem();
   }
   
   if(col_index <= column_count-1)
      hArr.push("</tr>");
   
   hArr.push("</table>");

   hArr.push("<div class='mouseOut' button_name='gem_colour_back_button' targetFunction='globalStore.ActiveGem.OnBackButton' style='width=30px;float:right;'>");
   hArr.push("<img alt =" + gBackButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/back.gif' align=absmiddle border=0 width=30 height=30>");
   hArr.push("</div>");

   this.TargetDiv.innerHTML = hArr.join("\n");
   InitialiseButtonDivs();
}

function gem_WriteShapeSelectionHTML(page)
{
   var image_size = 50;
   var column_count = 3;
   var gemshape_library_path = artcam.HtmlRootDir + "../GemLibrary/GemShapes";

   this.TargetDiv.style.display = "";
   this.CallingDiv.style.display = "none";

   this.OnFinish = this.OnSetParams;
   if(this.WizardMode)
   {
      this.NextPage = "params";
      this.PreviousPage = "";         
   }
   else if(typeof(page)=='string')
   {
      this.PreviousPage = page;         
   }

   //this.PropertyPage = "shape";

   var splitpath = artcam.CreateSplitPath(gemshape_library_path);
   if( splitpath == null )
      return; // If we can't create it we ignore this directory

   // Now loop through all the files in this directory
   var dirList = artcam.CreateDirectoryList(gemshape_library_path);
   dirList.StartList("*.gif"); // Enumerate ALL items. '*' wild card matches everything

   var hArr = new Array();
   hArr.push("<table border=0 width=100% style='margin-left:1px;text-align:center;table-layout:fixed'>");
   hArr.push("<colgroup>");
   for(var index = 0;index<column_count;index++)
   {
      //hArr.push("<col width="+ 100/column_count +"%>");
      hArr.push("<col width=55>");
   }
   hArr.push("</colgroup>");

   var col_index = 0;
   while( dirList.ItemIsValid() )
   {
      splitpath.Path = dirList.ItemPath;
      if(col_index == 0)
      {
         hArr.push("<tr><td>");
      }
      else
      {
         hArr.push("<td>");
      }
      hArr.push("<div class='mouseOut'");
      hArr.push("button_name='" + dirList.ItemPath + "' ");
      hArr.push("targetFunction = 'globalStore.ActiveGem.OnSelectType' ");
      hArr.push("functionArgs ='" + dirList.ItemPath + "'>");
      hArr.push("<img src='"+dirList.ItemPath+"' align=absmiddle border=0 width="+image_size+" height="+image_size+"><br>");

      // Gets atext name if it exists
      hArr.push(GetPluginTitle(splitpath.Path, false));

      hArr.push("</div>");

      if(col_index >= column_count-1)
      {
         hArr.push("</td></tr>");
         col_index=0;
      }
      else
      {
         hArr.push("</td>");
         col_index++;
      }
      dirList.NextItem();
   }
   if(col_index <= column_count-1)
      hArr.push("</tr>");
   
   hArr.push("</table>");
   
   hArr.push("<div class='mouseOut' button_name='gem_colour_back_button' targetFunction='globalStore.ActiveGem.OnBackButton' style='width=30px;float:right;'>");
   hArr.push("<img alt =" + gBackButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/back.gif' align=absmiddle border=0 width=30 height=30>");
   hArr.push("</div>");

   this.TargetDiv.innerHTML = hArr.join("\n");
   InitialiseButtonDivs();
}

function DrawPearVector(width, length)
{
   var pear_vector = artcam.Vectors.CreateVector();
   if (typeof(pear_vector)!="object")
   {
      artcam.Alert("Failed to create pear_vector",0);
      return;
   } 

   var half_width = width / 2;
   var quarter_width = half_width / 2;

   var third_length = length / 3;
   var sixth_length = third_length / 2;

   var control_1_x = -quarter_width;
   var control_1_y = 0;
   var control_2_x = -half_width;
   var control_2_y = sixth_length;
   var end_x = -half_width;
   var end_y = third_length;

   origin_x = 0;
   origin_y = -9*(length/20);

   pear_vector.MoveTo(origin_x,origin_y);
   pear_vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = -half_width;
   control_1_y = third_length * 2;
   control_2_x = -quarter_width;
   control_2_y = sixth_length * 5;
   end_x = 0;
   end_y = length;
   pear_vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = quarter_width;
   control_1_y = sixth_length * 5;
   control_2_x = half_width;
   control_2_y = third_length * 2;
   end_x = half_width;
   end_y = third_length;
   pear_vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = half_width;
   control_1_y = sixth_length;
   control_2_x = quarter_width;
   control_2_y = 0;
   end_x = 0;
   end_y = 0;
   pear_vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   pear_vector.Close(false);

   artcam.Vectors.AddVectorToArtcam(pear_vector);
   return pear_vector;
}

function DrawMarquiseVector(width, length)
{
   var vector = artcam.Vectors.CreateVector();
   if (typeof(vector)!="object")
   {
      artcam.Alert("DrawMarquiseVector::Failed",0);
      return;
   } 

   var half_width = width / 2;
   var quarter_width = half_width / 2;

   var half_length = length / 2;
   var quarter_length = half_length / 2;
   var eigth_length = quarter_length / 2;

   var control_1_x = -quarter_width;
   var control_1_y = eigth_length;
   var control_2_x = -half_width;
   var control_2_y = quarter_length;
   var end_x = -half_width;
   var end_y = half_length;   var control_1_x = -quarter_width;

   origin_x = 0;
   origin_y = -length/2;

   vector.MoveTo(origin_x,origin_y);
   vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = -half_width;
   control_1_y = quarter_length * 3;
   control_2_x = -quarter_width;
   control_2_y = eigth_length * 7;
   end_x = 0;
   end_y = length;
   vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = quarter_width;
   control_1_y = eigth_length * 7;
   control_2_x = half_width;
   control_2_y = quarter_length * 3;
   end_x = half_width;
   end_y = half_length;  
   vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   control_1_x = half_width;
   control_1_y = quarter_length;
   control_2_x = quarter_width;
   control_2_y = eigth_length;
   end_x = 0;
   end_y = 0;
   vector.BezierTo(control_1_x + origin_x , control_1_y + origin_y, control_2_x + origin_x, control_2_y + origin_y, end_x + origin_x, end_y + origin_y);

   vector.Close(false);

   artcam.Vectors.AddVectorToArtcam(vector);
   return vector;
}

function CreateGemVectorArray(use_selection)
{
   var GemVectorArray = new Array();
   var initial_selection = "";

   // If we are not using the selection, select all the vectors and remember current selection
   if( !use_selection )
   {
      initial_selection = artcam.VectorSelection.Selection; 
      artcam.VectorSelection.SelectAllVectors();
   }

   var index;
   for(index=0;index<artcam.VectorSelection.Count;index++)
   {
      var obj = artcam.VectorSelection.Item(index);
      AppendGemVectorsToArray(obj, GemVectorArray);
   }
   
   if( !use_selection )
      artcam.VectorSelection.Selection = initial_selection; // Restore original selection if we were not using the selection
   
   return GemVectorArray;
}

function AppendGemVectorsToArray(obj, array)
{
   if (obj.IsContour)
   {
      if(obj.StringExists("geminfo_Shape") )
      {
         array.push(obj);
      }
      return true;
   }
   else if (obj.IsGroup)
   {
      // this is a group - call ourselves recursively with each item in group
      var num_objs = obj.NumObjectsInGroup;
      for (var i = 0; i < num_objs; i++)
      {
         if (!AppendGemVectorsToArray(obj.Item(i),array))
            return false;
      }
      return true;
   }
   // shoudnt reach here
   return false;
}


function FindGemVectors(shape)
{
   var initial_selection = artcam.VectorSelection.Selection;
   var gem_ids = new Array();
   artcam.VectorSelection.SelectAllVectors();
   var index;
   // If the type is not passed, find all the GemVectors
   if( typeof(shape) == "undefined" )
   {
      for(index=0;index<artcam.VectorSelection.Count;index++)
      {
         if( artcam.VectorSelection.Item(index).StringExists("geminfo_Shape") )
         {
            gem_ids.push(artcam.VectorSelection.Item(index).VectorID);
         }
      }
   }
   // Otherwise only return the ones that have the right
   // 'type' string specified
   else
   {
      for(index=0;index<artcam.VectorSelection.Count;index++)
      {
         if( artcam.VectorSelection.Item(index).StringExists("geminfo_Shape") )
         {
            if( artcam.VectorSelection.Item(index).GetString("geminfo_Shape","Failed") == shape )
            {
               gem_ids.push(artcam.VectorSelection.Item(index).VectorID);
            }
         }
      }
   }
   artcam.VectorSelection.Selection = initial_selection;

   if(gem_ids.length==0)
      return "";

   return gem_ids.join(",");
}

function gem_OnSelectType(item)
{
   var splitpath = artcam.CreateSplitPath(item);
   if( splitpath == null )
      return; // If we can't create it we ignore this directory
   switch(splitpath.File)
   {
   case "Round":
      this.Shape = "Round";
      break;
   case "Brilliant":
      this.Shape = "Brilliant";
      break;
   case "Oval":
      this.Shape = "Oval";
      break;
   case "Princess":
      this.Shape = "Princess";
      break;
   case "BoxRadiant":
      this.Shape = "BoxRadiant";
      break;
   case "Marquise":
      this.Shape = "Marquise";
      break;
   case "Pear":
      this.Shape = "Pear";
      break;
   case "Heart":
      this.Shape = "Heart";
      break;
   case "Triangle":
      this.Shape = "Triangle";
      break;
   case "Trillion":
      this.Shape = "Trillion";
      break;
   case "Hexagon":
      this.Shape = "Hexagon";
      break;
   case "Emerald":
      this.Shape = "Emerald";
      break;
   default:
      return;
      break;
   }
   this.TargetDiv.innerHTML = "";
   this.GetNextPropertyPage();
}

function gem_OnSelectColour(item)
{
   var splitpath = artcam.CreateSplitPath(item);
   if( splitpath == null )
      return; // If we can't create it we ignore this directory

   // Deal with the Custom color
   if(splitpath.File=="Custom")
   {
      var color = artcam.GetColor(255,255,254);

      var r =  (color&0xff);
      var g = ((color&0xff00)  >>8);
      var b = ((color&0xff0000)>>16);

      // If the colour out is the same as the colour in, assume no color selected?
      // Might be better to make a colour object with a valid member.
      if( r==255 && g==255 && b==254 )
         return;

      // Now set the colour in this gem.
      this.DiffuseRed   = r;
      this.DiffuseGreen = g;
      this.DiffuseBlue  = b;
      this.AmbientRed   = 127;
      this.AmbientGreen = 127; // Assume semi-ambient
      this.AmbientBlue  = 127;
   }
   else
   {
      splitpath.Extension = "txt";

      var file_browser = artcam.CreateFileSelector();
      var file_text = file_browser.ReadTextFile(splitpath.Path);
      if( file_text == "" )
         return false;

      // Loop through the lines of the text file and find the first line that contains a paf description using a regexp
      var lines = file_text.split("\n");
      var line;
      for(line in lines)
      {

         // . Match Any character
         // + 1 or more times
         // ? Match as little as possible
         // () Grab out to $1
         // \s Match any space character
         // * 0 or more times
         // = Match '=' character

         if( /^\s*(.+?)\s*=\s*(.+?)\s*$/.test( lines[line] ) )
         {
            switch(RegExp.$1)
            {
            case "DiffuseRed":
               this.DiffuseRed = parseInt(RegExp.$2);
               break;
            case "DiffuseGreen":
               this.DiffuseGreen = parseInt(RegExp.$2);
               break;
            case "DiffuseBlue":
               this.DiffuseBlue = parseInt(RegExp.$2);
               break;
            case "AmbientRed":
               this.AmbientRed = parseInt(RegExp.$2);
               break;
            case "AmbientGreen":
               this.AmbientGreen = parseInt(RegExp.$2);
               break;
            case "AmbientBlue":
               this.AmbientBlue = parseInt(RegExp.$2);
               break;
            }
         }
      }
   }


   // If there is a current gem model, change it's colour
   if( this.GemModel )
   {
      this.GemModel.DiffuseRed   = this.DiffuseRed;
      this.GemModel.DiffuseGreen = this.DiffuseGreen;
      this.GemModel.DiffuseBlue  = this.DiffuseBlue;
      this.GemModel.AmbientRed   = this.AmbientRed;
      this.GemModel.AmbientGreen = this.AmbientGreen;
      this.GemModel.AmbientBlue  = this.AmbientBlue;
      artcam.Refresh3dView();
   }

   this.GetNextPropertyPage();
}

function gem_OnBackButton()
{
   //if(this.WizardMode)
   //{
      switch (this.PreviousPage)
      {
      case "shape": // First page goto the parent div
         this.TargetDiv.innerHTML = "";
         this.WriteShapeSelectionHTML();
         //this.ParentDiv.style.display = "";
         break;
      case "params":
         this.TargetDiv.innerHTML = "";
         this.WriteParamsSelectionHTML();
         break;
      case "summary":
         this.TargetDiv.innerHTML = "";
         this.WriteSummaryHTML();
         break;
      case "colour":
         this.TargetDiv.innerHTML = "";
         this.WriteColourSelectionHTML();
         break;
      default:
         if(typeof(this.CallbackFunction)=='function')
            this.CallbackFunction(false);
         else
            this.OnClose();
         break;
      }
   /*}
   else
   {
      // Clear our HTML
      this.TargetDiv.innerHTML = "";
      this.TargetDiv.style.display = "none";

      // Show the Calling DIV
      this.CallingDiv.style.display = "";
      // If a callback function was set, call it with success.
      if(typeof(this.CallbackFunction=='function'))
         this.CallbackFunction(true);
   }*/
}

function gem_OnClose()
{
   this.TargetDiv.innerHTML = "";
   this.TargetDiv.style.display = "none";
   this.CallingDiv.style.display = "";
}

function gem_GetNextPropertyPage()
{
   //if(this.WizardMode)
   //{
      switch (this.NextPage)
      {
      case "shape":
         this.TargetDiv.innerHTML = "";
         this.WriteShapeSelectionHTML();
         break;
      case "params":
         this.TargetDiv.innerHTML = "";
         this.WriteParamsSelectionHTML();
         break;
      case "colour":
         this.TargetDiv.innerHTML = "";
         this.WriteColourSelectionHTML();
         break;
      case "summary":
         this.TargetDiv.innerHTML = "";
         this.WriteSummaryHTML();
         break;
      default:
         this.TargetDiv.innerHTML = "";
         this.TargetDiv.style.display = "none";
         this.CallingDiv.style.display = "";
         if(typeof(this.CallbackFunction)=='function')
            this.CallbackFunction(true);
         break;
      }
  /* }
   else
   {
      // Clear our HTML
      this.TargetDiv.innerHTML = "";
      this.TargetDiv.style.display = "none";

      // Show the Calling DIV
      this.CallingDiv.style.display = "";
      // If a callback function was set, call it with success.
      if(typeof(this.CallbackFunction=='function'))
         this.CallbackFunction(true);
   }*/
}

function gem_OnSetParams()
{
   if(this.GemModel!=null)
   {
      globalStore.StoredWorkplane = this.GemModel.GetWorkplane();
      this.GemModel.ReturnToOrigin();
   }

   // I need to store a new value now... which says we are getting the width and height from the current vector...
   // then this will be done
   this.SizeSetFromVector = false;
   if(this.SizeFromVectorOption && this.SizeStandardSelect.GetSelectedTitle()==gGemSizeFromVector)
      this.SizeSetFromVector = true;

   this.Width  = this.WidthEdit.getValue();
   this.Length = this.LengthEdit.getValue();
   this.Depth  = this.DepthEdit.getValue();

   // If there is an existing gem model, set it's size
   if( this.GemModel )
   {
      this.GemModel.SetWidthHeightAndDepth(this.Width, this.Length, this.Depth);
      artcam.Refresh3dView();
   }

   this.GetNextPropertyPage();

   if(this.GemModel!=null)
   {   
      this.GemModel.SetWorkplane(globalStore.StoredWorkplane);
   }
}

function DrawHeartVector(width, length)
{
   var HW   = width;
   var HH  = length;
   var HAHW = HW/2;
   var HAHH = HH/2;
   
   var H1   = (HAHH*27/100);
   var H2   = (HAHH*8/100);  
   var H3   = (HAHH*70/100);
   var H4   = (HAHH*95/100);
   var H5   = (HAHH*55/100);
   var H6   = (HAHH*33/100);
   
   var H7   = (HH*51/100);
   var H8   = (HH*49.5/100);
   var H9   = (HH*47/100);
   var H10  = (HH*35.8/100);
   var H11  = (HH*10.5/100);
   var H12  = (HH*4.5/100);
   
   var W1   = (HAHW*25/100);
   var W2   = (HAHW*45/100);
   var W3   = (HAHW*60/100);
   var W4   = (HAHW*85/100);
   var W5   = (HAHW*50/100);
   var W6   = (HAHW*37/100);
   
   var W7   = (HW*8.6/100);
   var W8   = (HW*23/100);
   var W9   = (HW*30.5/100);
   var W10  = (HW*41.9/100);
   var W11  = (HW*53/100);
   var W12  = (HW*49.4/100);
   var W13  = (HW*48.5/100);
   
   var profile_vector = artcam.Vectors.CreateVector();
   
   profile_vector.MoveTo(0,(HAHH-H1));
   var control_1_x = -W7;
   var control_1_y = (HAHH);
   var control_2_x = -W8;
   var control_2_y = H7;
   var end_x = -W9;
   var end_y = H8;
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   control_1_x = -W10;
   control_1_y = H9;
   control_2_x = -W11;
   control_2_y = H10;
   end_x = -W12;
   end_y = (H11);
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   control_1_x = -W13;
   control_1_y = -(H12);
   control_2_x = -(HAHW-W6);
   control_2_y = -((HAHH-H6));
   end_x = 0;
   end_y = -HAHH;
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   control_1_x = (HAHW-W6);
   control_1_y = -((HAHH-H6));
   control_2_x = W13;
   control_2_y = -H12;
   end_x = W12;
   end_y = H11;
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   control_1_x = W11;
   control_1_y = H10;
   control_2_x = (W10);
   control_2_y = H9;
   end_x = (W9);
   end_y = (H8);
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   control_1_x = (W8);
   control_1_y = H7;
   control_2_x = (W7);
   control_2_y = (HAHH);
   end_x = 0;
   end_y = (HAHH-H1);
   
   profile_vector.BezierTo(control_1_x, control_1_y, control_2_x, control_2_y, end_x, end_y);
   
   profile_vector.Close(false);
   
   artcam.Vectors.AddVectorToArtcam(profile_vector);
   return profile_vector;
}

function DrawTriangleVector(width, height)
{
   var diameter = Math.sqrt( (4*(width*width))/3 );
   
   artcam.DrawPolygon
      ( 
      0, //double centre_x, 
      0, //double centre_y, 
      diameter/2,//double radius, 
      0,//double angle, 
      3, //int sides, 
      0//bool editing 
      );
   
   var vector = artcam.VectorSelection.Item(0);
   return vector;
}

function DrawHexagonVector(width, height)
{
   var diameter = width;
   
   artcam.DrawPolygon(0,0,diameter/2,Math.PI/6,6,0);
   
   var vector = artcam.VectorSelection.Item(0);
   return vector;
}

function DrawTrillionVector(width, height)
{
   var triangle_width   = width;
   var triangle_height  = height;
   var tri_width        = triangle_width/2;
   var tri_height       = triangle_height/2;
   var tri_width1       = tri_width*25/100;
   var tri_height1      =  tri_height*25/100;
   
   var tri_height2 = Math.sqrt((tri_width*tri_width)+(triangle_height*triangle_height));
   var profile_vector = artcam.Vectors.CreateVector();
   
   profile_vector.MoveTo(tri_width,-(tri_height-tri_width1));        
   profile_vector.ArcTo((tri_width/2+tri_width1),0,0,tri_height);
   profile_vector.ArcTo(-(tri_width/2+tri_width1),0,-tri_width,-(tri_height-tri_width1));
   profile_vector.ArcTo(-(tri_width/2-tri_width1),-(tri_height),tri_width,-(tri_height-tri_width1));
   
   artcam.Vectors.AddVectorToArtcam(profile_vector);
   return profile_vector;
}

function DrawBoxRadiantVector(width, facet)
{
   var boxradiant_width   = width;
   var box_facet_width    = facet;
   
   if (box_facet_width>boxradiant_width*70/100)
   {
      artcam.Alert("DrawBoxRadiantVector::Facet width is not possible for this Stone size",0);
      return;
   }
   
   var facet_width2   = box_facet_width/2;
   var box_facet_width2   = boxradiant_width/2;
   
   // pythagoras theorem 
   var facet_pos = Math.sqrt((facet_width2*facet_width2)+(facet_width2*facet_width2));
   
   var trim_box_X = ((boxradiant_width/2)-(facet_pos));
   var trim_box_Y = ((boxradiant_width/2)-(facet_pos));
   
   var profile_vector = artcam.Vectors.CreateVector();
   
   profile_vector.MoveTo(trim_box_X ,-box_facet_width2);
   profile_vector.LineTo(box_facet_width2,-trim_box_Y);
   profile_vector.LineTo(box_facet_width2,trim_box_Y);
   profile_vector.LineTo(trim_box_X ,box_facet_width2);
   
   profile_vector.LineTo(-trim_box_X ,box_facet_width2);
   profile_vector.LineTo(-box_facet_width2,trim_box_Y);
   profile_vector.LineTo(-box_facet_width2,-trim_box_Y);
   profile_vector.LineTo(-trim_box_X ,-box_facet_width2);
   profile_vector.LineTo(trim_box_X ,-box_facet_width2);
   
   artcam.Vectors.AddVectorToArtcam(profile_vector);
   return profile_vector;
}

function gem_GetReferenceAngle(vector)
{
   var first_span = vector.GetSpan(0);
   var x_centre = vector.Centre.X + artcam.CurrentModel.XPosition;
   var y_centre = vector.Centre.Y + artcam.CurrentModel.YPosition;
   var x_offset  = first_span.StartPointX - x_centre;
   var y_offset  = first_span.StartPointY - y_centre;

   var angle = Math.atan2( y_offset, x_offset);
   var deg_angle = angle*(180/Math.PI);
   return deg_angle;
}

function gem_OnStandardSelect()
{
   if(this.SizeStandardSelect.GetSelectedTitle()==gCustom)
   {
      this.WidthEdit.disabled = false;
      this.LengthEdit.disabled = false;
      this.DepthEdit.disabled = false;
      this.SizeOptionsSelect.SetDisabled(true);
      return;
   }

   if(this.SizeFromVectorOption &&
      this.SizeStandardSelect.GetSelectedTitle()==gGemSizeFromVector)
   {
      this.WidthEdit.disabled = true;
      this.LengthEdit.disabled = true;
      this.DepthEdit.disabled = true;
      this.SizeOptionsSelect.SetDisabled(true);
      return;
   }

   this.WidthEdit.disabled = false;
   this.LengthEdit.disabled = false;
   this.DepthEdit.disabled = false;
   this.SizeOptionsSelect.SetDisabled(false);

   FillSelectFromTextPairFile(this.SizeOptionsSelect, this.SizeStandardSelect.GetSelectedData());
   this.SizeOptionsSelect.SetSelectedIndex(0);
   this.OnSizeSelect();
}

function gem_OnSizeSelect()
{
   if(this.SizeOptionsSelect.GetSelectedTitle()==gCustom)
      return;
   var sizes = this.SizeOptionsSelect.GetSelectedData();
   var size_array = sizes.split(",");

   switch(size_array.length)
   {
   case 1:
      this.WidthEdit.setValue(size_array[0]);
      this.LengthEdit.setValue(size_array[0]);
      this.DepthEdit.setValue(this.WidthEdit.getValue()*0.42);
      break;
   case 2:
      this.LengthEdit.setValue(size_array[0]);
      this.WidthEdit.setValue(size_array[1]);
      this.DepthEdit.setValue(this.WidthEdit.getValue()*0.42);
      break;
   case 3:
      this.LengthEdit.setValue(size_array[0]);
      this.WidthEdit.setValue(size_array[1]);
      this.DepthEdit.setValue(size_array[2]);
      break;
   }
}

// sgc 25/07/06 Changed to use composite relief

function gem_SetPositionFromRelief(find_normal)
{
   var compRelief = artcam.CompositeRelief();
   this.ZPosition = compRelief.GetZHeight(this.XPosition,this.YPosition);

   if(find_normal)
   {
      // We now get a work plane from the relief
      this.Workplane = compRelief.GetWorkplaneAtPoint(this.XPosition,this.YPosition);

      var left_border = -artcam.CurrentModel.RealWidth/2;
      var right_border = artcam.CurrentModel.RealWidth/2;
      
      var x_location_left = this.XPosition-(this.Width/2);
      var x_location_right = this.XPosition+(this.Width/2);
      var y_location_top = this.YPosition-(this.Length/2);
      var y_location_bottom = this.YPosition+(this.Length/2);;
      
      // If the vector is overlapping the edge of the relief
      // wrap around model to find position
      if(x_location_left<left_border)
      {
         x_location_left = right_border + (x_location_left-left_border);
      }
      
      if(x_location_right>right_border)
      {
         x_location_right = left_border + (x_location_right-right_border);
      }
      
      var left = compRelief.GetZHeight(x_location_left,this.YPosition);
      var right = compRelief.GetZHeight(x_location_right,this.YPosition);
      var top = compRelief.GetZHeight(this.XPosition, y_location_top);
      var bottom = compRelief.GetZHeight(this.XPosition, y_location_bottom);
      
      if(top==bottom || left==right)
         return false;
      
      var height_difference = left-right;
      var angle = Math.atan2(this.Width, height_difference);
      var angle_degs = angle*(180/Math.PI);
      //this.XRotation = 90-angle_degs;
      this.XRotation = angle_degs - 90;
      
      height_difference = top-bottom;
      angle = Math.atan2(this.Length, height_difference);
      angle_degs = angle*(180/Math.PI);
      //this.YRotation = angle_degs-90;
      this.YRotation =90 - angle_degs;
   }
}

function gem_PositionAroundRing()
{
   if(this.GemModel==null)
   {
      artcam.Alert("Must Create Gem Model First",0);
      return;
   }

   var distortion_free_height = -artcam.Relief.BaseHeight;
   var ring_radius = ((artcam.CurrentModel.RealWidth / Math.PI) / 2) - distortion_free_height;
   
   var relief_length = artcam.Relief.MaxX - artcam.Relief.MinX;
   var relief_min_x = artcam.Relief.MinX;
   
   var x_ratio = (this.XPosition - relief_min_x) / relief_length;
   
   var angle;
   if (x_ratio < 0.5)
   {
      angle = 180 * (1.0 - (x_ratio / 0.5));
   }
   else
   {
      angle = -180 *  ((x_ratio - 0.5) / 0.5);
   }

   //Return to the origin + ring_radius
   this.GemModel.Transform(
      -this.XPosition,-this.YPosition,ring_radius,
      1,1,1,
      0,0,0,
      0,0,0,
      false,false);
   
   // Rotate each gem by 90deg on it's own axis, because of change in orientation
   this.GemModel.Transform(
      0,0,0,
      1,1,1,
      0,0,90,
      0,0,0,
      false,false);

   // Use the X Position to rotate the gem around the ring (now along X axis)
   this.GemModel.Transform(
      0,0,0,
      1,1,1,
      angle,0,0,
      0,0,0,
      false,false);

   // Use the Y position to set X, because of change in orientation
   this.GemModel.Transform(
      this.YPosition,0,0,
      1,1,1,
      0,0,0,
      0,0,0,
      false,false);
}

function gem_WriteSummaryHTML()
{
   this.TargetDiv.style.display = "";
   this.CallingDiv.style.display = "none";

   var hArr = new Array();
   // Add the back button HTML to the array
   this.NextPage = "summary"
   this.PreviousPage = "";

   this.OnFinish = this.OnAcceptChanges;

   hArr.push("<table width='100%' border=0 cellspacing=0 style='table-layout:fixed'>");
   hArr.push("<colgroup><col width=40px><col width=34%><col width=33%><col width=33%></colgroup>");
   
   hArr.push("<tr><td></td> <td>" + gGemLength + ":</td> <td><input type=edit id=length_edit number size=3></td> <td rowspan=3><input type=button value='" + gGemEdit + "' onclick = globalStore.ActiveGem.WriteParamsSelectionHTML('summary')></td></tr>");
   hArr.push("<tr><td></td> <td>" + gGemWidth + ":</td> <td><input type=edit id=width_edit number size=3></td> </tr>");
   hArr.push("<tr><td></td> <td>" + gGemDepth + ":</td> <td><input type=edit id=depth_edit number size=3></td> </tr>");

   hArr.push("<tr><td></td> <td colspan=2><input type=button value='" + gGemEditColour + "' onclick = globalStore.ActiveGem.WriteColourSelectionHTML('summary')></td> <td></td> </tr>");
   
   hArr.push("</table>");

   hArr.push("<div class='mouseOut' button_name='accept_button' targetFunction='globalStore.ActiveGem.OnFinish' style='width=30px;float:right;'>");
   hArr.push("<img alt =" + gAcceptButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/accept.gif' align=absmiddle border=0 width=30 height=30>");
   hArr.push("</div>");

   hArr.push("<div class='mouseOut' button_name='gem_params_back_button' targetFunction='globalStore.ActiveGem.OnBackButton' style='width=30px;float:right;'>");
   hArr.push("<img alt =" + gBackButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/back.gif' align=absmiddle border=0 width=30 height=30>");
   hArr.push("</div>");

   // Bung all our HTML into the div and display it
   this.TargetDiv.innerHTML = hArr.join("\n");

   // initialise all the 'special' objects
   InitialiseButtonDivs();
   SubclassNumberEditControls();

   length_edit.style.backgroundColor = 'buttonface';
   length_edit.readOnly = true;
   length_edit.setValue(this.Length);

   width_edit.style.backgroundColor = 'buttonface';
   width_edit.readOnly = true;
   width_edit.setValue(this.Width);

   depth_edit.style.backgroundColor = 'buttonface';
   depth_edit.readOnly = true;
   depth_edit.setValue(this.Depth);
}

// sgc 25/07/06 Use actual model dimensions instead of whatever is stored in modelX/Y/Z size

function gem_RetrieveInfoGemModel(model)
{
      this.Name = model.Name;
      this.Shape = this.ShapeFromFile(model.FileName);

      globalStore.StoredWorkplane = model.GetWorkplane();
      model.ReturnToOrigin();

      this.Width = model.MaxX - model.MinX;
      this.Length = model.MaxY - model.MinY;
      this.Depth = model.MaxZ - model.MinZ;

      model.UpdateSize(this.Width, this.Length, this.Depth);

      model.SetWorkplane(globalStore.StoredWorkplane);

      this.DiffuseRed   = model.DiffuseRed;
      this.DiffuseGreen = model.DiffuseGreen;
      this.DiffuseBlue  = model.DiffuseBlue;
      this.AmbientRed   = model.AmbientRed;
      this.AmbientGreen = model.AmbientGreen;
      this.AmbientBlue  = model.AmbientBlue;
      
      this.XPosition = model.XPosition;
      this.YPosition = model.YPosition;
      this.ZPosition = model.ZPosition;

      this.XRotation = model.XRotation;
      this.YRotation = model.YRotation;
      this.ZRotation = model.ZRotation;

      this.Workplane = model.GetWorkplane();

      this.GemModel = model;

      this.WizardMode = false;
}

function gem_WriteNavigationButtons(hArr)
{

   // If there is a next page - use forward button
   if(this.NextPage!="")
   {
      hArr.push("<div class='mouseOut' button_name='forward_button' targetFunction='globalStore.ActiveGem.OnFinish' style='width=30px;float:right;'>");
      hArr.push("<img alt =" + gForwardButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/forward.gif' align=absmiddle border=0 width=30 height=30>");
      hArr.push("</div>");
   }
   else // Otherwise - use accept button
   {
      hArr.push("<div class='mouseOut' button_name='accept_button' targetFunction='globalStore.ActiveGem.OnFinish' style='width=30px;float:right;'>");
      hArr.push("<img alt =" + gAcceptButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/accept.gif' align=absmiddle border=0 width=30 height=30>");
      hArr.push("</div>");
   }

   // Always add back button
   hArr.push("<div class='mouseOut' button_name='back_button' targetFunction='globalStore.ActiveGem.OnBackButton' style='width=30px;float:right;'>");
   hArr.push("<img alt =" + gBackButtonAlt + " id=back_img src ='" + artcam.HtmlRootDir + "../SharedImages/back.gif' align=absmiddle border=0 width=30 height=30>");
   hArr.push("</div>");
}

function gem_OnAcceptChanges()
{
   this.UpdateGemModel();
   this.OnBackButton();
}


//=== gem_GetGemVectorLayer ==============================================
//
// Returns the Vector layer for the gem vectors. Creates it if it doesn't exist.
//
// History
// Who When     What
// --- -------- ---------------------------------------------------------
// tpb 25/05/04 Written
//-----------------------------------------------------------------------

function gem_GetGemVectorLayer()
{
   // See if we have a gem vector layer
   var vl = artcam.VectorLayers;
   for(var layer_index = vl.FindFirst();                                          // Loop from first layer
       vl.IsValid(layer_index) && vl.GetLayer( layer_index ).name != gGemVectors; // Break if we have found it
       layer_index = vl.FindNext(layer_index) );                                  // Move to next layer

   // If we haven't found one, create it
   if(!vl.IsValid(layer_index))
   {
      // Remember the current layer first and set it back afterwards
      var selIdx = vl.selectedIndex;
      layer_index = vl.Create(-1, gGemVectors);
      vl.selectedIndex = selIdx;
   }

   // If we have a layer, set it's colour to be a ruby colour, ensure it is visible and return the index
   if(vl.IsValid(layer_index))
   {
      var layer = vl.GetLayer(layer_index);
      layer.color = 0x2200cc; // (0xbbggrr)
      layer.visibility = 100;
   }

   // Now return the index which may or may not be valid
   return layer_index;
}

function gem_DimensionsEdited()
{
   var DirSelector = artcam.CreateFileSelector();
   var dir_path = artcam.HtmlRootDir + "../GemLibrary/GemWeights/" + this.Shape + "/";
   var path_exists = DirSelector.DirectoryExists(dir_path);

   if(!path_exists)
      return;

   // Assuming for gems there are only ever going to be 2 standard size options. Carat or custom... 
   // We set the option to custom if the dimensions have been manually edited
   globalStore.ActiveGem.SizeStandardSelect.SetSelectedIndex(1);
   globalStore.ActiveGem.OnStandardSelect();
}