
/*
 *
 * Utility functions for use in the MatrixMaxx UI
 *
 */

/* Set various jQuery UI defaults */
$.datepicker.setDefaults({changeMonth: true, changeYear: true,
	                showButtonPanel: true, autoSize: true});

/* Add a jQuery method to log to the Firebug console */
$.log = function (message) {
    if (typeof console !== 'undefined') {
        console.log(message);
    }
};

/* Method to check if some other jQuery element set is contained within
   this element set. */
$.fn.containsSet = function (other) {
    var result = this.filter(other);
    return (result.length === other.length);
};

/* JS implementation of Python's dict.pop() method; removes one key from the
   provided object and returns it. */
function dict_pop(obj) {
    var key;
    for (key in obj) {
	if (obj.hasOwnProperty(key)) {
	    delete obj[key];
	    return key;
        }
    }
    /* No keys found */
    return undefined;
}

/* returns the first key in the object. */
function dict_get(obj) {
  var key;
  var count = 0;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      return key;
    }
  }
  return undefined;
}

/* JS implementation of Python's len(dict) method; returns the number
of keys in the object. */
function dict_len(obj) {
  var key;
  var count = 0;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      count++;
    }
  }
  return count;
}

function disableForm(formName) {
   // disable the enabled elemetnts on the form and mark them as temporarily disabled
   // (so we can know which ones to re-enable later)
   if (formName) {
      $('#'+formName+' input:enabled').addClass('temp-disabled').attr('disabled', 'disabled');
   }
}

function enableForm(formName) {
   // enable form elements that were temporarily disabled above
   if (formName) {
      $('#'+formName+' .temp-disabled').removeClass('temp-disabled').removeAttr('disabled');
   }
}

function showSpinner() {
   // Show 'loading' spinner.
   $("#spinnerDiv").html('<img src="/themes/images/loading.gif" />').show();
}

function killSpinner() {
   // Kill 'loading' spinner.
   $("#spinnerDiv").empty().hide();
}

/* Open a little window (used for search_tips) */
function openWindow(page, height, width) {
    // Open a little window (used for search_tips)
    if (!height) {height=650;}
    if (!width)  {width=550;}
    this.open(page, "CtrlWindow", "height="+height+",width="+width+",left=20,top=20,toolbar=no,menubar=no,location=no,scrollbars=yes,resizable=yes");
}

function maxx_confirm_submit(message, pleaseWaitMessage) {
   // using browser's confirm rather than maxx_confirm
   var resp = confirm(message);
   if (resp && pleaseWaitMessage) {
     maxx_alert(pleaseWaitMessage);
   }
   return resp;
}

function maxx_confirm(message, ok_action, cancel_action) {
   // Displays a message to the user and presents OK/cancel buttons.
   // If OK is selected, the ok_action function is called.
   // Callers can do: maxx_confirm("Do this risky thing?,
   //                     function () {...risky thing...})
   // The message is automatically wrapped inside a <p> element.

    if (!cancel_action) {cancel_action=close_dialog;}

    function close_dialog() {
      $('#confirm-dialog').dialog('close');
    }

    // set dialog to modal
    $('#confirm-dialog').html('<p align="left">' + message + '</p>')
        .dialog({
	modal: true,
        dialogClass: "confirmation",
        autoOpen: false,
        height: 244,
        width: 400,
        resizable: false, title: '<b>Confirm Action</b>',
	buttons: {
	  'OK': function () {close_dialog(); ok_action();},
	  'Cancel': function() {close_dialog(); cancel_action();}
	}
       });

    // Hide the standard close button
    $('.ui-dialog-titlebar-close').hide();

    $('#confirm-dialog').dialog('open');
}

function maxx_confirm_redirect(message, dest_url) {
  // Displays a message to the user and presents OK/cancel buttons.
  // If OK is selected, redirects to some different URL.
  maxx_confirm(message, function () {
    parent.location=dest_url;
  });
}

function maxx_alert(message, title, height, width) {
    // Displays a message to the user in a dialog that they can then dismiss.
    if (!title)  {title = "Notice";}
    if (!height) {height = 424;}
    if (!width)  {width = 500;}

    function close_dialog() {
      $('#alert-dialog').dialog('close');
    }

    // set dialog to modal
    $('#alert-dialog').html('<p align="left">' + message + '</p>')
        .dialog({
        modal: true,
        dialogClass: "confirmation",
	autoOpen: false,
        height: height,
        width: width,
        resizable: true,
        title: '<b>'+title+'</b>',
	buttons: {
	  'OK': function () {close_dialog();}
	}
       });

    $('#alert-dialog').dialog('open');
}


