/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/jsf/tags/sakai_2-3-1/widgets/src/java/org/sakaiproject/jsf/renderer/InputRichTextRenderer.java $
* $Id: InputRichTextRenderer.java 15703 2006-10-05 18:16:51Z chmaurer@iupui.edu $
***********************************************************************************
*
* Copyright (c) 2003, 2004 The Sakai Foundation.
*
* Licensed under the Educational Community License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.opensource.org/licenses/ecl1.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/



package org.sakaiproject.jsf.renderer;

import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.content.cover.ContentHostingService;
import org.sakaiproject.jsf.model.InitObjectContainer;
import org.sakaiproject.jsf.util.ConfigurationResource;
import org.sakaiproject.jsf.util.RendererUtil;
import org.sakaiproject.tool.cover.ToolManager;

import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.model.SelectItem;
import javax.faces.render.Renderer;
import java.io.IOException;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.*;

/**
 * <p>Formerly RichTextEditArea.java</p>
 * <p>Renders a rich text editor and toolbar within an HTML "textarea" element.</p>
    <p>The textarea is decorated using the HTMLArea JavaScript library.</p>
    <p>
      HTMLArea is a free, customizable online editor.  It works inside your
      browser.  It uses a non-standard feature implemented in Internet
      Explorer 5.5 or better for Windows and Mozilla 1.3 or better (any
      platform), therefore it will only work in one of these browsers.
    </p>

    <p>
      HTMLArea is copyright <a
      href="http://interactivetools.com">InteractiveTools.com</a> and
      released under a BSD-style license.  HTMLArea is created and developed
      upto version 2.03 by InteractiveTools.com.  Version 3.0 developed by
      <a href="http://students.infoiasi.ro/~mishoo/">Mihai Bazon</a> for
      InteractiveTools.  It contains code sponsored by other companies as
      well.
    </p>

 * <p>Copyright: Copyright (c) 2004 Sakai</p>
 * @author cwen@iu.edu
 * @author Ed Smiley esmiley@stanford.edu (modifications)
 * @version $Id: InputRichTextRenderer.java 15703 2006-10-05 18:16:51Z chmaurer@iupui.edu $
 */
public class InputRichTextRenderer extends Renderer
{
  private static final String SCRIPT_PATH;
  private static final String HTMLAREA_SCRIPT_PATH;
  private static final String RESOURCE_PATH;
  private static final String TOOLBAR_SCRIPT_NONE;
  private static final String TOOLBAR_SCRIPT_SMALL;
  private static final String TOOLBAR_SCRIPT_MEDIUM;
  
  
  
  private static final String TOOLBAR_SCRIPT_LARGE;
  private static final int DEFAULT_WIDTH_PX;
  private static final int DEFAULT_HEIGHT_PX;
  private static final int DEFAULT_COLUMNS;
  private static final int DEFAULT_ROWS;
  private static final String INSERT_IMAGE_LOC;
   private static final MessageFormat LIST_ITEM_FORMAT_HTML =
     new MessageFormat("\"{0}\" : \"<a href=''{1}''>{0}</a>\"");
   private static final MessageFormat LIST_ITEM_FORMAT_FCK =
     new MessageFormat("[\"{0}\", \"{1}\"]");


  // we have static resources for our script path and built-in toolbars etc.
  static {
    ConfigurationResource cr = new ConfigurationResource();
    SCRIPT_PATH = cr.get("inputRichTextScript");
    HTMLAREA_SCRIPT_PATH = cr.get("inputRichTextHTMLArea");
    RESOURCE_PATH = cr.get("resources");
    TOOLBAR_SCRIPT_NONE = makeToolbarScript(cr.get("inputRichText_none"));
    TOOLBAR_SCRIPT_SMALL = makeToolbarScript(cr.get("inputRichText_small"));
    TOOLBAR_SCRIPT_MEDIUM = makeToolbarScript(cr.get("inputRichText_medium"));
    TOOLBAR_SCRIPT_LARGE = makeToolbarScript(cr.get("inputRichText_large"));
    DEFAULT_WIDTH_PX = Integer.parseInt(cr.get("inputRichTextDefaultWidthPx"));
    DEFAULT_HEIGHT_PX = Integer.parseInt(cr.get("inputRichTextDefaultHeightPx"));
    DEFAULT_COLUMNS = Integer.parseInt(cr.get("inputRichTextDefaultTextareaColumns"));
    DEFAULT_ROWS = Integer.parseInt(cr.get("inputRichTextDefaultTextareaRows"));
    INSERT_IMAGE_LOC = "/" + RESOURCE_PATH + "/" + cr.get("inputRichTextFileInsertImage");
  }

