Codebase.load("http://codebase.gd-ks.com/js/Function.js");
Codebase.load("http://codebase.gd-ks.com/js/Event.js");
Codebase.load("http://codebase.gd-ks.com/js/Style.js");
Codebase.load("http://codebase.gd-ks.com/js/Element.js");
Codebase.load("http://codebase.gd-ks.com/js/Enumerable.js");
Codebase.load("http://codebase.gd-ks.com/js/DOM.js");

// TOOLS
RTE.BOLD="Bold";
RTE.ITALIC="Italic";
RTE.UNDERLINE="Underline";
RTE.LINK="Create Link";
RTE.UNLINK="Unlink";
RTE.ORDERED_LIST="Insert Ordered List";
RTE.UNORDERED_LIST="Insert Unordered List";
RTE.SWITCH_TO_HTML_MODE="Switch to HTML Mode";
RTE.SWITCH_TO_GUI_MODE="Switch to GUI Mode";
RTE.PASTE_FROM_MSWORD="Paste from MSWord";

// Should use toolsets instead of layouts, that way it's inherently custom with presets
RTE.TOOLSET_BASIC=[RTE.BOLD, 
                   RTE.ITALIC, 
                   RTE.UNDERLINE, 
                   RTE.PASTE_FROM_MSWORD];

RTE.TOOLSET_STANDARD=[RTE.BOLD, 
                      RTE.ITALIC, 
                      RTE.UNDERLINE, 
                      RTE.LINK, 
                      RTE.UNLINK, 
                      RTE.ORDERED_LIST, 
                      RTE.UNORDERED_LIST, 
                      RTE.PASTE_FROM_MSWORD];
                      
RTE.TOOLSET_ALL=[RTE.BOLD, 
                 RTE.ITALIC, 
                 RTE.UNDERLINE, 
                 RTE.LINK, 
                 RTE.UNLINK, 
                 RTE.ORDERED_LIST, 
                 RTE.UNORDERED_LIST, 
                 RTE.PASTE_FROM_MSWORD, 
                 RTE.SWITCH_TO_HTML_MODE, 
                 RTE.SWITCH_TO_GUI_MODE];

// NEEDS Paste from MSWord - Fix the threat of users pasting from MSWord
function RTE(el, toolset)
{
   RTE.instances.push(this);
   
   var _this=this;
   
   // Check to see if the primitive is a textual input element
   this._originalNodeIsTextualInput=(el.tagName.toLowerCase()=="textarea" || el.tagName.toLowerCase()=="text" ? true : false);
   
   // CONTAINER FOR IT ALL
   this._node=$E("div", {"style":"border:1px solid #333; display:inline-block; background:#F5F5F5; padding:4px; padding-top:2px;"});
   
   this._editorContainer=$E("div", {"style":"border:1px solid #333; background-color:#FFF; "});
   
   // Create a container for the toolbars
   this._toolbarContainer=$E("span");
   
   // Footer container
   this._footerContainer=$E("span");
   
   // Create a node for editing html, if the editable node is a text input, then let it act as the html view
   this._htmlNode=(this._originalNodeIsTextualInput ? el : $E("textarea"));
   
   // Create a node for the GUI, if the editable node is a text input, then we'll need a new node for the gui view, if the editable node is not a text input then we can use it as the gui view
   // This node is also used for previewing
   this._guiNode=(this._originalNodeIsTextualInput ? ($E("div", {"innerHTML":this.getHTML()})) : el);
   
   Style.setAttributes(this._guiNode, {"overflow":"auto"});
   
   // Ensure that the gui is editable
   this._guiNode.contentEditable=true;
   
   // Clipboard GUI
   this._clipboardContainer=$E("div", {"style":"border:1px solid #333; padding:4px; position:absolute; z-index:5001; background-color:#F5F5F5;", "innerHTML":"Paste content from Microsoft Word<br><small>(Inserting will replace existing content.)</small>"});
   this._guiClipboardNode=$E("div", {"contentEditable":"true", "style":"border:1px solid #333; background-color:#FFF; width:400px; height:300px; overflow:auto;"});
   
   this._blackout=$E("div");
   Style.setAttributes(this._blackout, {"position":"absolute", "top":"0px", "left":"0px", "bottom":"0px", "right":"0px", "backgroundColor":"#000", "zIndex":"5000", "opacity":".5"});
   
   var cancelLink=$E("a", {"href":"javascript:void(0);", "innerHTML":"Cancel", "style":"margin-right:10px;"});
   var insertLink=$E("a", {"href":"javascript:void(0);", "innerHTML":"Insert"});
   
   Event.observe(cancelLink, "click", function(){ _this.hideGUIClipboard(); });
   Event.observe(insertLink, "click", function(){ _this.pasteFromGUIClipboard(); });
   
   // Build the layout
   DOM.insert(this._clipboardContainer, this._guiClipboardNode);
   DOM.insert(this._clipboardContainer, cancelLink);
   DOM.insert(this._clipboardContainer, insertLink);
   
   // If the editableNode is a text input then toggle it's visibility so we default to the GUI view
   DOM.replace(el, this._node);
   
   DOM.insert(this._editorContainer, this._htmlNode);
   DOM.insert(this._editorContainer, this._guiNode);
   
   DOM.insert(this._node, this._toolbarContainer);
   DOM.insert(this._node, this._editorContainer);
   DOM.insert(this._node, this._footerContainer);
   
   //DOM.insert(this._node, this._guiClipboardNode);
   
   // Size up the gui node if the original node is a text input
   if(this._originalNodeIsTextualInput)
   {
      Style.setAttributes(this._guiNode, {"width":Style.get(this._htmlNode, "width"), "height":Style.get(this._htmlNode, "height")});
   }
   
   this.exec("switchtoguimode");
   
   // Build toolbar
   for(var i=0; i<toolset.length; i++)
   {
      var a=$E("a", {"innerHTML":"<img src='http://resources.gd-ks.com/codebase/js/components/RTE/images/icon_" + toolset[i].toLowerCase().replace(/\s/g, "") + ".gif' title='" + toolset[i] + "'>"});
      
      Event.observe(a, "click", function(e){ _this.exec(e.command); }, {"command":toolset[i].toLowerCase().replace(/\s/g, "")});
      //Event.observe(a, "click", (function(command){ alert("CMD: " + command); this.exec(command); }).bind(this, toolset[i].toLowerCase().replace(/\s/g, "_")));
      
      DOM.insert(this._toolbarContainer, a);
      
      delete a;
   }
   
   // Setup the events
   this._initEventListeners();
}