function html_failed(XMLHttpRequest, textStatus, errorThrown) {
  maxx_alert("Unable to communicate with server");
}

function html_invoke(url, callback) {
  // Retrieves an HTML document from the server and passes
  // the resulting tree to a function

  function success_function(data, textStatus, xhr) {
    var tree = $(data, document);

    // Remove the debugging info, if present.
    if (tree instanceof Array) {
        var i;
	for(i=0; i<tree.length(); i++) {
	   tree[i].find("table.noPrint").remove();
	}
    } else {
        tree.find("table.noPrint").remove();
    }
    callback(tree);
  }

  $.ajax({
        url: url,
        success: success_function,
	dataType: "text",
        type: 'GET',
        error: html_failed,
        processData: false,
        timeout: 20000
        });
}



function json_failed(XMLHttpRequest, textStatus, errorThrown) {
  maxx_alert("Unable to communicate with server");
}

function json_invoke(url, value, callback) {
  // Retrieves JSON data from the server and calls a function
  function success_function(data, textStatus, xhr) {
    var json_value;
    try {
	json_value = JSON.parse(data);
    } catch (e) {
	// Some other exception occurred; if possible,
	// extract the traceback embedded in the data received
	var index = data.search('Traceback');
	json_value = {};
	json_value.error = 'The server did not respond correctly.';
	if (index !== -1) {
	    data = data.substring(index);
	    index = data.search('-->');
	    if (index !== -1) {
	        json_value.traceback = data.substring(0, index);
	    }
	}
    }
    if (json_value.traceback) {
	maxx_alert('<pre>' + json_value.traceback + '</pre>');
    } else {
        callback(json_value);
    }
  }

  $.ajax({
        url: url,
        data: JSON.stringify(value),
	dataType: "text",
        success: success_function,
        type: 'POST',
        error: json_failed,
        contentType: 'application/json',
        processData: false,
        timeout: 20000
        });
}

/******************************************
 End of utility functions
 ******************************************/


/* ------------------------------ */
/* for tasks                      */

function display_task_popup () {
  // Display the pop-up tasks window
  html_invoke('/tasks/TaskFormPrivate/popup', function (tree) {
    $(tree).children().appendTo($("#taskModal").empty());
    $('#Task_due_date_datepicker').datepicker();
    $('#Task_requester_field_id').autocomplete({
	source: "/ws/IndividualWS/lastName",
        minLength: 2,
        select: function (event, ui) {
           // Save the Maxx ID in a hidden field
           $("#Task_requester_id").val(ui.item.id);
	}
    });
    /* Task-add form -- create new task using JSON */
    $("#quick-task-add").submit(function () {
      var url = null, url_title = null;
      var checked = $("#quick-task-add input[name=link]").attr('checked');
      var d;

      if (checked) {
	url = $("#taskModal").attr("url");
	url_title = $("#taskModal").attr("url-title");
      }
      d = {
	assigned_to:$("#quick-task-add select[name=Task_assigned_to]").val(),
	category:$("#quick-task-add select[name=Task_category]").val(),
	description:$("#quick-task-add input[name=Task_description]").val(),
	due_date:$("#quick-task-add input[name=Task_due_date]").val(),
	details:$("#quick-task-add textarea[name=Task_details]").val(),
	notify:$("#quick-task-add input[name=notify]").val(),
	requester: $("#Task_requester_id").val(),
	url:url, url_title: url_title,
	status:1  // Default to open
      };
      json_invoke('/ws/TaskWS/add', d, function (result) {
	  if (result.task_id !== null) {
	      // Task successfully created
	      $('#taskModal').dialog('close').remove();
	      // Reload page.
	      location.reload();
	  } else {
	      // Report an error
	      $("#quick-task-error").html(result.error);
          }
        });
      return false;  // Prevent form submission
    });

    $('#taskModal').width(600).height('auto').fadeIn(250);
  });
}