  public boolean supportsComponentType(UIComponent component)
  {
    return (component instanceof org.sakaiproject.jsf.component.InputRichTextComponent);
  }

  public void encodeBegin(FacesContext context, UIComponent component)
      throws IOException
  {

    if (!component.isRendered())
    {
      return;
    }

    String contextPath =
      context.getExternalContext().getRequestContextPath() + SCRIPT_PATH;
    String clientId = component.getClientId(context);

    ResponseWriter writer = context.getResponseWriter();

    String value = null;
    if (component instanceof UIInput)
        value = (String) ((UIInput) component).getSubmittedValue();
    if (value == null && component instanceof ValueHolder)
        value = (String) ((ValueHolder) component).getValue();

    ///////////////////////////////////////////////////////////////////////////
    // attributes
    ///////////////////////////////////////////////////////////////////////////

//  If true, only the textarea will be rendered.  Defaults to false.
//  If true, the rich text toolbar  and external HTMLArea JavaScript will NOT.
    String textareaOnly = (String) RendererUtil.getAttribute(context, component, "textareaOnly");
//    Specify toolbar from among a number precanned lists of command buttons.
//    Allowed values are: "none", "small", "medium", "large".
     String buttonSet = (String) RendererUtil.getAttribute(context, component, "buttonSet");
//  Comma delimited list of toolbar command buttons registered with component.
    String buttonList = (String) RendererUtil.getAttribute(context, component, "buttonList");
    /**
     * @todo need to do something with extensions.
     */
//  URL to an external JavaScript file with additional JavaScript
    String javascriptLibraryExtensionURL =
        (String) RendererUtil.getAttribute(context, component, "javascriptLibraryExtensionURL");
//   The URL to the directory of the HTMLArea JavaScript library.
    String javascriptLibraryURL =
        (String) RendererUtil.getAttribute(context, component, "javascriptLibraryURL");
//  If true show XPath at bottom of editor.  Default is true.
    String showXPath = (String) RendererUtil.getAttribute(context, component, "showXPath");
    showXPath = RendererUtil.makeSwitchString(showXPath, true, true, true, false, false, true);

    ///////////////////////////////////////////////////////////////////////////

    // set up dimensions
    int widthPx = DEFAULT_WIDTH_PX;
    int heightPx = DEFAULT_HEIGHT_PX;
    int textareaColumns = DEFAULT_COLUMNS;
    int textareaRows = DEFAULT_ROWS;

    try
    {
      Integer cols = (Integer) RendererUtil.getAttribute(context, component, "cols");
      Integer rows = (Integer) RendererUtil.getAttribute(context, component, "rows");
      if (cols != null) textareaColumns = cols.intValue();
      if (rows != null) textareaRows = rows.intValue();
      
//    Width of the widget (in pixel units).
//    If this attribute is not specified, the width is controlled by the 'cols' attribute.
      String width = (String) RendererUtil.getAttribute(context, component, "width");
      if (width != null) widthPx = Integer.parseInt(width);
//    Height of the widget (in pixel units).
//    If this attribute is not specified, the width is controlled by the 'rows' attribute.
      String height = (String) RendererUtil.getAttribute(context, component, "height");
      if (height != null) heightPx = Integer.parseInt(height);
    }
    catch (Exception ex)
    {
      //default, whatever goes awry
    }

    if (widthPx == DEFAULT_WIDTH_PX && textareaColumns != DEFAULT_COLUMNS)
       widthPx = (DEFAULT_WIDTH_PX*textareaColumns)/DEFAULT_COLUMNS;
    if (heightPx == DEFAULT_HEIGHT_PX && textareaRows != DEFAULT_ROWS)
       heightPx = (DEFAULT_HEIGHT_PX*textareaRows)/DEFAULT_ROWS;

    Locale locale = Locale.getDefault();

    String editor = ServerConfigurationService.getString("wysiwyg.editor");
    if(editor != null && !editor.equalsIgnoreCase("FCKeditor"))
    {
      // Render JavaScripts.
      writeExternalScripts(locale, writer);

      // Render base textarea.
      writeTextArea(clientId, value, textareaRows, textareaColumns, writer);

      // Make textarea rich text (unless textareaOnly is true).
      if (!"true".equals(textareaOnly))
      {
        String toolbarScript;

        if (buttonList != null)
        {
          toolbarScript = makeToolbarScript(buttonList);
        }
        else
        {
          toolbarScript = getStandardToolbarScript(buttonSet);
        }

        // hook up configuration object
        writeConfigurationScript(context, component, clientId, toolbarScript, widthPx, heightPx, showXPath, locale, writer);
      }
    }
    else
    {
       //not as slick as the way htmlarea is rendered, but the difference in functionality doesn't all
       //make sense for FCK at this time since it's already got the ability to insert files and such.
       String collectionId = ContentHostingService.getSiteCollection(ToolManager.getCurrentPlacement().getContext());

       //is there a slicker way to get this? 
       String connector = "/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector";

       writer.write("<table border=\"0\"><tr><td>");
       writer.write("<textarea name=\"" + clientId + "_inputRichText\" id=\"" + clientId + "_inputRichText\"");
       if (textareaColumns > 0) writer.write(" cols=\""+textareaColumns+"\"");
       if (textareaRows > 0) writer.write(" rows=\""+textareaRows+"\"");
       writer.write(">");
       if (value != null)
          writer.write((String) value);
       writer.write("</textarea>");

       RendererUtil.writeExternalJSDependencies(context, writer, "inputrichtext.jsf.fckeditor.js", "/library/editor/FCKeditor/fckeditor.js");
       //writer.write("<script type=\"text/javascript\" src=\"/library/editor/FCKeditor/fckeditor.js\"></script>\n");
       writer.write("<script type=\"text/javascript\" language=\"JavaScript\">\n");

       String attachmentVar = "attachment" + createSafeRandomNumber();

       boolean hasAttachments = false;

       Object attchedFiles = RendererUtil.getAttribute(context,  component, "attachedFiles");
       if (attchedFiles != null && getSize(attchedFiles) > 0) {
          writeFilesArray(writer, attachmentVar, attchedFiles, LIST_ITEM_FORMAT_FCK, false);
          writer.write("\n");
          hasAttachments = true;
       }

       writer.write("function chef_setupformattedtextarea(textarea_id){\n");
       writer.write("var oFCKeditor = new FCKeditor(textarea_id);\n");
       writer.write("oFCKeditor.BasePath = \"/library/editor/FCKeditor/\";\n");

       if (widthPx < 0)
         widthPx = 600;
       if (heightPx < 0)
         heightPx = 400;
       //FCK's toolset is larger then htmlarea and this prevents tools from ending up with all toolbar
       //and no actual editing area.
       if (heightPx < 200)
         heightPx = 200;

       writer.write("oFCKeditor.Width  = \"" + widthPx + "\" ;\n");
       writer.write("oFCKeditor.Height = \"" + heightPx + "\" ;\n");

       if ("archival".equals(ServerConfigurationService.getString("tags.focus")))
          writer.write("\n\toFCKeditor.Config['CustomConfigurationsPath'] = \"/library/editor/FCKeditor/archival_config.js\";\n");
       else {

         writer.write("\n\t\tvar courseId = \"" + collectionId  + "\";");
         writer.write("\n\toFCKeditor.Config['ImageBrowserURL'] = oFCKeditor.BasePath + " +
               "\"editor/filemanager/browser/default/browser.html?Connector=" + connector + "&Type=Image&CurrentFolder=\" + courseId;");
         writer.write("\n\toFCKeditor.Config['LinkBrowserURL'] = oFCKeditor.BasePath + " +
               "\"editor/filemanager/browser/default/browser.html?Connector=" + connector + "&Type=Link&CurrentFolder=\" + courseId;");
         writer.write("\n\toFCKeditor.Config['FlashBrowserURL'] = oFCKeditor.BasePath + " +
               "\"editor/filemanager/browser/default/browser.html?Connector=" + connector + "&Type=Flash&CurrentFolder=\" + courseId;");
         writer.write("\n\toFCKeditor.Config['ImageUploadURL'] = oFCKeditor.BasePath + " +
               "\"" + connector + "?Type=Image&Command=QuickUpload&Type=Image&CurrentFolder=\" + courseId;");
         writer.write("\n\toFCKeditor.Config['FlashUploadURL'] = oFCKeditor.BasePath + " +
               "\"" + connector + "?Type=Flash&Command=QuickUpload&Type=Flash&CurrentFolder=\" + courseId;");
         writer.write("\n\toFCKeditor.Config['LinkUploadURL'] = oFCKeditor.BasePath + " +
               "\"" + connector + "?Type=File&Command=QuickUpload&Type=Link&CurrentFolder=\" + courseId;");

         writer.write("\n\n\toFCKeditor.Config['CurrentFolder'] = courseId;");

         writer.write("\n\toFCKeditor.Config['CustomConfigurationsPath'] = \"/library/editor/FCKeditor/config.js\";\n");
       }

       if (hasAttachments) {
          writer.write("\n\n\toFCKeditor.Config['AttachmentsVariable'] = \"" + attachmentVar  + "\";");
          writer.write("\n\n\toFCKeditor.ToolbarSet = \"Attachments\";");
       }

       writer.write("oFCKeditor.ReplaceTextarea();\n");
       writer.write("} \n");
       writer.write("</script>\n");
       writer.write("<script type=\"text/javascript\" defer=\"1\">chef_setupformattedtextarea('"+clientId+"_inputRichText');</script>");
       writer.write("</td></tr></table>\n");
    }
  }