RTE.prototype.showGUIClipboard=function()
{
   DOM.insert(this._blackout);
   DOM.insert(this._clipboardContainer);
   
   Style.setAttributes(this._blackout, {"position":"fixed", "top":"0px", "left":"0px", "bottom":"0px", "right":"0px", "backgroundColor":"#000", "zIndex":"5000", "opacity":".5"});
   
   Element.center(this._clipboardContainer);
};

RTE.prototype.hideGUIClipboard=function()
{
   DOM.remove(this._blackout);
   DOM.remove(this._clipboardContainer);
   
   this._guiClipboardNode.innerHTML="";
};


// This needs to work by remembering the location of the cursor when it's moved then using "inserthtml" or pasteHTML depending on browser, for now it replaces the content
RTE.prototype.pasteFromGUIClipboard=function()
{
   /*this.hideGUIClipboard();
   DOM.setCaretPosition(this._guiNode, 0);
   document.execCommand("inserthtml", false, MSWord.clean(this._guiClipboardNode.innerHTML));
   this._updateHTML();*/
   
   this._guiNode.innerHTML=MSWord.clean(this._guiClipboardNode.innerHTML);
   
   this.hideGUIClipboard();
   
   this._updateHTML();
};


RTE.prototype.setHTML=function(html)
{
   this._htmlNode.value=html;
   
   this._updateGUI();
};

RTE.prototype.getHTML=function()
{
   return this._htmlNode.value;//.replace(/&lt;/g, "<").replace(/&gt;/g, ">");
};

// Update the source HTML in the primitive from the node
RTE.prototype._updateGUI=function()
{
   this._guiNode.innerHTML=this._htmlNode.value;
};

RTE.prototype._updateHTML=function()
{
   this._htmlNode.value=RTE.clean(this._guiNode.innerHTML);
};

RTE.prototype._initEventListeners=function()
{
   var _this=this;
   
   // Manage events
   Event.observe(this._guiNode, "keyup", function(){ _this._updateHTML(); }); // Make the HTML reflect the GUI
   Event.observe(this._htmlNode, "keyup", function(){ _this._updateGUI(); }); // Make the HTML reflect the GUI
   
   // Saving this for later
   //Event.observe(this._guiNode, "paste", function(e){ for(var key in e){ document.body.innerHTML+=key + ": " + e[key] + "<br>"; } });
};