// Read the contents of the 'track time' dialog and submit them.
function submit_time(task_id) {
  var category, date, duration, duration_array;
  var hour, minute;

  function show_error(msg) {
    $("#track-time-error").html(msg);
  }

  show_error("");

  // Sanity-check the field values
  category = $("#form-track-time select[name=TimeTracked_category]").val();
  if (!category) {
    show_error("You must select a category");
    return;
  }

  // Check the date field
  date = $("#form-track-time input[name=TimeTracked_date]").val();
  date = Date.parse(date);
  if (date === null) {
    show_error("Can't understand the date provided.");
    return;
  }
  date = date.toString('yyyy-M-d');

  // Check the duration field
  duration = $("#form-track-time input[name=TimeTracked_duration]").val();
  duration_array = duration.split(":");
  if (duration_array.length !== 2) {
    show_error("Can't understand the duration provided.");
    return;
  }
  hour = parseInt(duration_array[0], 10);
  minute = parseInt(duration_array[1], 10);
  if (minute < 0) {
    show_error("Can't understand the minute part of the duration.");
    return;
  }
  if (hour === 0 && minute === 0) {
    show_error("You must supply a non-zero duration.");
    return;
  }

  // Send content to server
  json_invoke('/ws/TaskWS/track',
              {'duration':duration, 'date':date,
               'category':category,
               'comments': $("#form-track-time textarea[name=TimeTracked_comments]").val(),
	       'task_id': task_id
              },
              function (json_value) {
                $('#time-tracker').dialog('close').remove();
                // Reload page
                location.reload();
	      });
}


function show_time_tracker(task_id) {
    function close_dialog() {
      $('#time-tracker').dialog('close').remove();
    }

    $("body").append("<div id='time-tracker' title='Track Your Time' class='dialogBox' style='display:none; background:white; opacity: 1.0'></div>");
    $('#time-tracker').html("<img src='/themes/images/ajax-loader.gif' />")
        .dialog({modal: true,
        dialogClass: "confirmation",
        height: 400,
        width: 400,
        resizable: false, title: '<b>Track Your Time</b>',
	buttons: {
	  'OK': function () {submit_time(task_id);},
	  'Cancel': close_dialog
	}
       });
    html_invoke('/tasks/TaskFormPrivate/track', function (tree) {
      $("#time-tracker").empty().append(tree.html());
      $("#time-tracker input[name=TimeTracked_Task_id]").val(task_id);
      $('#TimeTracked_date').datepicker();
    });
    $('#time-tracker').dialog('open');
}


/* ------------------------------ */
/* from calendar.js               */

function setUpAddText() {  
  //Automatically fill in some form fields
  $('input.addText').each(function() {
    if ($(this).val() === '') {
      $(this).val($(this).attr('title'));	
    }

    $(this).focus(function() {
      $(this).addClass('focused');
      if ($(this).val() === $(this).attr('title')) {
        $(this).val('');	
      }
    });

    $(this).blur(function() {
      $(this).removeClass('focused');
      if ($(this).val() === '') {
        $(this).val($(this).attr('title'));	
      }
    });			 
  });
}

function setUpCalExportSlider() {
    // Personal Calendar Export slider
    $('#cal-options').hide().css({'position':'absolute', 'top':'12px', 'left':'7px'});
    $('#add-cal a').click(function(){
        $('#cal-options').slideDown('normal');
        return false;
    });
    $('body').click(function(){
        $('#cal-options').slideUp('normal');
    });
}


/* ------------------------------ */
/* from showfind.js               */

function showFind(POname, nameField, idField, optionalArgs) {
    var aStyle = "toolbar=no,width=550,height=450,status=no,scrollbars=yes,resizable=yes,menubar=no";
    var url = "find?poName=" + POname + "&nameField=" + nameField + "&idField=" + idField;
    if (optionalArgs) {
        url += "&" + optionalArgs;
    }
    if (typeof(window.aWindow) !== "undefined" && !aWindow.closed) {
        aWindow.focus();
        return;
    }
    aWindow=window.open(url,"thewindow", aStyle);
}

function openPopup(url) {
    window.open("popup?body=" + url, "Popup", "height=300,width=500,toolbar=no,menubar=no,location=no,scrollbars=yes,resizable=yes");
}