  /**
   * Return the config script portion for a standard button set.
   * @param buttonSet
   * @return
   */
  private String  getStandardToolbarScript(String buttonSet) {
    String toolbarScript;
    if ("none".equals(buttonSet))
    {
      toolbarScript = TOOLBAR_SCRIPT_NONE;
    }
    else if ("small".equals(buttonSet))
    {
      toolbarScript = TOOLBAR_SCRIPT_SMALL;
    }
    else if ("medium".equals(buttonSet))
    {
      toolbarScript = TOOLBAR_SCRIPT_MEDIUM;
    }
    else if ("large".equals(buttonSet))
    {
      toolbarScript = TOOLBAR_SCRIPT_LARGE;
    }
    else
    {
      toolbarScript = TOOLBAR_SCRIPT_MEDIUM;
    }

    return toolbarScript;
  }

  /**
   * Write out HTML rextarea
   * @param clientId
   * @param value the textarrea value
   * @param writer
   * @throws IOException
   */
  private void writeTextArea(String clientId, String value, int rows, int cols,
    ResponseWriter writer) throws IOException {

  	// wrap the textarea in a table, so that the HTMLArea toolbar doesn't bleed to the
  	// edge of the screen.
  	writer.write("<table border=\"0\"><tr><td>\n");
    writer.write("<textarea name=\"");
    writer.write(clientId);
    writer.write("_inputRichText\" id=\"");
    writer.write(clientId);
    writer.write("_inputRichText\"");
    writer.write(" rows=\"" + rows + "\"");
    writer.write(" cols=\"" + cols + "\"");
    writer.write(">" + value + "</textarea>\n");
    writer.write("</td></tr></table>\n");
  }

