
var controls = [
  {name:'bold',     scenario:'simple',    title:'_ Strong emphasis - Bold text',   tags:{open:'<strong>', close:'</strong>'}, func:'inline',   allow:/bold|italic|underline|quote/},
  {name:'italic',   scenario:'simple',    title:'_ Mild emphasis - Italic text',   tags:{open:'<em>', close:'</em>'}, func:'inline',           allow:/bold|italic|underline|quote/},
  {name:'underline',scenario:'simple',    title:'_ Underlined text',               tags:{open:'<span style="text-decoration:underline;">', close:'</span>'}, func:'inline', allow:/bold|italic|underline|quote/},
  {name:'quote',    scenario:'simple',    title:'_ Quoted text',                   tags:{open:'<q>', close:'</q>'},        func:'inline',      allow:/bold|italic|underline|quote/},
  {name:'h2',       scenario:'advanced',  title:'_ Level 2 heading',               tags:{open:'<h2>',close:'</h2>'},       func:'inline',      allow:/bold|italic|underline|quote/},
  {name:'h3',       scenario:'advanced',  title:'_ Level 3 heading',               tags:{open:'<h3>',close:'</h3>'},       func:'inline',      allow:/bold|italic|underline|quote/},
  {name:'image',    scenario:'advanced',  title:'Insert image',                    tags:{open:'<img '},                    func:'image',       allow:/^$/},
  {name:'document', scenario:'advanced',  title:'Insert a document link',          tags:{open:'<a '},                      func:'document',    allow:/^$/},
  {name:'link',     scenario:'advanced',  title:'Make the selection a link',       tags:{open:'<a '},                      func:'link',        allow:/^$/},
  {name:'list_ul',  scenario:'lists',  title:'Create an unordered list',        tags:{open:'<ul>', close:'</ul>'},      func:'list',        allow:/^$/},
  {name:'list_ol',  scenario:'lists',  title:'Create an ordered list',          tags:{open:'<ol>', close:'</ol>'},      func:'list',        allow:/^$/},
  {name:'table',    scenario:'advanced',  title:'Create a table',          tags:{open:'<table>', close:'</table>'},      func:'table',        allow:/^$/},
  {name:'rule',     scenario:'advanced',  title:'Create a dividing line',          tags:{open:'<hr />'},                   func:'divider',     allow:/^$/}
];

var counter = 0;

var SS_ENABLED = 1, SS_DISABLED = 2, SS_UNAVAILABLE = 3;

function ControlListener(controller, elem, props, state) {
  EventListener.call(this, elem);
  var self = this;
  this.controller = controller;
  this.name = props.name;
  this.tags = props.tags;
  this.allow = props.allow;
  this.unclosed = false;
  this.state = state | SS_ENABLED;

  var imgs = {};

  this.init = function() {
    imgs.on = create("img");
    imgs.on.src = "../g/controls/" + elem.id + "_on.png";
    imgs.off = create("img");
    if (state == SS_UNAVAILABLE) {
      imgs.off.src = "../g/controls/" + elem.id + "_dis.png";
      this.register('click', this.unavailable);
    }
    else {
      imgs.off.src = "../g/controls/" + elem.id + ".png";
      this.register('click', this.format);
    }
    imgs.dis = create("img");
    imgs.dis.src = "../g/controls/" + elem.id + "_dis.png";

    elem.appendChild(imgs.off);
  }

  this.disable = function() {
    if (self.state != SS_UNAVAILABLE) {
      self.state = SS_DISABLED;
      imgs.on.src = imgs.dis.src;
      self.repaint();
    }
  }

  this.enable = function() {
    if (self.state != SS_UNAVAILABLE) {
      self.state = SS_ENABLED;
      imgs.on.src = "../g/controls/" + elem.id + "_on.png";
      self.repaint();
    }
  }

  this.format = function(evt) {
    self.invoke(evt);
    self.cancelDefault();

    if (self.state == SS_ENABLED) {
      try {
        controller[props.func](self);
      } catch(e) {alert('Errors occurred in ControlListener::format()');report_errors(e);}
    }
  }

  this.unavailable = function(evt) {
    self.invoke(evt);
    self.cancelDefault();
    alert('This action is not available until the new entry has been posted.');
  }

  this.repaint = function() {
    if (self.unclosed || self.state == SS_DISABLED) {
      self.elem.replaceChild(imgs.on, imgs.off);
      if (self.unclosed == true) {
        self.elem.title = self.elem.title.replace(/Start /, 'Stop ');
      }
    }
    else {
      self.elem.replaceChild(imgs.off, imgs.on);
      self.elem.title = self.elem.title.replace(/Stop /, 'Start ');
    }
  }

  this.init();
}
ControlListener.prototype = new EventListener;