function openNormalPopup(url) {
    window.open(url, "Popup", "height=500,width=700,toolbar=no,menubar=no,location=no,scrollbars=yes,resizable=no");
}

function clearFind(POname, nameField, idField) {
    var findBox = document.getElementById(nameField);
    findBox.value = '';
    if (findBox.onchange) {
        findBox.onchange();
    }
    $("input[name="+idField+"]").val('')
}

//Only show the name input box if there is a value in it
function selectVisibility(nameField) {
    var findBox, displayStyle;
    try {
        findBox = document.getElementById(nameField);
    } catch(e) {
        return;
    }
    if (findBox.value && findBox.value !== "None") {
        displayStyle = '';
    }
    else {
        displayStyle = 'none';
    }
    findBox.style.display = displayStyle;
}


/* ------------------------------ */
/* from formFocus.js              */

function setFocus() {
  if (window.location.href.indexOf("#") < 0) {
    if (document.forms) {
      var form_num, i, frm;
      for (form_num=0; form_num < document.forms.length; form_num++) {
        frm = document.forms[form_num];
        if (frm && 
            frm.id !== 'searchQuery' && 
            frm.className !== 'nofocus' &&
            frm.elements) {
          for (i=0; i<frm.elements.length; i++) {
            var elem = frm.elements[i];
            var id = elem.id;

            // Skip form elements that have been disabled.
            // Skip form elements that have nofocus class.
            // Skip input elements that are buttons, hidden, or a datepicker.
            if (!elem.getAttribute('DISABLED') &&
                elem.className !== 'nofocus' &&
                elem.className.indexOf('atepicker') === -1 &&
                !(elem.tagName === 'INPUT' &&
                  (elem.type === 'submit' || elem.type === 'reset' ||
                   elem.type === 'button' || elem.type === 'hidden' ||
                   id.substring(id.length-10) === 'datepicker'))) {

              // Focus on the form element and return.
              try {
                elem.focus();
              }
              catch (err) {
                // oh well.
              }
              return;
            }
          }
        }
      }
    }
  }
}

function prepopstuff() {
    // zebra striping
    var stripe = document.getElementById('storeResults');
    if (stripe) {
      var trs = stripe.getElementsByTagName('tr');
      var i;
      for (i=0; i<trs.length; i++) {
        if ((i % 2) !== 0) {
            trs[i].className = 'odd';
        } else {
            trs[i].className = 'even';
        }
      }
    }
}


/* ------------------------------ */
/* from viewIndividualBio.js      */

function bioFailed(XMLHttpRequest, textStatus, errorThrown) {
    // If the ajax request returns an error, we get here.
    // We probably timed out.
    $('#member_bio_dialog').dialog("destroy");
}

function bioCompleted(data, textStatus) {
    // Install the Bio in the dialog
    var devStringStart = '<!-- Templates used:';
    var devStringIndex = data.indexOf(devStringStart);
    if (devStringIndex < 0) {
        $("#bio_text").html(data);
    } else {
        $("#bio_text").html(data.substring(0,devStringIndex));
    }
    // Display the dialog
    $('#member_bio_dialog').show();
    $('#member_bio_dialog').show('open');
}

function fetchBio(individualId) {
    $.ajax({
        type: 'GET',
        url: 'getBioForJquery',
        success: bioCompleted,
        error: bioFailed,
	dataType: "text",
        data: {
         individualId: individualId
        },
        timeout: 20000
        });
}

function clickedCancel() {
    $('#member_bio_dialog').dialog("destroy");
}

function show_bio(individualId, memberName) {
    // Build the dialog box for displaying a member bio

    // set up button click handler for dialog
    $('#cancel_button').click(clickedCancel);

    // set dialog to modal and style the overlay to grey
    $('#member_bio_dialog').dialog({modal: false,
        width: 540,
        title: ('Biography for <b>' + memberName + '</b>') });

    // Hide the standard close button
    $('.ui-dialog-titlebar-close').hide();

    // Fetch the Bio
    fetchBio(individualId);
}



/* ------------------------------ */
/* Tasks for after the page loads */