  /**
   * @todo do these as a document.write after testing if done
   * @param contextPath
   * @param writer
   * @throws IOException
   */
  protected void writeExternalScripts(Locale locale, ResponseWriter writer)
      throws IOException {
    writer.write("<script type=\"text/javascript\">var _editor_url = \"" +
                 "/" + RESOURCE_PATH + "/" + HTMLAREA_SCRIPT_PATH + "/" +
                 "\";</script>\n");
    writer.write("<script type=\"text/javascript\" src=\"" + "/" +
                 RESOURCE_PATH + "/" + HTMLAREA_SCRIPT_PATH + "/" +
                 "htmlarea.js\"></script>\n");
    writer.write("<script type=\"text/javascript\" src=\"" + "/" +
                 RESOURCE_PATH + "/" + HTMLAREA_SCRIPT_PATH + "/" +
                 "dialog.js\"></script>\n");
    writer.write("<script type=\"text/javascript\" src=\"" + "/" +
                 RESOURCE_PATH + "/" + HTMLAREA_SCRIPT_PATH + "/" +
                 "popupwin.js\"></script>\n");
    writer.write("<script type=\"text/javascript\" src=\"" + "/" +
                 RESOURCE_PATH + "/" + HTMLAREA_SCRIPT_PATH + "/" +
                 "lang/en.js\"></script>\n");

    String language = locale.getLanguage();
    if (!Locale.ENGLISH.equals(language))
    {
      writer.write("<script type=\"text/javascript\" src=\"" + "/" +
        RESOURCE_PATH + "/"     + HTMLAREA_SCRIPT_PATH + "/" +
        "lang/" + language + ".js\"></script>\n");
    }
    writer.write("<script type=\"text/javascript\" src=\"" + "/" +
      RESOURCE_PATH + "/" + SCRIPT_PATH + "\"></script>\n");
  }