RTE.prototype.destroy=function()
{
   DOM.remove(this._editorContainer);
   
   DOM.replace(this._node, this._guiNode);
   
   this._guiNode.contentEditable=false;
   
   delete this;
};

RTE.prototype.execInstanceCommand=function(cmd)
{
   // Get instance
   this._guiNode.focus();
   
   this.exec(cmd);
};


// Handle all functionality
RTE.prototype.exec=function(cmd)
{
   switch(cmd)
   {
      case "bold"                : 
      case "italic"              : 
      case "underline"           : document.execCommand(cmd, false, DOM.getSelection());
         break;

      case "createlink"                : document.execCommand(cmd, false, prompt("Enter a URL: "));
         break;

      case "unlink"              : 
      case "insertorderedlist"   : 
      case "insertunorderedlist" : document.execCommand(cmd, false, null);
         break;
         
      case "switchtohtmlmode"    : Style.setAttributes(this._htmlNode, {"display":"block"});
                                   Style.setAttributes(this._guiNode, {"display":"none"});
         break;
         
      case "switchtoguimode"     : Style.setAttributes(this._guiNode, {"display":"block"});
                                   Style.setAttributes(this._htmlNode, {"display":"none"});
         break;

      case "pastefrommsword"     : this.showGUIClipboard(this._guiClipboardNode);
                                   //this.setHTML(MSWord.clean(this._guiClipboardNode.innerHTML));
                                   //this._updateGUI();
         break;
   }
   
   this._updateHTML();
};

RTE.clean=function(content)
{
   return content.replace('class="Apple-style-span" ', "");
};


// Handle Behaviors(create default RTE's from class flagged textareas)
// TODO: Preload images
RTE.init=function()
{
   Enumerable.map($$(".flag_rte"), function(el){ new RTE(el, RTE.TOOLSET_STANDARD); }); // STANDARD
   Enumerable.map($$(".flag_rte_basic"), function(el){ new RTE(el, RTE.TOOLSET_BASIC); }); // BASIC
}

RTE.instances=[];



