function setUpCollapsibleHelp() {
    // Collapsible help displays.
    $('.longHelpText').addClass('hidden');
    $('.longHelpText').each(function() {
	$('<p><a href="#" class="showHelp">Show more help</a> <img class="noPrint" src="/themes/images/leftPixelArrow.gif" alt=">" /></p>').insertBefore(this);
    });
    $('.showHelp').click(function() {
	if($(this).text() === 'Show more help') {
	    $(this).text('Hide help');
	    $(this).nextAll('img').attr('src', '/themes/images/downPixelArrow.png');
	} else {
	    $(this).text('Show more help');
	    $(this).nextAll('img').attr('src', '/themes/images/leftPixelArrow.gif');
	}
	$(this).parent().nextAll('.longHelpText').toggleClass('hidden');
	return false;
    });
}

function setUpCollapsibleDetails() {
    // Collapsible detail displays.
    $('div.showDetails').addClass('hidden');
    $('div.showDetails').each(function() {
	$('<p><a href="#" class="showDetails">Show Details</a> <img class="noPrint" src="/themes/images/leftPixelArrow.gif" alt=">" /></p>').insertBefore(this);
    });
    $('a.showDetails').click(function() {
	if ($(this).text() === 'Show Details') {
	    $(this).text('Hide Details');
	    $(this).nextAll('img').attr('src', '/themes/images/downPixelArrow.png');
	} else {
	    $(this).text('Show Details');
	    $(this).nextAll('img').attr('src', '/themes/images/leftPixelArrow.gif');
	}
	$(this).parent().nextAll('div.showDetails').toggleClass('hidden');
	return false;
    });
}

function setUpReportsMode() {
    // Set up reports mode
    if($('#primaryContent > table').width() >= 920){
        $('body.reports #container').css('width','100%');
        $('body.reports #content').css('width','97%');
        $('body.reports #headerContainer').css('width',$('#content').width()+30);
        $('body.reports #footerContainer').css('width',$('#content').width()+30);
    }

    $(window).resize(function() {
        $('body.reports #headerContainer').css('width',$('#content').width()+30);
        $('body.reports #footerContainer').css('width',$('#content').width()+30);
    });
}

function setUpDiv(divId, divAttrs) {
    // Set up persistent div (if it's not already there), hide for now
    if (!divAttrs) {divAttrs='';}
    if ($("#"+divId).length === 0) {
       $("body").append("<div id=" + divId + " " + divAttrs + "></div>");
       $("#"+divId).hide();
    }
}

function setUpDialog(dialogType) {
    // Set up dialog (if it's not already there)
    setUpDiv(dialogType+"-dialog", "class='dialogBox' style='background:white; opacity: 1.0'");
}

function markAnchorAsClicked(obj) {
    var href = obj.getAttribute('href');

    $(obj).addClass('alreadyClicked');
    obj.removeAttribute('href');
    obj.removeAttribute('onclick');

    if (href) {
        window.location = href;
    }

    return true;
}

function markSubmitButtonAsClicked(obj) {
  $(obj).hide();
  var procMsg = "Processing...";
  if ($(obj).next().html() !== procMsg) {
    $(obj).after("<i>"+procMsg+"</i>");
  }
    
}

function setUpOnlyClickOnce() {
    // for submit buttons
    $("[type='submit'].onlyClickOnce").click(function(event) {
        markSubmitButtonAsClicked(this);
    });

    // for non-submit buttons
    $("[type!='submit'].onlyClickOnce").not("a").click(function() {
        $(this).attr('disabled', 'disabled');
    });

    // for anchors
    $("a.onlyClickOnce").click(function() {
        markAnchorAsClicked(this);
    });
}

function setUpAjaxSpinner() {
  setUpDiv('spinnerDiv', 'class="spinnerDiv"');

  $("#spinnerDiv").ajaxSend(function() {
    showSpinner();
  }).ajaxComplete(function() {
    killSpinner();
  });
}


/* ------------------------------ */
/* Tasks for after the page loads */
$(document).ready(function() {
    setUpDialog('alert');
    setUpDialog('confirm');
    setUpCollapsibleHelp();
    setUpCollapsibleDetails();
    setUpReportsMode();
    setUpOnlyClickOnce();

    // calendar stuff
    setUpAddText();
    setUpCalExportSlider();
    $('.uses-datepicker').datepicker();

    // restyle button links.
    $("button, input:submit, a", ".buttonlinks").button();

    // show spinner during ajax requests
    setUpAjaxSpinner();
});
/* ------------------------------ */



