/*
 * forms.js provides support for making a form into a wizard or tabbed form.
 *
 * $ Id: $
 *
 * Copyright 2006 - 2008 Todd D. Esposito.
 *
 * This file is part of TurtolCMS.
 *
 *     TurtolCMS is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 *
 *     TurtolCMS is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public
 *     License along with TurtolCMS.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
 var TcmsForm = Class.create();
 var tcms_Items = new Array();
 var formAjaxResult;
 
 //Get any forms with appropriate classes and turn them into tcms forms
 Event.observe(window, 'load', function() {
 //wizardForms = document.getElementsByClassName("tcms_wizardForm");
 wizardForms = $$(".tcms_wizardForm");
 wizardForms.each(function(wizardForm) {
 tcms_Items.push(new TcmsForm($(wizardForm).id));
 });
 //tabbedForms = document.getElementsByClassName("tcms_tabbedForm");
 tabbedForms = $$(".tcms_tabbedForm");
 tabbedForms.each(function(tabbedForm) {
 tcms_Items.push(new TcmsForm($(tabbedForm).id));
 });
 });
 
 //include validation.js by default
 document.write("<script type='text/javascript' src='/tcms/js/validation.js'></script>");
 
 TcmsForm.prototype = {
 initialize: function(form_id)
 {
 this.form = $(form_id);
 this.displayPanes = new Array();
 this.nextButtons = [];
 this.backButtons = [];
 this.submitButtons = [];
 //default immediateValidation to false, set it to true if set to "true" in form tag
 var immediateValidation = false;
 if (this.form.getAttribute("immediateValidation") == "true") {
 immediateValidation = true;
 }
 //defaulting onSubmit to false since wizardDone handles calling the validation during submit
 this.valid = new Validation(this.form.id, {onSubmit:false, useTitles:true, immediate:immediateValidation});
 this.currentPaneId = 0;
 if (this.form.hasClassName("tcms_wizardForm")) {
 this.paneToHideId = 0;
 this.nextButtons = this.form.select('.tcms_wizardNextBtn');
 this.backButtons = this.form.select('.tcms_wizardBackBtn');
 this.submitButtons = this.form.select('.tcms_wizardSubmitBtn')
 //if the onClick attribute exists for submit buttons, clear it out, so this doesnt break old forms
 this.submitButtons.each(function(button) {
 if (button.getAttribute("onclick")) {button.setAttribute("onclick", "");}
 });
 //register events on wizard buttons
 this.nextButtons.each(this.setupNavButton.bind(this));
 this.backButtons.each(this.setupNavButton.bind(this));
 this.submitButtons.each(this.setupNavButton.bind(this));
 this.panes = this.form.select('.tcms_wizardPane');
 //show the appropriate buttons
 if (this.panes.length > 1) {
 $(this.nextButtons[0]).show();
 }
 if ((this.panes.length==1) && (this.submitButtons.length>0)) {
 $(this.submitButtons[0]).show();
 }
 }
 //create this.panes prior to creating this.displayPanes
 if (this.form.hasClassName("tcms_tabbedForm")) {
 this.panes = this.form.select('.tcms_tabPane');
 }
 //look up aliases, store in displayPanes array.
 //The array index indicates the "current pane," the value represents the pane to display
 for(var i=0;i<this.panes.length;i++) {
 aliasElements = this.panes[i].select('.tcms_alias');
 if (aliasElements.length > 0) {
 this.displayPanes[i]=aliasElements.first().getAttribute("targetPaneId");
 }
 else if (aliasElements.length==0) {
 this.displayPanes[i]=i;
 }
 }
 if (this.form.hasClassName("tcms_tabbedForm")) {
 this.tabs = this.form.select('.tcms_tab');
 //register submit event on tcms_tabbedFormSubmitBtn elements
 this.submitButtons = this.form.select('.tcms_tabbedFormSubmitBtn');
 this.submitButtons.each(this.setupNavButton.bind(this));
 //Set up initial tab, leftmost tab selected by default, run onEnter
 this.tabs.first().addClassName("tcms_activeTab");
 //check if first pane has an alias and display the correct pane, run onEnter
 paneToDisplayId = this.displayPanes[this.currentPaneId];
 $(this.panes[paneToDisplayId]).addClassName('tcms_activeTabBody');
 eval($(this.panes[this.currentPaneId]).getAttribute("onEnter"));
 this.tabs.each(this.setupNavButton.bind(this));
 }
 //display the first wizard pane
 if (this.form.hasClassName("tcms_wizardForm")) {
 this.displayWizardPane();
 }
 //add date selector calendar control to appropriate elements
 datePickers = this.form.select('.tcms_datePicker');
 datePickers.each(function(datePicker) {
 tcms_Items.push(new DatePicker(datePicker, tcms_Items.length));
 });
 
 // add color picker control to appropriate elements
 colorPickers = this.form.select('.tcms_colorpicker');
 colorPickers.each(function(Picker){
 trigger = Picker.id + "_trigger"
 Picker.setAttribute("OnChange", "$(\"" + trigger + "\").setStyle({'background-color':$('"+Picker.id+"').value})");
 Element.insert(Picker, {After: "<br/><input title='Click here to pick a color' style=\"cursor:pointer;border:1px solid #ccc;background-color:"+Picker.value+";\" id=\"" + trigger + "\" size="+Picker.size+"/>"});
 tcms_Items.push(new ColorPicker(Picker.id, trigger));
 });
 
 // add time picker control to appropriate elements
 timePickers = this.form.select('.tcms_timePicker');
 timePickers.each(function(TP){
 tcms_Items.push(new TimePicker(TP));
 });
 },
 
 setupNavButton : function(element) {
 Event.observe(element,'click',this.activateNavButton.bindAsEventListener(this));
 },
 
 activateNavButton :  function(event) {
 //find the closest element to the element that fired the event. Done this way to handle a link with an interior element, such as <a><span/></a>
 var element = Event.findElement(event, "input");
 if (!element){element = Event.findElement(event, "a");}
 Event.stop(event);
 this.switchToPane(element);
 },
 
 switchToPane: function(element)
 {
 //tabbed section
 if (this.form.hasClassName("tcms_tabbedForm")) {
 if (element.hasClassName("tcms_tabbedFormSubmitBtn")) {
 this.wizardDone(this.currentPaneId);
 }
 else {
 //add or remove tcms_invalidTab class as needed on current tab
 if (!this.validatePane(this.currentPaneId)) {
 $(this.tabs[this.currentPaneId]).addClassName('tcms_invalidTab');
 }
 else {
 $(this.tabs[this.currentPaneId]).removeClassName('tcms_invalidTab');
 }
 //switch the pane
 $(this.tabs[this.currentPaneId]).removeClassName('tcms_activeTab');
 //check if the current pane has an alias and hide the correct pane
 paneToHideId = this.displayPanes[this.currentPaneId];
 $(this.panes[paneToHideId]).removeClassName('tcms_activeTabBody');
 $(this.panes[paneToHideId]).hide();
 //update currentTab
 eval($(this.panes[this.currentPaneId]).getAttribute("onExit"));
 this.currentPaneId = this.tabs.indexOf(element);
 $(this.tabs[this.currentPaneId]).addClassName('tcms_activeTab');
 //check if the current pane has an alias and display the correct pane, run onEnter
 paneToDisplayId = this.displayPanes[this.currentPaneId];
 $(this.panes[paneToDisplayId]).addClassName('tcms_activeTabBody');
 $(this.panes[paneToDisplayId]).show();
 eval($(this.panes[this.currentPaneId]).getAttribute("onEnter"));
 }
 }
 //wizard section
 if (this.form.hasClassName("tcms_wizardForm")) {
 if (element.hasClassName("tcms_wizardSubmitBtn")) {
 this.wizardDone(this.currentPaneId);
 }
 if (element.hasClassName("tcms_wizardNextBtn")) {
 //if pane is valid, display new pane
 if (this.validatePane(this.currentPaneId)) {
 //check if current pane has an alias and hide the correct pane
 paneToHideId = this.displayPanes[this.currentPaneId];
 //progress to next pane if onExit returns true or is not present, otherwise eval onExit
 onExit = eval(this.panes[this.currentPaneId].getAttribute("onExit"));
 if (onExit == true || onExit == null) {
 this.panes[paneToHideId].hide();
 //increment currentPaneId
 this.currentPaneId++;
 this.displayWizardPane();
 }
 }
 }
 if (element.hasClassName("tcms_wizardBackBtn")) {
 //check if current pane has an alias and hide the correct pane
 paneToHideId = this.displayPanes[this.currentPaneId];
 this.panes[paneToHideId].hide();
 //decrement currentPaneId
 this.currentPaneId--;
 this.displayWizardPane();
 }
 }
 },
 
 displayWizardPane: function()
 {
 eval(this.panes[this.currentPaneId].getAttribute("onEnter"));
 //check if current pane has an alias and hide the correct pane
 paneToDisplayId = this.displayPanes[this.currentPaneId];
 this.panes[paneToDisplayId].show();
 //display appropriate buttons
 //first pane in a 1 pane form, only show submit
 if (this.currentPaneId == 0 && this.panes.length==1) {
 this.nextButtons.each(function(button) {button.hide()});
 this.backButtons.each(function(button) {button.hide()});
 this.submitButtons.each(function(button) {button.show()});
 }
 //first pane in a mutli pane form, only show next
 else if (this.currentPaneId == 0 && this.panes.length > 1) {
 this.nextButtons.each(function(button) {button.show()});
 this.backButtons.each(function(button) {button.hide()});
 this.submitButtons.each(function(button) {button.hide()});
 }
 //last pane in a form, show back and submit
 else if (this.currentPaneId == this.panes.length-1) {
 this.nextButtons.each(function(button) {button.hide()});
 this.backButtons.each(function(button) {button.show()});
 this.submitButtons.each(function(button) {button.show()});
 }
 //middle panes, not first or last. show back and next
 else {
 this.nextButtons.each(function(button) {button.show()});
 this.backButtons.each(function(button) {button.show()});
 this.submitButtons.each(function(button) {button.hide()});
 }
 },
 
 nextPane: function()
 {
 this.panes[paneToHideId].hide();
 this.currentPaneId ++;
 this.displayWizardPane();
 },
 
 confirmExit: function()
 {
 window.onbeforeunload = null;
 return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
 },
 
 validatePane: function(paneId)
 {
 return this.valid.validateSection($(this.panes[paneId]));
 },
 
 //returns true or false indicating whether all fields are valid or not
 //for tabbed forms, if true removes invalidTab class from invalid tabs
 validateForm: function()
 {
 isValid = true;
 isValid = this.valid.validate();
 //remove tcms_invalidTab class on tabs for invalid forms
 if (isValid == true && this.form.hasClassName("tcms_tabbedForm")) {
 invalidTabs = this.form.select('.tcms_invalidTab');
 invalidTabs.each (function(invalidTab) {invalidTab.removeClassName("tcms_invalidTab");});
 }
 return isValid;
 },
 
 //returns true if all panes are valid, false otherwise
 //if an invalid pane is found that is not the current pane, run the passed in error Code or run an alert with default text
 //if all panes are valid on a tabbed form, remove invalidTab class from invalid tabs
 validateAllPanes: function(notifyCode)
 {
 isValid = false;
 invalidPaneIds = new Array();
 for (var i=0; i < this.panes.length; i++) {
 if (!this.validatePane(i)) {invalidPaneIds.push(i);}
 }
 if (invalidPaneIds.length == 0) {isValid = true;}
 else {
 //theres an invalid pane, display message if the invalid pane is not the current pane
 displayMessage = true;
 for (var i=0; i < invalidPaneIds.length; i++) {
 if (invalidPaneIds[i] == this.currentPaneId) {displayMessage = false;}
 }
 if (displayMessage == true) {
 //if nofityCode was passed in run it, otherwise run default alert
 if (notifyCode) {eval(notifyCode);}
 else {alert("Please check all tabs for any invalid fields");}
 }
 }
 //remove tcms_invalidTab class on tabs for invalid forms
 if (isValid == true && this.form.hasClassName("tcms_tabbedForm")) {
 invalidTabs = this.form.select('.tcms_invalidTab');
 invalidTabs.each (function(invalidTab) {invalidTab.removeClassName("tcms_invalidTab");});
 }
 return isValid;
 },
 
 wizardDone: function()
 {
 //validate the current tab
 var isTabValid = this.validatePane(this.currentPaneId);
 if (isTabValid) {
 $(this.panes[this.currentPaneId]).hide();
 this.submitButtons.each(function(button) {
 if (button.visible()) {button.hide();}
 });
 this.backButtons.each(function(button) {
 if (button.visible()) {button.hide();}
 });
 this.PostingMessageDiv = this.form.select('.tcms_wizardPostingMessage')[0];
 this.SuccessMessageDiv = this.form.select('.tcms_wizardSuccessMessage')[0];
 this.FailureMessageDiv = this.form.select('.tcms_wizardFailureMessage')[0];
 if (this.PostingMessageDiv) {this.PostingMessageDiv.show();}
 if (this.form.getAttribute("method") == "AJAX") {
 var Success = this.form.getAttribute("onSuccess");
 var Failed = this.form.getAttribute("onFailure");
 new Ajax.Request(this.form.getAttribute("action"), {
 method:'post',
 onSuccess: function(transport) {
 this.PostingMessageDiv.hide();
 //if onsuccess was specified, run it, otherwise default handler is run
 if (Success != null) {
 this.SuccessMessageDiv.show();
 var fn= eval(Success);
 fn(this, transport);
 this.SuccessMessageDiv.show();
 }
 else {this.SuccessMessageDiv.show();}
 }.bind(this),
 onFailure: function(transport) {
 this.PostingMessageDiv.hide();
 //if onfailure was specified, run it, otherwise default handler is run
 if (Failed != null) {
 var fn = eval(Failed);
 fn(this, transport);
 }
 else {this.FailureMessageDiv.show();}
 }.bind(this),
 on404: function(transport) {
 this.PostingMessageDiv.hide();
 this.FailureMessageDiv.show();
 }.bind(this),
 postBody: this.form.serialize()
 });
 }
 //if the form is not Ajax, it has passed validation so submit
 else {this.form.submit();}
 }
 }
 }
 