var MSWord={

   clean: function cleanMSWord(content)
          {
             var bull=String.fromCharCode(8226);
             var middot=String.fromCharCode(183);
          
             // paste_replace_list
             //var rl=('\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013,&ndash;,\u2014,&mdash;,\u2015|\u2212,-').split(",");
             var rl=('\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');
          
             for (var i=0; i<rl.length; i+=2)
                content=content.replace(new RegExp(rl[i], 'gi'), rl[i+1]);
          
             // Convert MsoHeading to strong tags, overwrites, H1-6
             content=content.replace(new RegExp('<p class=MsoHeading.*?>(.*?)<\/p>', 'gi'), '<p><b>$1</b></p>');
          
             content=content.replace(new RegExp('tab-stops: list [0-9]+.0pt">', 'gi'), '">' + "--list--");
             content=content.replace(new RegExp(bull + "(.*?)<BR>", "gi"), "<p>" + middot + "$1</p>");
             content=content.replace(new RegExp('<SPAN style="mso-list: Ignore">', 'gi'), "<span>" + bull); // Covert to bull list
             content=content.replace(/<o:p><\/o:p>/gi, "");
             content=content.replace(new RegExp('<br style="page-break-before: always;.*>', 'gi'), '-- page break --'); // Replace pagebreaks
             content=content.replace(new RegExp('<(!--)([^>]*)(--)>', 'g'), "");  // Word comments
          
             // Remove span elements
             content=content.replace(/<\/?span[^>]*>/gi, "");
          
             // Remove style attributes
             content=content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)', 'gi'), "<$1$3");
          
             content=content.replace(/<\/?font[^>]*>/gi, "");
          
             // Remove class attributes
             content=content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3");
          
             // Commented because document_base_url isn't implemented
             //content=content.replace(new RegExp('href="?' + MSWord._escape("" + document.location) + '', 'gi'), 'href="' + RTE._document_base_url);
             content=content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
             content=content.replace(/<\\?\?xml[^>]*>/gi, "");
             content=content.replace(/<\/?\w+:[^>]*>/gi, "");
             content=content.replace(/-- page break --\s*<p>&nbsp;<\/p>/gi, ""); // Remove pagebreaks
             content=content.replace(/-- page break --/gi, ""); // Remove pagebreaks
          
             // Create p elements when new line 
             if(Browser.isIE)
             {
                content=content.replace(/<\/?p[^>]*>/gi, "");
             }
             else
             {
                content=content.replace('', '' ,'gi');
                content=content.replace('</p>', '<br /><br />' ,'gi');
             }
          
             content=content.replace(/<\/?div[^>]*>/gi, "");
          
             // Convert middot lists to ul's
             var div=document.createElement("div");
             div.innerHTML=content;
          
             // paste_unindented_list_class
             while (MSWord._convertMiddots(div, "--list--")) ; // bull
             while (MSWord._convertMiddots(div, middot)) ; // Middot
             while (MSWord._convertMiddots(div, bull)) ; // bull
          
             content=div.innerHTML;
          
             // Replace all headers with strong and fix some other issues
             content=content.replace(/<h[1-6]>&nbsp;<\/h[1-6]>/gi, '<p>&nbsp;&nbsp;</p>');
             content=content.replace(/<h[1-6]>/gi, '<p><b>');
             content=content.replace(/<\/h[1-6]>/gi, '</b></p>');
             content=content.replace(/<b>&nbsp;<\/b>/gi, '<b>&nbsp;&nbsp;</b>');
             content=content.replace(/^(&nbsp;)*/gi, '');
          
             content=content.replace(/--list--/gi, ""); // Remove --list--
             
             // MORE CLEANUP
             
             // Strip meta tags
             content=content.replace(/<meta[^>]*>/gi, "");

             // Strip link tags
             content=content.replace(/<link[^>]*>/gi, "");

             // Strip style tags
             content=content.replace(/<\/?style[^>]*>/gi, "");

             // Strip comments
             content=content.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g, "");

             // Strip whitespace
             content=content.replace(/ {2,}/g, " ");

             // Strip blank lines
             content=content.replace(/\n\r{2,}/g, "\n");
          
             // Run the normal cleanup
             //window.setTimeout('tinyMCE.execCommand("mceCleanup");', 1); // Do normal cleanup detached from this thread
             
             return content;
          },
   
   _escape: function(s)
            {
                var l="?.\\*[](){}+^$:";
                var o="";
            
                for(var i=0; i<s.length; i++)
                {
                   var c=s.charAt(i);
            
                   if(l.indexOf(c) != -1)
                      o += '\\' + c;
                   else
                      o += c;
                }
            
                return o;
            }, 
        
   _convertMiddots: function(div, search)
          {
             var mdot=String.fromCharCode(183);
             var bull=String.fromCharCode(8226);

             var nodes=div.getElementsByTagName("p");
             var prevul;
             
             for(var i=0; i<nodes.length; i++)
             {
                var p=nodes[i];
                
                // Is middot
                if(p.innerHTML.indexOf(search) == 0)
                {
                   var ul=document.createElement("ul");

                   // Add the first one
                   var li=document.createElement("li");
                   li.innerHTML=p.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
                   ul.appendChild(li);

                   // Add the rest
                   var np=p.nextSibling;
                   
                   while(np)
                   {
                      // If the node is whitespace, then
                      // ignore it and continue on.
                      if(np.nodeType == 3 && new RegExp('^\\s$', 'm').test(np.nodeValue))
                      {
                         np=np.nextSibling;
                         continue;
                      }

                      if(search == mdot)
                      {
                         if(np.nodeType == 1 && new RegExp('^o(\\s+|&nbsp;)').test(np.innerHTML))
                         {
                            // Second level of nesting
                            if(!prevul)
                            {
                               prevul=ul;
                               ul=document.createElement("ul");
                               prevul.appendChild(ul);
                            }
                            
                            np.innerHTML=np.innerHTML.replace(/^o/, '');
                         }
                         else
                         {
                            // Pop the stack if we're going back up to the first level
                            if(prevul)
                            {
                               ul=prevul;
                               prevul=null;
                            }
                            
                            // Not element or middot paragraph
                            if(np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
                            {
                               break;
                            }
                         }
                      }
                      else
                      {
                         // Not element or middot paragraph
                         if(np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
                         {
                            break;
                         }
                      }

                      var cp=np.nextSibling;
                      var li=document.createElement("li");
                      li.innerHTML=np.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
                      np.parentNode.removeChild(np);
                      ul.appendChild(li);
                      np=cp;
                   }

                   p.parentNode.replaceChild(ul, p);

                   return true;
                }
             }

             return false;
          }

};