Lycos.use("util/captcha");
Lycos.use("ui");

/**
 * The class used for a guestbook module.
 * @constructor
 * @param {integer} instId The instance id of the module being constructed.
 * @param {integer} subInstId The sub-instance id of the module being constructed.
 * @base Lycos.webon.module
 */
Lycos.webon.modules.guestbook = function(instId, subInstId) {

  /**
   * The type of module.
   * @see Lycos.webon.module
   */
  this.type = "guestbook";
  this.lyModule = Lycos.webon.module;
  this.lyModule(instId, subInstId);

  /**
   * A variable holding the text of the JS object initialization.
   */
  this.jsObj = "(Lycos.webon.getInstance('"+this.type+"', "+this.instId+", "+this.subInstId+"))"

  var tmp = this;
  this.addEventListener( "showEdit", function(e){ tmp.onLightbox(e); } ); 
  this.addEventListener( "saveQuestions", function(e){ tmp.onSaveQuestions(e); } ); 
  this.addEventListener( "removeQuestion", function(e){ tmp.onRemoveQuestion(e); } ); 
  this.addEventListener( "comment", function(e){ tmp.onComment(e); } ); 
  this.addEventListener( "markEntryAsSpam", function(e){ tmp.onMarkEntryAsSpam(e); } ); 
  this.addEventListener( "unmarkEntryAsSpam", function(e){ tmp.onUnmarkEntryAsSpam(e); } ); 
  this.addEventListener( "getEntries", function(e){ tmp.onGetEntries(e); } ); 
  this.addEventListener( "deleteEntry", function(e){ tmp.onDeleteEntry(e); } ); 
  this.addEventListener( "approveEntry", function(e){ tmp.onApproveEntry(e); } ); 

  this.commentSubmitting = "Submitting...";
  this.commentSubmitted = "Submit";
  /**
   * Number to start at for new question ideas. These numbers are temporary but should not have conflicts.
   */
  this.newQuestionCounter = 100000001;

  /**
   * True if spam should be shown to the owner.
   */
  this.showspams = false;
  
  /**
   * Todo: I'm not sure where this is called.
   */
  this.checkForm = function() {}

  /**
   * Marks or unmarks an entry as spam.
   * @param {DomElement} obj The node triggering the action.
   * @param {integer} id The id of the entry to mark/unmark as spam.
   * @param {boolean} b True if entry is spam.
   * @see #toggleSpamEntry
   */
  this.setSpamEntry = function(obj, id, b) {
    this.lyAjaxObj( {id:id}, (b ? "mark" : "unmark") + "EntryAsSpam");
    return false;
  }
  
  /**
   * Toggles an entry's spam status.
   * @param {DomElement} obj The node triggering the action.
   * @param {integer} id The id of the entry to mark/unmark as spam.
   * @see #setSpamEntry
   */
  this.toggleSpamEntry = function(obj, id) {
    return this.setSpamEntry(obj, id, (obj.innerHTML == "mark"));
  }
  
  /**
   * Sets a variable indicating if spam should dbe showm.
   * @param {boolean} b True if spam should be displayed to the owner.
   * @see #setSpamEntry
   */
  this.setShowSpams = function(b) {
    this.showspams = b;
  }
  
  /**
   * Toggles whether or not spam should be shown.
   * @see #setShowSpam
   */
  this.toggleShowSpams = function() {
    this.showspams = !this.showspams;
    var el = document.getElementById("showSpamLink" + this.instId + "_" + this.subInstId);
    if ( el ) el.innerHTML = this.showspams ? "hide" : "show";
    this.getEntries();
  }

  /**
   * Request a list of comments from the server.
   */
  this.getEntries = function () {
    this.lyAjaxObj({showspams:(this.showspams ? "yes" : "no")}, "getEntries");
    return false;
  }

  /**
   * Updates the display of the entry count based on Ajax response data.
   * @param {object} data The contents of an event.lyResponse data structure.
   */  
  this.updateEntriesCount = function(data) {

	if (data.action == "markEntryAsSpam") {
	  numComm = document.getElementById("numComments"+this.instId+"_"+this.subInstId);
	  numSpam = document.getElementById("numSpams"+this.instId+"_"+this.subInstId);
	  numComm.innerHTML = parseInt(numComm.innerHTML) - 1;
	  numSpam.innerHTML = parseInt(numSpam.innerHTML) + 1;
	}
	else if (data.action == "unmarkEntryAsSpam") {
	  numComm = document.getElementById("numComments"+this.instId+"_"+this.subInstId);
	  numSpam = document.getElementById("numSpams"+this.instId+"_"+this.subInstId);
	  numComm.innerHTML = parseInt(numComm.innerHTML) + 1;
	  numSpam.innerHTML = parseInt(numSpam.innerHTML) - 1;
	}
	else if (data.action == "deleteEntry") {
	  numComm = document.getElementById("numComments"+this.instId+"_"+this.subInstId);
	  numSpam = document.getElementById("numSpams"+this.instId+"_"+this.subInstId);
	  if (data.isspam == "Y" && numSpam ) {
	    numSpam.innerHTML = parseInt(numSpam.innerHTML) - 1;
	  }
	  else {
	    numComm.innerHTML = parseInt(numComm.innerHTML) - 1;
	  }
	}
	else if (data.action == "approveEntry") {
	  numComm = document.getElementById("numComments"+this.instId+"_"+this.subInstId);
	  numSpam = document.getElementById("numSpams"+this.instId+"_"+this.subInstId);
	  markLink = document.getElementById("markLink" + this.instId + "_" + data.id);
	  s = ( markLink && markLink.innerHTML == "unmark" ? numSpam : numComm );
	  s.innerHTML = parseInt(s.innerHTML) + 1;
	}
	else if (data.action == "getEntries" || data.action == "comment") {
	  document.getElementById("numComments"+this.instId+"_"+this.subInstId).innerHTML = data.commentCount;
	  document.getElementById("numSpams"+this.instId+"_"+this.subInstId).innerHTML = data.spamCount;
	  document.getElementById("viewSpam"+this.instId+"_"+this.subInstId).style.display=data.dispViewSpam;
    }
	if (parseInt(document.getElementById("numComments"+this.instId+"_"+this.subInstId).innerHTML) > 0) {
	  document.getElementById("viewCommentCount"+this.instId+"_"+this.subInstId).style.display = "inline";
	  document.getElementById("noComments"+this.instId+"_"+this.subInstId).style.display = "none";
	}
	else {
	  document.getElementById("viewCommentCount"+this.instId+"_"+this.subInstId).style.display = "none";
	  document.getElementById("noComments"+this.instId+"_"+this.subInstId).style.display = "inline";
	}
	spamCount = parseInt(document.getElementById("numSpams"+this.instId+"_"+this.subInstId).innerHTML);
	if (!data.dispViewSpam) {
	  document.getElementById("viewSpam"+this.instId+"_"+this.subInstId).style.display= spamCount > 0 ? "inline" : "none";
	}
  
  }

  /**
   * Sets the HTML of all the guestbook entries.
   * @param {object} data The contents of an event.lyResponse data structure.
   */  
  this.setEntriesHTML = function (data) {
    var cont = document.getElementById("commentList"+this.instId+"_"+this.subInstId);
	cont.innerHTML = data.commentsHTML;
    
	this.updateEntriesCount(data);	
  }
  
  /**
   * Deletes an entry with a particular id
   * @param {integer} comment The id of the entry to delete.
   */  
  this.delEntry = function ( comment ) {
    resp = confirm("Are you sure you would like to delete this entry?");
    if (!resp)
      return false;
    var cmAll = document.getElementById("commentAll"+this.instId+"_"+comment );
    var loading = cmAll.ownerDocument.createElement("div");
    var markLink = document.getElementById("markLink"+this.instId+"_"+comment);
    var isspam = (!markLink || markLink.innerHTML != "unmark" ? "N" : "Y");
    loading.id = "commentDeling"+comment;
    loading.style.backgroundColor = "white";
    loading.style.border = "1px solid black";
    loading.style.color = "black";
    loading.style.padding = "10px";
    loading.innerHTML = "<img src=\"/adm/media/ajax-loader.gif\" alt=\"Please Wait.\"> Deleting entry...";
	markLink = null;
    cmAll.parentNode.replaceChild(loading, cmAll);

    this.lyAjaxObj({id:comment,isspam:isspam}, "deleteEntry");
    return false;
  }

  /**
   * Approves an entry on a moderated guestbook.
   * @param {DomElement} alink The link clicked on to approve the entry.
   * @param {integer} comment The id of the comment to approve.
   */
  this.approveEntry = function( alink, comment ) {
    var loading = alink.ownerDocument.createElement("span");
    loading.id = "commentApproving"+comment;
    loading.style.backgroundColor = "white";
    loading.style.border = "1px solid black";
    loading.style.color = "black";
    loading.innerHTML = "Approving entry...";
    alink.parentNode.replaceChild(loading, alink);
    
    this.lyAjaxObj({id:comment}, "approveEntry");
    return false;
  }

  /**
   * Sends the comment entry form and action to be processed.
   * @param {DomElement} frm The form to be sent to Lycos.webon.module.lyAjaxForm() to be processed.
   */
  this.submitForm = function (frm) {

	// Get the comment entry form's submit button
    var btn = document.getElementById("commentsSubmit"+this.instId+"_"+this.subInstId);

	// Change the button's text to 'Submitting...' and disable it
    if (btn) {
      btn.value = this.commentSubmitting;
      btn.disabled = true;
    }
	
	// Get the iframe from the captcha.tpl that holds the recaptcha form
	var recaptcha_iframe = document.getElementById('recaptcha_iframe' + this.instId + '.' + this.subInstId);

	// Add the recaptcha challenge field from the recaptcha iframe to the form
	frm.recaptcha_challenge_field.value = recaptcha_iframe.contentWindow.document.getElementById('recaptcha_challenge_field').value;
	frm.recaptcha_response_field.value = recaptcha_iframe.contentWindow.document.getElementById('recaptcha_response_field').value;

	// Send the form to be processed by Lycos.webon.module.lyAjaxForm()
    this.lyAjaxForm(frm, 'comment');
  }

  /**
   * Toggles the entry form. Is not used for guestbooks.
   * @deprecated
   */
  this.toggleForm = function (display) {}

  /**
   * Clears the content of the entry form.
   * @param {DomElement} form The form element.
   */
  this.clearForm = function(form) {

    var btn = document.getElementById("commentsSubmit"+this.instId+"_"+this.subInstId);
    if (btn) {
      btn.value = this.commentSubmitted;
      btn.disabled = false;
    }

    var f = document.getElementById("guestbook_form_"+this.instId);
    var e = f.elements;
    for( id in e ) {
      if( e[id] == null || e[id].type == null )
	continue;

      if( e[id].type == "text" || e[id].type == "textarea" || e[id].type == "password" )
	e[id].value = "";
      else if( e[id].type == "checkbox" || e[id].type == "radio" )
	e[id].checked = false;
      else if( e[id].type == "select-one" || e[id].type == "select-multiple" ) {
	e[id].selectedIndex = -1;
      }
    }
  }

  /**
   * Adds a question to the question editing lightbox.
   */
  this.addQuestion = function() {
    var newId = this.newQuestionCounter;
    this.newQuestionCounter += 1;
    var temp = document.getElementById("questionTemplate"+this.instId);
    var newRow = temp.ownerDocument.createElement('div');
    newRow.id = "questionBlock"+this.instId+"_"+newId;
    newRow.className = "questionHolder";//+(this.newQuestionCounter % 2 == 0 ? "" : " alternate");
    newRow.innerHTML = temp.innerHTML.replace(/TEMPLATE/g, newId);
    temp.parentNode.appendChild(newRow);
    newRow.style.display="";
    this.addAnswer(newId,false);
    this.addAnswer(newId,false);
    var inputField = document.getElementById("qinput_"+newId);
    if( inputField )
      inputField.focus();

    this.alternateColors();
  }

  /**
   * Toggles the option to add answers to a question (e.g: multiple choice).
   * @param {integer} quid The question id.
   */
  this.toggleAnswerAdd = function (qid) {
    var idStr = this.instId+"_"+qid;
    var sel = document.getElementById("qtype"+idStr);
    var items = sel.value.split('_');
    var anset = document.getElementById("answerSet"+idStr);
    anset.style.display = (items[1] == '1' ? "" : "none");
    if(anset.scrollIntoView)
      anset.scrollIntoView();
    
  }

  /**
   * Adds an answer to a question (e.g: multiple choice).
   * @param {integer} quid The question id.
   * @param {boolean} grabFocus True if the new answer should grab keyboard focus.
   */
  this.addAnswer = function(qid,grabFocus) {
    var allQsDiv = document.getElementById("allQuestions_"+instId);
    var idStr = this.instId+"_"+qid;
    var temp = document.getElementById("answerTemplate"+idStr);
    var newDiv = temp.cloneNode(true);
    var lnk = document.getElementById("answerLink"+idStr);
    lnk.parentNode.insertBefore(newDiv, lnk.previousSibling);
    newDiv.style.display="";
    var index = newDiv.parentNode.childNodes.length;
    newDiv.id="answerBlock"+idStr+"_"+index;
    for (var c = 0; c < newDiv.childNodes.length; c++) {
      if (newDiv.childNodes[c].tagName == "INPUT") {
        newDiv.childNodes[c].name = "answers["+index+"]["+newDiv.childNodes[c].name+"]";
	if( grabFocus && newDiv.childNodes[c].style.display != 'none' )
	  newDiv.childNodes[c].focus();
        var aTags = newDiv.getElementsByTagName("A");
        if (aTags.length > 0)
          aTags[0].href="javascript:"+this.jsObj+".removeAnswer("+qid+","+index+")";
      }
    }
    if(allQsDiv.scrollTop)
      allQsDiv.scrollTop += 25;
  }

  /**
   * Alternate the colors between added questions.
   */
  this.alternateColors = function() {
    var ct = 0;
    var parent = document.getElementById("questionTemplate"+this.instId).parentNode;
    var kids = parent.childNodes;
    for( i in kids ) {
      if( kids[i] && kids[i].className && kids[i].className.indexOf("questionHolder") >= 0 ) {
	kids[i].className = "questionHolder" + (ct ? " alternate" : "");
	ct = (ct+1)%2;
      }
    }
  }    

  /**
   * Removes an answer from the list of multiple-choice answers while editing.
   * @param {integer} quid The question id.
   * @param {integer} id The id of the answer to remove.
   */
  this.removeAnswer = function (qid,id) {
    var div = document.getElementById("answerBlock"+this.instId+"_"+qid+"_"+id);
    div.parentNode.removeChild(div);
  }

  /**
   * Requests the "edit questions" lightbox from the server.
   */
  this.editQuestions = function() {
    this.lyAjaxObj({}, "showEdit");
  }

  /*
   * Removes a question while editing.
   * @param {integer} quid The question id.
   */
  this.removeQuestion = function(qid) {
    var row = document.getElementById("questionBlock"+this.instId+"_"+qid);
    row.parentNode.removeChild(row);
    this.alternateColors();
  }

  /*
   * Removes the question container from the dom.
   * @param {integer} quid The question id.
   * @see #onRemoveQuestion
   */
  this.removeQContainer = function (qid) {
    var cont = document.getElementById("qContainer"+this.instId+"_"+qid);
    cont.parentNode.removeChild(cont);
    cont = document.getElementById("qContainer"+this.instId+"_"+qid+"_m");
    cont.parentNode.removeChild(cont);
  }

  /**
   * event that is triggered when a ajax response requiring a lightbox is completed.
   * @param {Event} evt A Javascript event object.
   */
  this.onLightbox = function( evt ) {
    Lycos.ui.lightbox.show();
    Lycos.ui.lightbox.populate(evt.lyResponse.html);
  }
  
  /**
   * event that is triggered after the questions are finished saving.
   * @param {Event} evt A Javascript event object.
   */
  this.onSaveQuestions = function( evt ) {
    var cont = document.getElementById("questions_block_"+this.instId);
    cont.innerHTML = evt.lyResponse.html;
    Lycos.ui.lightbox.hide();

	// Loop through every iframe on the page and figure out which one contains this guestbook
	var frames = document.getElementsByTagName("iframe");

	for (var i = 0; i < frames.length; i++) {

		// Only look at iframes with an id in the form of "webon_edit_frame_#"
		if (frames[i].id.indexOf('webon_edit_frame') != -1) {

			// Figure out if this this iframe contains the questions block containing questions we're saving here
			framedocument = frames[i].contentWindow.document;
			result = framedocument.getElementById("questions_block_"+this.instId);

			if (result != null) {

				// If the guestbook is in this iframe,  adjust the iframes's height
				Lycos.ui.regionCtrl.adjustHeight(frames[i]);
				Lycos.ui.regionCtrl.updateEditFrame(frames[i]);
			}
		}
	}

  }
  
  /**
   * event that is triggered after a question is finished being removed.
   * @param {Event} evt A Javascript event object.
   */
  this.onRemoveQuestion = function( evt ) {
    this.removeQContainer(evt.lyResponse.qid);
  }
  
  /**
   * event that is triggered after a new guestbook entry is made.
   * @param {Event} evt A Javascript event object.
   */
  this.onComment = function( evt ) {

	var data = evt.lyResponse;

	// Reload the captcha
	recaptcha_iframe = document.getElementById('recaptcha_iframe' + this.instId + '.' + this.subInstId);
	recaptcha_iframe.src = recaptcha_iframe.src;

    if ( typeof(data.error) != "undefined" ) {
	
		if (data.lightbox && data.lightbox == "cancel") {
			Lycos.ui.lightbox.hide();
		}

		this.clearForm();
		alert (data.error);
    }
	else {
    
		this.updateEntriesCount(data);

		if (data.id == 0) {
			var cont = document.getElementById("commentList"+this.instId+"_"+this.subInstId);
			cont.innerHTML = cont.innerHTML + data.html;
		}

		this.clearForm();
		this.toggleForm('none');

		if( data && data.newId ) {
			var aName = "comment" + this.instId + "_" + data.newId;
			window.location.hash = "#" + aName;
			Lycos.ui.dragdrop.scrollToAnchor(aName);
		}
		else  {
			window.location.hash = "#";
		}
	}
  }

  /**
   * event that is triggered after a entry is marked as spam.
   * @param {Event} evt A Javascript event object.
   */
  this.onMarkEntryAsSpam = function( evt ) {
    var data = evt.lyResponse;
    
    obj = document.getElementById("markLink" + this.instId + "_" + data.id);
    if (obj) {
      obj.title = "unmark entry as spam";
      obj.innerHTML = "unmark";
      this.updateEntriesCount(data);
    }
  }
  
  /**
   * event that is triggered when an entry is unmarked as spam.
   * @param {Event} evt A Javascript event object.
   */
  this.onUnmarkEntryAsSpam = function( evt ) {
    var data = evt.lyResponse;
    
    obj = document.getElementById("markLink" + this.instId + "_" + data.id);
    if (obj) {
      obj.title = "mark entry as spam";
      obj.innerHTML = "mark";
      this.updateEntriesCount(data);
    }
  }
  
  /**
   * event that is triggered when the entries are retreived from the server.
   * @param {Event} evt A Javascript event object.
   */
  this.onGetEntries = function( evt ) {
    this.setEntriesHTML(evt.lyResponse);
  }
  
  /**
   * event that is triggered after an entry is deleted.
   * @param {Event} evt A Javascript event object.
   */
  this.onDeleteEntry = function( evt ) {
    var data = evt.lyResponse;
    
    this.updateEntriesCount(data);
    x = document.getElementById( "commentDeling"+data.id );
    x.parentNode.removeChild(x);
  }
  
  /**
   * event that is triggered after an entry is approved.
   * @param {Event} evt A Javascript event object.
   */
  this.onApproveEntry = function( evt ) {
    var data = evt.lyResponse;
    
    this.updateEntriesCount(data);
    var x = document.getElementById( "commentApproving"+data.id );
    var y = document.getElementById( "commentApprovalNotice"+this.instId+"_"+data.id );
    y.parentNode.removeChild( y );
    x.parentNode.removeChild(x);
    this.updateEntriesCount(data);
  }
}
