function plugin_main()
{
   HideAllLibraryDivs();

   paramsDiv.style.display = "";

   // Create the parameters in paramsDiv (this must exist)
   Plain_write_paramsDiv();

   // Initialise any button classes we have just created
   InitialiseButtonDivs();

   globalStore.OnBlockCopy = OnBlockCopy;

   RetrievePageSettings();

   if (artcam.DisplayHelp)
      ToggleHelp();   
}

function Plain_write_paramsDiv()
{
   // Empty any existing content
   paramsDiv.innerHTML = "";

   // Create an array to hold the HTML
   var hArr = new Array();

   hArr.push("<br>");

   hArr.push("<table id=copyDiv border=0 cellspacing=0 cellpadding=0 style='table-layout:fixed'>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'>");
   hArr.push("   <td colspan=2>");
   hArr.push("      <img src='../SharedImages/help.gif'>" + gBlockCopyHelp);
   hArr.push("      <br><br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("       <nobr>");
   hArr.push("          <b>"+ gTransformRelativeTo + ":</b>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='TxOriginRadio0' name='TxOriginRadio' checked><label for='TxOriginRadio0'>"+ gWorldOrigin +"</label>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='TxOriginRadio1' name='TxOriginRadio'><label for='TxOriginRadio1'>"+ gObjectOrigin + "</label>");
   hArr.push("          <br>");
   hArr.push("       </nobr>");
   hArr.push("    </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("       <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("       <nobr>");
   hArr.push("          <b>"+ gTangentPlane + ":</b>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='TangentPlane0' name='TangentPlane' checked><label for='TangentPlane0'><b><font color = 'red'>X</font>-<font color = 'green'>Y</font></b> "+gPlane+"</label><br>");
   hArr.push("          <input type=radio id='TangentPlane1' name='TangentPlane'><label for='TangentPlane1'><b><font color = 'green'>Y</font>-<font color = 'blue'>Z</font></b> "+gPlane+"</label><br>");
   hArr.push("          <input type=radio id='TangentPlane2' name='TangentPlane'><label for='TangentPlane2'><b><font color = 'blue'>Z</font>-<font color = 'red'>X</font></b> "+gPlane+"</label><br>");
   hArr.push("      </nobr>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'><td colspan=2>"+gTangentPlaneHelp+"<br><br></td></tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("      <nobr>");
   hArr.push("          <input type=checkbox id='ReverseRowDirection'><label for='ReverseRowDirection'>"+gReverseRowDir+"</label>");
   hArr.push("          <br>");
   hArr.push("          <input type=checkbox id='ReverseColDirection'><label for='ReverseColDirection'>"+gReverseColDir+"</label>");
   hArr.push("          <br>");
   hArr.push("      </nobr>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("          <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("       <nobr>");
   hArr.push("          <b>"+ gSurfaceCurvature + ":</b>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='Surface0' name='Surface' checked><label for='Surface0'>"+gPlane+"</label>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='Surface1' name='Surface'><label for='Surface1'>"+gCylinder+"</label>");
   hArr.push("          <br>");
   hArr.push("          <input type=radio id='Surface2' name='Surface'><label for='Surface2'>"+gSphere+"</label>");
   hArr.push("          <br>");
   hArr.push("       </nobr>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'><td colspan=2>"+gCurveHelp+"<br><br></td></tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("          <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td>");
   hArr.push("       <label for='Offset'><b>"+gOffset+"</b>");
   hArr.push("   </td>");
   hArr.push("   <td>");
   hArr.push("          <input id='Offset' size=4 maxLength=6 value='1.0' number dp='4'>");
   hArr.push("          <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'><td colspan=2>"+gOffsetHelp+"<br><br></td></tr>");
   hArr.push("<tr>");
   hArr.push("   <td>");
   hArr.push("          <label for='NumRows'><b>"+gNumRows+"</b>");
   hArr.push("   </td>");
   hArr.push("   <td>");
   hArr.push("          <input id='NumRows' size=4 maxLength=6 value='3' number dp='0'>");
   hArr.push("          <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td>");
   hArr.push("          <label for='NumCols'><b>"+gNumCols+"</b>");
   hArr.push("   </td>");
   hArr.push("   <td>");
   hArr.push("          <input id='NumCols' size=4 maxLength=6 value='3' number dp='0'>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'><td colspan=2>"+gRowColHelp+"<br><br></td></tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   hArr.push("          <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr>");
   hArr.push("   <td colspan=2>");
   if (artcam.SelectedAssembly.GetObjectAddress() == artcam.ProjectAssembly.GetObjectAddress)
   {
      hArr.push("    <input type=checkbox id='NestCheckbox' disabled=true><label for='NestCheckbox' disabled=true><b>"+gNest+"<b></label>");
   }
   else
   {
      hArr.push("    <input type=checkbox id='NestCheckbox'><label for='NestCheckbox'><b>"+gNest+"<b></label>");
   }
   hArr.push("       <br>");
   hArr.push("   </td>");
   hArr.push("</tr>");
   hArr.push("<tr HELPTAG style='DISPLAY:none'><td colspan=2>"+gNestHelp+"<br><br></td></tr>");
   hArr.push("</table>");

   hArr.push("<br>");

   // Add the forward button HTML to the array
   hArr.push("<div class='mouseOut' button_name='forward_button' id=ForwardButton targetFunction='globalStore.OnBlockCopy' 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>");

   // Add the back button HTML to the array
   AddBackButtonHTML(hArr);

   // Bung all our HTML into the div and display it
   paramsDiv.innerHTML = hArr.join("\n");
   SubclassNumberEditControls();
   paramsDiv.style.display = "";
}


//only works for assemblies
function OnBlockCopy()
{
   var selected_component = artcam.SelectedAssembly;
   if (selected_component == null)
   {
      artcam.Alert("No selected assembly",0);
      return;
   }

   var assembly_name = selected_component.Name;

   var parent_assembly = selected_component.GetParent();
   var whole_project_selected = false;
   if (parent_assembly == null)
   {
      //the selection was the 3DP
      whole_project_selected = true;
      parent_assembly = artcam.ProjectAssembly;
   }

   //get input values into local variables
   var centreIsComponent = TxOriginRadio[1].checked;
   var xAxisIsNormal = (TangentPlane1.checked);
   var yAxisIsNormal = (TangentPlane2.checked);
   var zAxisIsNormal = (TangentPlane0.checked);
   var xAxisIsRows = (TangentPlane0.checked);
   var yAxisIsRows = (TangentPlane1.checked);
   var zAxisIsRows = (TangentPlane2.checked);
   var xAxisIsCols = (TangentPlane2.checked);
   var yAxisIsCols = (TangentPlane0.checked);
   var zAxisIsCols = (TangentPlane1.checked);
   var surfaceIsPlane = Surface[0].checked;
   var surfaceIsCylinder = Surface[1].checked;
   var surfaceIsSphere = Surface[2].checked;
   var numOfRows = NumRows.getValue();
   var numOfCols = NumCols.getValue();
   var colOffset = ReverseRowDirection.checked ? -Offset.getValue() : Offset.getValue();
   var rowOffset = ReverseColDirection.checked ? -Offset.getValue() : Offset.getValue();
   var nestChecked = NestCheckbox.checked;

   if (numOfRows < 1 || numOfCols < 1)
   {
      return;
   }

   var selection_centre_x = (selected_component.MinX + selected_component.MaxX) / 2;
   var selection_centre_y = (selected_component.MinY + selected_component.MaxY) / 2;
   var selection_centre_z = (selected_component.MinZ + selected_component.MaxZ) / 2;
   var xHemisphereSign = selection_centre_x >= 0 ? 1 : -1;
   var yHemisphereSign = selection_centre_y >= 0 ? 1 : -1;
   var zHemisphereSign = selection_centre_z >= 0 ? 1 : -1;

   //our new assemblies will sit inside the following assembly
   var container_assembly;
   if (nestChecked || whole_project_selected)
   {
      container_assembly = artcam.CreateAssembly(assembly_name);
      if (container_assembly == null)
      {
         artcam.Alert("artcam.CreateAssembly() - failed",0);
         return;
      }
      container_assembly.InDisplayList = false;
   }
   else
   {
      container_assembly = parent_assembly;
   }

   var column_assembly;
   column_assembly = artcam.CreateAssembly(assembly_name);
   if (column_assembly == null)
   {
      artcam.Alert("artcam.CreateAssembly() - failed",0);
      return;
   }
   container_assembly.AppendChild(column_assembly);
   column_assembly.InDisplayList = false;

   for (rowIndex = 0; rowIndex < numOfRows; rowIndex++)
   {
      var new_assembly = CopyAssemblyTo(selected_component, column_assembly);
      if (new_assembly == null)
         return;

      var x_offset = 0.0;
      var y_offset = 0.0;
      var z_offset = 0.0;

      var x_angle = 0.0;
      var y_angle = 0.0;
      var z_angle = 0.0;

      if (surfaceIsPlane)
      {
         if (xAxisIsCols)
            x_offset += rowOffset * rowIndex;
         if (yAxisIsCols)
            y_offset += rowOffset * rowIndex;
         if (zAxisIsCols)
            z_offset += rowOffset * rowIndex;
      }

      if (surfaceIsCylinder)
      {
         if (xAxisIsCols)
            x_offset += rowOffset * rowIndex;
         if (yAxisIsCols)
            y_offset += rowOffset * rowIndex;
         if (zAxisIsCols)
            z_offset += rowOffset * rowIndex;
      }

      if (surfaceIsSphere)
      {
         if (xAxisIsNormal)
         {
            if (yAxisIsCols)
               z_angle = -(180 * xHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
            else
               y_angle = (180 * xHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_z, 2)));
         }

         if (yAxisIsNormal)
         {
            if (zAxisIsCols)
               x_angle = -(180 * yHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_y, 2)));
            else
               z_angle = (180 * yHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
         }

         if (zAxisIsNormal)
         {
            if (xAxisIsCols)
               y_angle = -(180 * zHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_x, 2)));
            else
               x_angle = (180 * zHemisphereSign * rowOffset * rowIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_y, 2)));
         }
      }

      new_assembly.Transform(x_offset,y_offset,z_offset,     // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,0.0,0.0,                    // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             x_angle,0.0,0.0,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,y_angle,0.0,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,0.0,z_angle,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
   }

   for (colIndex = 1; colIndex < numOfCols; colIndex++)
   {
      var new_assembly = CopyAssemblyTo(column_assembly, container_assembly);
      if (new_assembly == null)
         return;

      var x_offset = 0.0;
      var y_offset = 0.0;
      var z_offset = 0.0;

      var x_angle = 0.0;
      var y_angle = 0.0;
      var z_angle = 0.0;

      if (surfaceIsPlane)
      {
         if (xAxisIsRows)
            x_offset += colOffset * colIndex;
         if (yAxisIsRows)
            y_offset += colOffset * colIndex;
         if (zAxisIsRows)
            z_offset += colOffset * colIndex;
      }

      if (surfaceIsCylinder)
      {
         if (xAxisIsCols)
         {
            if (yAxisIsNormal)
               x_angle = -(180 * yHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_y, 2) + Math.pow(selection_centre_z, 2)));
            else
               x_angle = (180 * zHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_y, 2) + Math.pow(selection_centre_z, 2)));
         }

         if (yAxisIsCols)
         {
            if (zAxisIsNormal)
               y_angle = -(180 * zHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_z, 2)));
            else
               y_angle = (180 * xHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_z, 2)));
         }

         if (zAxisIsCols)
         {
            if (xAxisIsNormal)
               z_angle = -(180 * xHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
            else
               z_angle = (180 * yHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
         }
      }

      if (surfaceIsSphere)
      {
         if (xAxisIsNormal)
         {
            if (yAxisIsCols)
            {
               y_angle = (180 * xHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_z, 2)));
            }
            else
            {
               z_angle = -(180 * xHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
            }
         }

         if (yAxisIsNormal)
         {
            if (zAxisIsCols)
            {
               z_angle = (180 * yHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_x, 2) + Math.pow(selection_centre_y, 2)));
            }
            else
            {
               x_angle = -(180 * yHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_y, 2)));
            }
         }

         if (zAxisIsNormal)
         {
            if (xAxisIsCols)
            {
               x_angle = (180 * zHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_y, 2)));
            }
            else
            {
               y_angle = -(180 * zHemisphereSign * colOffset * colIndex) / (Math.PI * Math.sqrt(Math.pow(selection_centre_z, 2) + Math.pow(selection_centre_x, 2)));
            }
         }
      }

      new_assembly.Transform(x_offset,y_offset,z_offset,     // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,0.0,0.0,                    // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             x_angle,0.0,0.0,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,y_angle,0.0,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
      new_assembly.Transform(0.0,0.0,0.0,                    // trans
                             1.0,1.0,1.0,                    // scale
                             0.0,0.0,z_angle,                // rotate
                             0.0,0.0,0.0,                    // about point
                             centreIsComponent,
                             false);
   }
   
   if (nestChecked || whole_project_selected)
   {
      parent_assembly.AppendChild(container_assembly);
   }

   //hide the original selection rather than remove it -  makes it easier to get back to where you started
   if (whole_project_selected)
   {
      // Don't hide the root assembly, instead loop through each of it's children and hide those
      var child_index;
      for (child_index = 0; child_index < selected_component.NumChildren; ++child_index)
      {
         var child = selected_component.GetChildAtIndex(child_index);
         if (child != null && child.GetObjectAddress() != container_assembly.GetObjectAddress())
            child.DrawFlag = false;
      }
      for (child_index = 0; child_index < selected_component.Num3dModels; ++child_index)
      {
         var child = selected_component.Get3dModelAtIndex(child_index);
         if (child != null)
            child.DrawFlag = false;
      }
      for (child_index = 0; child_index < selected_component.NumGemSets; ++child_index)
      {
         var child = selected_component.GetGemSetAtIndex(child_index);
         if (child != null)
            child.DrawFlag = false;
      }      
   }
   else
   {
      selected_component.DrawFlag = false;
   }

   artcam.ProjectAssembly.UpdateAssemblyMonitor();
   artcam.Refresh3dView();
   StorePageSettings();
   OnBackButton();
}