  /**
   * Standard decode method.
   * @param context
   * @param component
   */
  public void decode(FacesContext context, UIComponent component)
  {
    if( RendererUtil.isDisabledOrReadonly(context, component)) return;

    if (null == context || null == component
        || !(component instanceof org.sakaiproject.jsf.component.InputRichTextComponent))
    {
      throw new IllegalArgumentException();
    }

    String clientId = component.getClientId(context);

    Map requestParameterMap = context.getExternalContext()
        .getRequestParameterMap();

    String newValue = (String) requestParameterMap.get(clientId + "_inputRichText");

    org.sakaiproject.jsf.component.InputRichTextComponent comp = (org.sakaiproject.jsf.component.InputRichTextComponent) component;
    comp.setSubmittedValue(newValue);
  }

  /**
   * Write configuration script
   *
   * @param clientId the client id
   * @param toolbar the toolbar configuration string (i.e from makeToolbarScript())
   * @param widthPx columns
   * @param heightPx rows
   */
  protected void writeConfigurationScript(FacesContext context, UIComponent component, String clientId,
    String toolbar, int widthPx, int heightPx, String showXPath, Locale locale, ResponseWriter writer)
    throws IOException
  {
    // script creates unique Config object
    String configVar = "config" + createSafeRandomNumber();

    writer.write("<script type=\"text/javascript\">\n");
    writer.write("  sakaiSetLanguage(\"" + locale.getDisplayLanguage() + "\");");
    writer.write("  var " + configVar + "=new HTMLArea.Config();\n");
    writer.write("  sakaiRegisterButtons(" + configVar + ");\n");
    writer.write("  " + configVar + ".toolbar = " + toolbar + ";\n");
    writer.write("  " + configVar + ".width=\"" + widthPx + "px\";\n");
    writer.write("  " + configVar + ".height=\"" + heightPx + "px\";\n");
    writer.write("  " + configVar + ".statusBar=" + showXPath + ";\n");
    writeAdditionalConfig(context, component, configVar, clientId,
          toolbar, widthPx, heightPx, locale,  writer);
    writer.write(  "sakaiSetupRichTextarea(\"");
    writer.write(clientId);
    writer.write("_inputRichText\"," + configVar + ");\n");
    writer.write("</script>\n");
  }

   /**
    * subclasses can override to provide additonal configuration such as add buttons, etc
    * @param context
    * @param component
    * @param configVar
    * @param clientId
    * @param toolbar
    * @param widthPx
    * @param heightPx
    * @param locale
    * @param writer
    */
   protected void writeAdditionalConfig(FacesContext context, UIComponent component, String configVar,
      String clientId, String toolbar, int widthPx, int heightPx, Locale locale, ResponseWriter writer)
      throws IOException{
      writeAttachedFiles(context, component, configVar, writer, toolbar);
      registerWithParent(component, configVar, clientId);
   }

   protected void writeAttachedFiles(FacesContext context, UIComponent component,
                                     String configVar, ResponseWriter writer, String toolbar) throws IOException {
      Object attchedFiles = RendererUtil.getAttribute(context,  component, "attachedFiles");
      if (attchedFiles != null && getSize(attchedFiles) > 0) {
         String arrayVar = configVar + "_Resources";

         writeFilesArray(writer, arrayVar, attchedFiles, LIST_ITEM_FORMAT_HTML, true);

         writer.write(  "sakaiRegisterResourceList(");
         writer.write(configVar + ",'" + INSERT_IMAGE_LOC + "'," + arrayVar);
         writer.write(");\n");

         writer.write("  " + configVar + ".toolbar = " + addToolbar(toolbar) + ";\n");
      }
   }