function Text_Controller(fieldset) {

  this.control_menu = undefined;
  this.controls = [];

  var container = undefined;

  var img_container = undefined;
  var doc_container = undefined;
  var table_container = undefined;

  this.field = fieldset.get('textarea')(0);
  this.stack = [];

  var self = this;

  this.req = null;

  this.imagepicker = false;
  this.documentpicker  = false;

  function __construct() {
    
		var simplecontrols = (/simple/.test(fieldset.className)) ? 1 : 0;
		var listcontrols   = (/lists/.test(fieldset.className)) ? 1 : 0;
		
		self.control_menu = ref('topControlsMenu').cloneNode(false);
    self.control_menu.id = 'ctrl' + (++counter);
    self.control_menu.className = "controlMenu";
    var btn, img, listener;
    var addition = (get('form')(0).action.search(/add/) != -1);
    for (var i = 0, m = controls.length; i < m; i++) {
			if (simplecontrols && controls[i].scenario != "simple") { continue; }
			if (listcontrols   && controls[i].scenario != "lists" && controls[i].scenario != "simple") { continue; }

		  btn = create('button');
      btn.id = controls[i].name;
      btn.title = controls[i].title.replace(/_/, "Start");
      btn.className = "small";
      if (addition && (btn.id == "image" || btn.id == "document")) {
                listener = new ControlListener(self, btn, controls[i], SS_UNAVAILABLE);
        btn.className += " disabled";
        btn.title += " (This action is currently unavailable)";
      }
      else {
        listener = new ControlListener(self, btn, controls[i]);
      }
      self.controls[self.controls.length] = listener;
      self.control_menu.appendChild(btn);
    }

    // create the image container
    img_container = create('div');
    img_container.id = "img_container" + counter;
    img_container.className = "container hidden";
    if (typeof img_container.get == "undefined") {
      img_container.get = get;
    }
    img_container.appendChild(create(' ',Node.TEXT_NODE));

    // create the document container
    doc_container = create('div');
    doc_container.id = "doc_container" + counter;
    doc_container.className = "container hidden";
    if (typeof doc_container.get == "undefined") {
      doc_container.get = get;
    }
    doc_container.appendChild(create(' ',Node.TEXT_NODE));

    // create the table container
    table_container = create('div');
    table_container.id = "table_container" + counter;
    table_container.className = "container tables hidden";
    if (typeof table_container.get == "undefined") {
      table_container.get = get;
    }
    table_container.appendChild(create(' ',Node.TEXT_NODE));

    fieldset.insertBefore(table_container, fieldset.get('legend')(0).nextSibling);
    fieldset.insertBefore(doc_container, fieldset.get('legend')(0).nextSibling);
    fieldset.insertBefore(img_container, fieldset.get('legend')(0).nextSibling);
    fieldset.insertBefore(self.control_menu, img_container);
  }

  function wrap(str, tags) {
    return (str.charAt(str.length - 1) == " ") ?
      tags.open + str.substring(0, (str.length - 1)) + tags.close + " " :
      tags.open + str + tags.close;
  }

  function getFieldSelection(field) {
    var selection = {start:null,end:null,scrollTop:null,txt:null};
    if (document.selection) {
      selection.txt = document.selection.createRange().text;
      field.focus();
    }
    else if (self.field.selectionStart || self.field.selectionStart == '0') {
      selection.start = field.selectionStart;
      selection.end   = field.selectionEnd;
      selection.scrollTop = field.scrollTop;
      selection.txt = (field.value).substring(selection.start, selection.end);
    }
    return selection;
  }

  function updateFieldSelection(field, selection, new_txt) {
    var cursor = selection.start+new_txt.length;
    if (document.selection) {
      document.selection.createRange().text = new_txt;
      // reposition the caret?
      //if (this.field.createTextRange) {this.field.caretPos = document.selection.createRange().duplicate()};
    }
    else {
      field.value = field.value.substring(0, selection.start) + new_txt + field.value.substring(selection.end, field.value.length);
      field.focus();
      field.selectionStart=cursor;
      field.selectionEnd=cursor;
      field.scrollTop=selection.scrollTop;
    }
  }

  this.updateControlStatus = function(control, state) {
    for (var i = 0, m = this.controls.length; i < m; i++) {
      if (this.controls[i].name == control.name) {
        continue;
      }
      if (state == SS_ENABLED && this.controls[i].state == SS_DISABLED) {
        this.controls[i].enable();
      }
      else if (state == SS_DISABLED && !this.controls[i].unclosed && this.controls[i].state != SS_DISABLED) {
        if (!control.allow.test(this.controls[i].name)) {
          this.controls[i].disable();
        }
      }
    }

  }

  this.inline = function(control) {
    try {
      var s = getFieldSelection(this.field), new_text;

      if (s.txt == undefined || s.txt.length == 0) {
        if (!control.unclosed) {
          // disable all controls that cannot be children of this element
          this.updateControlStatus(control, SS_DISABLED);
          new_txt = control.tags.open;
          control.unclosed = true;
          control.repaint();
          this.stack.push(control);
        }
        else {

          // re-enable all controls that cannot be children of this element
          // not ideal solution since will only re-enable on the last item
          // in the stack...
          if (this.stack.length == 1) {
            this.updateControlStatus(control, SS_ENABLED);
          }

          new_txt = "";
          if (this.stack[this.stack.length-1] != control) {
            var t;
            do {
              t = this.stack.pop();
              new_txt += t.tags.close;
              t.unclosed = false;
              t.repaint();
            } while (t != control);
          }
          else {
            new_txt = control.tags.close;
            this.stack.pop();
            control.unclosed = false;
            control.repaint();
          }
        }
      }
      else {
        new_txt = wrap(s.txt, control.tags);
      }

      updateFieldSelection(this.field, s, new_txt);

    } catch(e) {alert('Errors occurred in Text_Controller::inline()');report_errors(e);}

  }

  this.link = function(control) {
    control.unclosed = true;
    control.repaint();

    var s = getFieldSelection(this.field), new_text;

    if (s.txt == undefined || s.txt.length == 0) {
      alert("Please select the text that you wish to make into a link first.");
    }
    else {
      var l = prompt('Enter URI...','http://')
      if (l != null) {
        var t = prompt('Enter additional content to describe the resource the link points to...');
        new_txt = '<a href="' + l + '"';
        if (t != null) {
          new_txt += ' title="' + t + '"';
        }
        new_txt += '>' + s.txt + "</a>";
        updateFieldSelection(this.field, s, new_txt);
      }
    }

    control.unclosed = false;
    control.repaint();

  }

  this.list = function(control) {
    control.unclosed = true;
    control.repaint();

    var s = getFieldSelection(self.field), new_text = "\n";
    var items = [], item = "", i = 0;

    do {
      item = prompt("Enter list item " + (++i) + "\n(Click Cancel or OK on an empty string to finish)", "", "Create A List");
      if (item === null || item.length == "") {
        break;
      }
      items[items.length] = item;
    } while (true);

    if (items.length > 0) {
      for (i = 0, m = items.length; i < m; i+=1) {
        new_text += "<li> " + items[i] + "</li>\n";
      }

      new_txt = wrap(new_text, control.tags) + "\n";

      updateFieldSelection(this.field, s, new_txt);
    }

    control.unclosed = false;
    control.repaint();
  }

  this.divider = function(control) {
    control.unclosed = true;
    control.repaint();

    var s = getFieldSelection(self.field);
    var new_txt = "\n\n" + control.tags.open + "\n\n";
    updateFieldSelection(this.field, s, new_txt);

    control.unclosed = false;
    control.repaint();
  }


  this.document = function(control) {
    try {
      if (control.unclosed) {
        // re-enable all other controls
        this.updateControlStatus(control, SS_ENABLED);

        doc_container.className = "container hidden";
        //container.innerHTML = "";
        control.unclosed = false;
        control.repaint();
      }
      else {
        // disable all other controls
        this.updateControlStatus(control, SS_DISABLED);

        if (!self.documentpicker) {
          var key = ref('key').value;
          var module = ref('module').value;
          var uri = '../manage/' + module + '.quickdoc,' + key;

            if (window.XMLHttpRequest) {
              self.req = new XMLHttpRequest();
            } else if (window.ActiveXObject) {
                self.req = new ActiveXObject("Microsoft.XMLHTTP");
            }
          self.req.onreadystatechange = function() {
            if (self.req.readyState == 4) {
              doc_container.innerHTML = self.req.responseText;
                (function(elem) {
                  elem.onclick = function(evt) {
                  try {
                    cancelDefault(evt);
                  var c = elem.parentNode.getElementsByTagName('input');
                  var s = getFieldSelection(self.field), new_text;
                  var opt = elem.parentNode.getElementsByTagName('select');

                  new_txt = '<a href="' + c[0].value + '"';
                  if (c[2].value.length > 0) { new_txt += ' title="' + c[2].value + '"'; }
                  if (typeof c[3].checked != 'undefined' && c[3].checked == true) { new_txt += ' class="new"'; }
                  new_txt += ">";
                  if (c[1].value.length > 0) { new_txt += c[1].value; }
                  else { new_txt += c[0].value; }
                  new_txt += "</a>";

                  updateFieldSelection(self.field, s, new_txt);

                  doc_container.className = "container hidden";

                  self.updateControlStatus(control, SS_ENABLED);

                  control.unclosed = false;
                  control.repaint();
                  } catch(e) {alert(e.message);}
                  };
                }).Iterate(doc_container.get('button')());
              }
          };
            self.req.open("GET", uri);
            self.req.send(null);

            self.documentpicker = true;
        }

        doc_container.className = "container visible";
        control.unclosed = true;
        control.repaint();

      }
    } catch(e) {alert('Errors occurred in Text_Controller::image()');report_errors(e);}
  }

  this.image = function(control) {
    try {
      if (control.unclosed) {
        // re-enable all other controls
        this.updateControlStatus(control, SS_ENABLED);

        img_container.className = "container hidden";
//        container.innerHTML = "";
        control.unclosed = false;
        control.repaint();
      }
      else {
        // disable all other controls
        this.updateControlStatus(control, SS_DISABLED);

        if (!self.imagepicker) {
          var key = ref('key').value;
          var module = ref('module').value;
          var uri = '../manage/' + module + '.quickimage,' + key;
            if (window.XMLHttpRequest) {
              self.req = new XMLHttpRequest();
            } else if (window.ActiveXObject) {
                self.req = new ActiveXObject("Microsoft.XMLHTTP");
            }
          self.req.onreadystatechange = function() {
            if (self.req.readyState == 4) {
                img_container.innerHTML = self.req.responseText;
                (function(elem) {
                  elem.onclick = function(evt) {
                    cancelDefault(evt);
                  var c = elem.parentNode.getElementsByTagName('input');
                  var s = getFieldSelection(self.field), new_text;
                  var opt = elem.parentNode.getElementsByTagName('select');

                  new_txt = '<img src="' + c[0].value + '" height="' + c[1].value.replace(/px/,'') + '" width="' + c[2].value.replace(/px/,'') + '"';
                  if (c[3].value.length > 0) {new_txt += ' alt="' + c[3].value + '"';}
                  if (opt[0].value != -1) {new_txt += ' class="' + opt[0].value + '"';}
                  new_txt += '/>';

                  updateFieldSelection(self.field, s, new_txt);

                  img_container.className = "container hidden";

                  self.updateControlStatus(control, SS_ENABLED);

                  control.unclosed = false;
                  control.repaint();

                  };
                }).Iterate(img_container.get('button')());
              }
          };
            self.req.open("GET", uri);
            self.req.send(null);

          self.imagepicker = true;
        }

        img_container.className = "container visible";
        control.unclosed = true;
        control.repaint();

      }
    } catch(e) {alert('Errors occurred in Text_Controller::image()');report_errors(e);}
  }

  this.table = function(control) {
    try {
      if (control.unclosed) {
        // re-enable all other controls
        this.updateControlStatus(control, SS_ENABLED);

        table_container.className = "container tables hidden";
//        container.innerHTML = "";
        control.unclosed = false;
        control.repaint();
      }
      else {
        // disable all other controls
        this.updateControlStatus(control, SS_DISABLED);

        // clean out all the child elements since want to start afresh each time
        while (table_container.hasChildNodes()) {
          table_container.removeChild(table_container.firstChild);
        }

        if (navigator.appName.indexOf('Internet Explorer') != -1) {
          // helper information
          var helper = create('p');
          helper.appendChild(create('This feature is not available in Microsoft Internet Explorer currently. Tables must be marked up manually, or alternatively use a different browser to enable this feature - eg Firefox.', Node.TEXT_NODE));          
          table_container.appendChild(helper);
        }
        else {
          
          // set up the default table environment
          var x = create('textarea');
          var c = create('td');
          c.appendChild(x);
          var r = create('tr');
          var t = create('table');
          t.id = 'tbuilder';
          r.appendChild(c);
          r.appendChild(c.cloneNode(true));
          t.appendChild(r);
          t.appendChild(r.cloneNode(true));
  
          // helper information
          var helper = create('p');
          helper.appendChild(create('Use the buttons below to create the number of rows and columns you want for your table and then enter the content in each cell. If the cell is a column or row header wrap the content with bars (eg. |Column Head|). You should also enter a caption which serves as a title for the table. Please note this control will only create simple tables. You can manually enter markup into table cells (eg bold text - <strong></strong>).', Node.TEXT_NODE));
  
          // summay input box
          var caption_div = create('div');
          var caption_label = create('label');
          caption_label.setAttribute('for', 'caption');
          caption_label.appendChild(create('Table Caption:', Node.TEXT_NODE));
          var caption = create('input');
          caption.id = 'caption';
          caption.size = '60';
          caption.maxlength = '100';
          caption_div.appendChild(caption_label);
          caption_div.appendChild(caption);
  
          // set up the add/delete rows/columns buttons
          var btn1 = create('button');
          btn1.appendChild(create('Add Row', Node.TEXT_NODE));
          btn1.onclick = function(evt) {
            cancelDefault(evt);
            t.appendChild(r.cloneNode(true));
          }
          var btn2 = create('button');
          btn2.appendChild(create('Delete Row', Node.TEXT_NODE));
          btn2.onclick = function(evt) {
            cancelDefault(evt);
            if (t.childNodes.length > 1) {
              t.removeChild(t.childNodes.item(t.childNodes.length - 1));
            }
          }
          var btn3 = create('button');
          btn3.appendChild(create('Add Column', Node.TEXT_NODE));
          btn3.onclick = function(evt) {
            cancelDefault(evt);
            var rows = table_container.getElementsByTagName('tr');
            for(i = 0, m = rows.length; i < m; i++) {
              rows[i].appendChild(c.cloneNode(c));
            }
          }
          var btn4 = create('button');
          btn4.appendChild(create('Delete Column', Node.TEXT_NODE));
          btn4.onclick = function(evt) {
            cancelDefault(evt);
            var rows = table_container.getElementsByTagName('tr');
            for(i = 0, m = rows.length; i < m; i++) {
              if (rows[i].childNodes.length > 2) {
                rows[i].removeChild(rows[i].childNodes.item(rows[i].childNodes.length - 1));
              }
            }
          }
  
          var btn5 = create('button');
          btn5.appendChild(create('Add Table', Node.TEXT_NODE));
          btn5.onclick = function(evt) {
            cancelDefault(evt);
  
            var s = getFieldSelection(self.field), new_txt = '';
  
            // get the table content to put into the textarea
            // note try to do this with some basic maths rather than looping through all cells.
            var rows = table_container.getElementsByTagName('tr').length;
            var cols = parseInt(table_container.getElementsByTagName('td').length / rows);
            var texts = table_container.getElementsByTagName('textarea');
            k = 0;
            new_txt += "\n<table>\n";
  
            if (caption.value.length > 0) {
              new_txt += "<caption>" + caption.value + "</caption>\n";
            }
  
            for (i = 0; i < rows; i++) {
              new_txt += "\n<tr>\n";
              for (j = 0; j < cols; j++) {
                if (texts[k].value.match(/^\|(.+)\|$/)) {
                  new_txt += "<th>" + texts[k].value.slice(1,-1) + "</th>\n";
                }
                else {
                  new_txt += "<td>" + texts[k].value + "</td>\n";
                }
                k+=1;
              }
              new_txt += "</tr>\n";
            }
            new_txt += "\n</table>\n";
  
  
            updateFieldSelection(self.field, s, new_txt);
  
            table_container.className = "container tables hidden";
            self.updateControlStatus(control, SS_ENABLED);
            control.unclosed = false;
            control.repaint();
  
          }
  
          table_container.appendChild(helper);
          table_container.appendChild(caption_div);
          table_container.appendChild(t);
          table_container.appendChild(btn1);
          table_container.appendChild(btn2);
          table_container.appendChild(btn3);
          table_container.appendChild(btn4);
          table_container.appendChild(btn5);
        }
        table_container.className = "container tables visible";
        control.unclosed = true;
        control.repaint();

      }
    } catch(e) {alert('Errors occurred in Text_Controller::table()');report_errors(e);}
  }


  __construct();

}


function __init_text_controls() {
  var fieldsets = get('fieldset')(), tc;
  if (fieldsets != null) {
    (function(elem){
      if (/controls/.test(elem.className)) {
        var tc = new Text_Controller(elem);
      }
    }).Iterate(fieldsets);
  }

}

addLoadEvent(__init_text_controls);

/** NOTES
[1]. have to use the normal DOM method call getElementsByTagName,
since get has not been assigned in IE browsers :(
*/