function CopyAssemblyTo(sourceAssembly, destAssemblyParent)
{
   var new_assembly = sourceAssembly.Copy();
   if (new_assembly == null)
   {
      artcam.Alert("artcam.CreateAssembly() - failed",0);
      return null;
   }

   destAssemblyParent.AppendChild(new_assembly)
   new_assembly.InDisplayList = false;

   return new_assembly;
}


function StorePageSettings()
{
   artcam.StoreInt("BlockCopy3DA", "Origin", TxOriginRadio[0].checked ? 0 : 1);

   var i = 0;
   var found = false;
   while (i < TangentPlane.length && !found)
   {
      if (TangentPlane[i].checked)
      {
         artcam.StoreInt("BlockCopy3DA", "TangentPlane", i);
         found = true;
      }
      ++i;
   }

   artcam.StoreInt("BlockCopy3DA", "ReverseRow", ReverseRowDirection.checked ? 1 : 0);
   artcam.StoreInt("BlockCopy3DA", "ReverseCol", ReverseColDirection.checked ? 1 : 0);

   i = 0;
   found = false;
   while (i < Surface.length && !found)
   {
      if (Surface[i].checked)
      {
         artcam.StoreInt("BlockCopy3DA", "Surface", i);
         found = true;
      }
      ++i;
   }

   artcam.StoreDouble("BlockCopy3DA", "Offset", Offset.getValue());
   artcam.StoreInt("BlockCopy3DA", "NumRows", NumRows.getValue());
   artcam.StoreInt("BlockCopy3DA", "NumCols", NumCols.getValue());

   artcam.StoreInt("BlockCopy3DA", "Nest", NestCheckbox.checked ? 1 : 0);
}