   protected void writeFilesArray(ResponseWriter writer, String arrayVar,
                                  Object attchedFiles, MessageFormat format,
                                  boolean includeLabel) throws IOException {
      StringWriter buffer = new StringWriter();

      char startChar = '[';
      char endChar = ']';

      if (format == LIST_ITEM_FORMAT_HTML) {
         startChar = '{';
         endChar = '}';
      }

      buffer.write("  var " + arrayVar + " = "+startChar+"\n");

      if (includeLabel) {
         buffer.write("\"select a file url to insert\" : \"\"");
      }

      if (attchedFiles instanceof Map) {
         buffer.write(outputFiles((Map)attchedFiles, format, !includeLabel));
      }
      else {
         buffer.write(outputFiles((List)attchedFiles, format, !includeLabel));
      }

      buffer.write(endChar + ";\n");
      String result = buffer.toString();
      writer.write(result);
   }

   protected void registerWithParent(UIComponent component, String configVar, String clientId) {

      InitObjectContainer parentContainer = null;

      UIComponent testContainer = component.getParent();
      while (testContainer != null) {
         if (testContainer instanceof InitObjectContainer) {
            parentContainer = (InitObjectContainer)testContainer;

            String script = " resetRichTextEditor(\"" + clientId +
               "_inputRichText\"," + configVar + ");\n";

            parentContainer.addInitScript(script);
         }
         testContainer = testContainer.getParent();
      }
   }

   protected String outputFiles(Map map, MessageFormat format, boolean first) {
      StringBuffer sb = new StringBuffer();

      for (Iterator i=map.entrySet().iterator();i.hasNext();) {
         Map.Entry entry = (Map.Entry)i.next();
         if (!first) {
            sb.append(',');
         }
         else {
            first = false;
         }
         format.format(new Object[]{entry.getValue(), entry.getKey()}, sb, null);
      }

      return sb.toString();
   }

   protected String outputFiles(List list, MessageFormat format, boolean first) {
      StringBuffer sb = new StringBuffer();

      for (Iterator i=list.iterator();i.hasNext();) {
         Object value = i.next();

         String url;
         String label;

         if (value instanceof SelectItem) {
            SelectItem item = (SelectItem)value;
            url = item.getValue().toString();
            label = item.getLabel();
         }
         else {
            url = value.toString();
            label = value.toString();
         }

         if (!first) {
            sb.append(',');
         }
         else {
            first = false;
         }
         format.format(new Object[]{label, url}, sb, null);
      }

      return sb.toString();
   }

   protected int getSize(Object attchedFiles) {
      if (attchedFiles instanceof Map) {
         return ((Map)attchedFiles).size();
      }
      else {
         return ((List)attchedFiles).size();
      }
   }

   protected String addToolbar(String toolbar) {
      int pos = toolbar.lastIndexOf("]");
      toolbar = toolbar.substring(0, pos) +
         ",[\"filedropdown\", \"insertfile\", ]" +
         toolbar.substring(pos);
      return toolbar;
   }

   /**
   * Built toolbar part of configuration script for a list of button commands.
   *
   * @param buttonList csv list of buttons
   * @return String, e.g.
   * <code><pre>
   *    [["fontname", "space",... ]] etc.
   * </pre></code>
   *
   */
  private static String makeToolbarScript(String buttonList) {
    StringBuffer script = new StringBuffer();
    String q = "\"";

    script.append("[[");

    StringTokenizer st = new StringTokenizer(buttonList, ",", false);

    while (st.hasMoreTokens())
    {
      String command = st.nextToken();
      if (!"linebreak".equals(command))
      {
        script.append(q + command + q + ", ");
      }
      else
      {
        script.append("],[");
      }
    }

    script.append("]]");
    return script.toString();
  }
  
  private String createSafeRandomNumber() {
     return "" + (long)(Math.floor(Math.random() * 1000000000));
  }

}