function RetrievePageSettings()
{
   if (artcam.RetrieveInt("BlockCopy3DA", "Origin", 0) == 0)
      TxOriginRadio[0].checked = true;
   else
      TxOriginRadio[1].checked = true;

   var storedValue = artcam.RetrieveInt("BlockCopy3DA", "TangentPlane", 0);
   TangentPlane[storedValue].checked = true;

   if (artcam.RetrieveInt("BlockCopy3DA", "ReverseRow", 0) == 0)
      ReverseRowDirection.checked = false;
   else
      ReverseRowDirection.checked = true;

   if (artcam.RetrieveInt("BlockCopy3DA", "ReverseCol", 0) == 0)
      ReverseColDirection.checked = false;
   else
      ReverseColDirection.checked = true;

   var storedValue = artcam.RetrieveInt("BlockCopy3DA", "Surface", 0);
   Surface[storedValue].checked = true;

   Offset.setValue(artcam.RetrieveDouble("BlockCopy3DA", "Offset", 1.0));
   NumRows.setValue(artcam.RetrieveInt("BlockCopy3DA", "NumRows", 3));
   NumCols.setValue(artcam.RetrieveInt("BlockCopy3DA", "NumCols", 3));

   if (artcam.RetrieveInt("BlockCopy3DA", "Nest", 0) == 0)
      NestCheckbox.checked = false;
   else
      NestCheckbox.checked = true;
}

