//
// Copyright (c) Softwire 2002-2005 - all rights reserved.
//

//*****************************************************************************
// This file contains common Javascript functions used by the DatePicker
// control (SWT.Controls.DatePicker).
//*****************************************************************************

//=============================================================================
// insertYearsIntoDropdown
//
// Inserts an appropriate range of years to the entries in a "year"
// dropdown.
//
// Note that this only applies to DatePickers with AllowOtherYear set to true.
//
// Parameters:
//      xiDropdown  - The HTML <select> element containing the years
//      xiAllowBlank- Is a null entry allowed?
//      xiBlankText - Text to display when blank (e.g. "----")
//      xiOtherText - Text to display when Other (e.g. "Other...")
//      xiSelYear   - The selected year
//      xiMinYear   - The start year (unless xiDefault < xiMinYear)
//      xiMaxYear   - The end year (unless xiDefault > xiMaxYear)
//
//=============================================================================
function insertYearsIntoDropdown(xiDropdown, xiAllowBlank, xiBlankText, xiOtherText, xiSelYear, xiMinYear, xiMaxYear)
{
  var lOptions = xiDropdown.options;

  //===========================================================================
  // Update the range of years to display if appropriate
  //===========================================================================
  if(xiSelYear != -1 && xiSelYear != 0)
  {
    if(xiSelYear < xiMinYear)
    {
      xiMinYear = xiSelYear;
    }
    if(xiSelYear > xiMaxYear)
    {
      xiMaxYear = xiSelYear;
    }
  }

  //===========================================================================
  // Fill in the dropdown
  //===========================================================================
  lOptions.length = 0; // Clear dropdown

  if(xiAllowBlank)
  {
    lOptions[0] = new Option(xiBlankText, 0, false, false);
  }

  for(var lYear = xiMinYear; lYear <= xiMaxYear; lYear++)
  {
    lOptions[lOptions.length] = new Option(lYear, lYear, false, false);
  }

  lOptions[lOptions.length] = new Option(xiOtherText, "other", false, false);

  //===========================================================================
  // Select the appropriate year from the list
  //===========================================================================
  if(xiSelYear != -1)
  {
    xiDropdown.selectedIndex = xiSelYear - xiMinYear + (xiAllowBlank ? 1 : 0);
  }
  else
  {
    xiDropdown.selectedIndex = 0;
  }

}

//=============================================================================
// selectYearFromDropdown
//
// Presents a popup allowing the user to select a year not already
// in a "year" dropdown, if they selected "Other...".
//
// Parameters:
//      xiDropdown  - The HTML <select> element
//      xiAllowBlank- Is a null entry allowed?
//      xiBlankText - Text to display when blank (e.g. "----")
//      xiOtherText - Text to display when Other (e.g. "Other...")
//      xiDefault   - The default year to select
//      xiMinYear   - The default start year
//      xiMaxYear   - The default end year
//
// Returns false on error, or true if a new year has been chosen
//
//=============================================================================
function selectYearFromDropdown(xiDropdown, xiAllowBlank, xiBlankText, xiOtherText, xiDefault, xiMinYear, xiMaxYear)
{
   if(xiDropdown.options[xiDropdown.selectedIndex].value != "other")
   {
      // No need to select a new year
      return true;
   }

   var lYear = prompt("Please enter a year:", xiDefault == 0 ? "" : xiDefault);
   if(lYear + 0 < 1900)
   {
       // Either a ludicrously small number, or not a number at all
       // Probably pressed "Cancel", so don't issue an error warning
       lYear = xiDefault;
   }

   insertYearsIntoDropdown(xiDropdown, xiAllowBlank, xiBlankText, xiOtherText, lYear, xiMinYear, xiMaxYear);

   return true;
}

//=============================================================================
// Makes sure that the handle is a valid DatePicker pointer, and resolves it
// if its a string or a <span>
//=============================================================================
function DatePicker_GetPointer(xiSomeHandle)
{
  if (!xiSomeHandle)
  {
    return false;
  }
  if (typeof(xiSomeHandle) == "string")
  {
    xiSomeHandle = GetElementInDocument(xiSomeHandle);
  }
  if (typeof(xiSomeHandle) != "object")
  {
    return false;
  }
  //===========================================================================
  // If we've been passed the <span>, get the pointer obj from the var name
  // We may need to check the first child also
  //===========================================================================
  if (xiSomeHandle.firstChild && xiSomeHandle.firstChild.JavascriptPointerVarName)
  {
    xiSomeHandle = xiSomeHandle.firstChild;
  }
  if (xiSomeHandle.JavascriptPointerVarName)
  {
    xiSomeHandle = eval(xiSomeHandle.JavascriptPointerVarName);
    
    if ((!xiSomeHandle) || (typeof(xiSomeHandle) != "object"))
    {
      return false;
    }
  }
  return xiSomeHandle;
}

//=============================================================================
// DatePicker_GetSelectedDate
//
// A function to return a Javascript Date object representing the current value
// represented by this DatePicker.
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! CAUTION: Javascript dates use (Year, Month-1, Date)  for (y/m/d)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// The calling function should pass in the reference object declared by the 
// DatePicker in question, which will have name DatePicker.JavascriptPointerVarName.
// (This function is static).
//
// Parameters:
//   xiDatePickerHandleObj  - The handle object, as emitted by the DatePicker control
//                            or the object representing the DatePicker's enclosing <span> element
//
// Properties of the pointer object:
//   getDayDropDown()       - The HTML <select> element for the day dropdown, or null
//   getMonthDropDown()     - The HTML <select> element for the month dropdown, or null
//   getYearDropDown()      - The HTML <select> element for the year dropdown, or null
//   getMonthYearDropDown() - The HTML <select> element for the month-year dropdown, or null
//   getDayTextBox()        - The HTML <input> element for the day textbox, or null
//   getMonthTextBox()      - The HTML <input> element for the month textbox, or null
//   getYearTextBox()       - The HTML <input> element for the year textbox, or null
//   getDateTextBox()       - The HTML <input> element for the date textbox, or null
//
//   Most of the properties will be null for any given Type of DatePicker (see DatePicker.eType).
//   The necessary values will be emitted by the C# code and should not, in general, be 
//   manipulated by the Javascript.
//
// Returns: a new Date object, 
//       or false if an error has ocurred,
//       or null if no date is selected
//=============================================================================
function DatePicker_GetSelectedDate(xiDatePickerHandle)
{
  var lPtr = DatePicker_GetPointer(xiDatePickerHandle);

  if(!lPtr)
  {
    return false;
  }

  //===========================================================================
  // If Type == eType.TEXTBOXDATE we can do this in one go:
  //===========================================================================
  if(lPtr.getDateTextBox())
  {
    if(lPtr.getDateTextBox().value == "" 
     || lPtr.getDateTextBox().value == lPtr.DateFormatUserPrompt) 
    {
      return null; //no entry
    }
     
    //=========================================================================
    // We currently only support dd/mm/yy format
    // (Note that we don't need to test the length of lArray -- uninitialised
    //  or out of bounds array elements are always null in javascript)
    //=========================================================================
    var lArray = lPtr.getDateTextBox().value.split('/');
    if (lArray[0] != null && DatePicker_IsNonNegativeInteger(lArray[0]) &&
        lArray[1] != null && DatePicker_IsNonNegativeInteger(lArray[1]) &&
        lArray[2] != null && DatePicker_IsNonNegativeInteger(lArray[2]))
    {
      var lYearAsInt = (lArray[2] - 0);
      lYearAsInt = (lYearAsInt < 100) ? (lYearAsInt + 2000) : lYearAsInt;

      return DatePicker_MakeNewDate(lYearAsInt, lArray[1] - 1, lArray[0] - 0);
    }
    else
    {
      return false; //malformed entry
    }
  }
  //===========================================================================
  // Otherwise, search individually for year/month/day values.
  // (lDay, lMonth, lYear) are kept as string values:
  //===========================================================================
  var lDay = "", lMonth = "", lYear = "";
  
  //===========================================================================
  // day:
  //===========================================================================
  if (lPtr.getDayTextBox())
  {
    if (lPtr.getDayTextBox().value != "")
    {
      lDay = lPtr.getDayTextBox().value - 0;
    }
  }
  else if(lPtr.getDayDropDown())
  {
    if (lPtr.getDayDropDown().value != "0")
    {
      lDay = lPtr.getDayDropDown().value - 0;
    }
  }
  else
  {
    return false;
  }
  
  //===========================================================================
  // month: !! NOTE Javascript month is zero-based
  //===========================================================================
  if(lPtr.getMonthTextBox())
  {
    if (lPtr.getMonthTextBox().value != "")
    {
      lMonth = lPtr.getMonthTextBox().value - 1;
    }
  }
  else if(lPtr.getMonthDropDown())
  {
    if (lPtr.getMonthDropDown().value != "0")
    {
      lMonth = lPtr.getMonthDropDown().value - 1;
    }
  }
  else if(lPtr.getMonthYearDropDown())
  {
    if(lPtr.getMonthYearDropDown().value != "-1")
    {
      lMonth = DatePicker_getMonthFromEncoding(lPtr.getMonthYearDropDown().value);
    }
  }
  else
  {
    return false;
  }
  
  //===========================================================================
  // year:
  //===========================================================================
  if(lPtr.getYearTextBox())
  {
    if (lPtr.getYearTextBox().value != "")
    {
      var lYearAsInt = (lPtr.getYearTextBox().value - 0);
      lYearAsInt = (lYearAsInt < 100) ? (lYearAsInt + 2000) : lYearAsInt;
      lYear = lYearAsInt.toString();
    }
  }
  else if(lPtr.getYearDropDown())
  {
    if (lPtr.getYearDropDown().value != "0")
    {
      lYear = lPtr.getYearDropDown().value - 0;
    }
  }
  else if(lPtr.getMonthYearDropDown())
  {
    if (lPtr.getMonthYearDropDown().value != "-1")
    {
      lYear = DatePicker_getYearFromEncoding(lPtr.getMonthYearDropDown().value);
    }
  }
  else
  {
    return false;
  }
  
  //===========================================================================
  // Return the value. Note that if lMonth is 0, (lMonth == "") can return true...
  //===========================================================================
  if (lDay == "" || (lMonth == "" && lMonth != 0) || lYear == "")
  {
    return null //no entry
  }
  else if (DatePicker_IsNonNegativeInteger(lDay) &&
           DatePicker_IsNonNegativeInteger(lMonth) &&
           DatePicker_IsNonNegativeInteger(lYear))
  {
     return DatePicker_MakeNewDate(lYear - 0, lMonth - 0, lDay - 0);
  }
  else
  {
    return false; //(shouldn't occur)
  }
}

//=============================================================================
// returns true if, and only if, the given string matches /[0-9]+/
//=============================================================================
function DatePicker_IsNonNegativeInteger(xiString)
{
  if (xiString == null || xiString.length == 0)
  {
    return false;
  }

  var i;
  for (i=0; i<xiString.length; i++)
  {
    if ("0123456789".indexOf(xiString.charAt(i)) == -1)
    {
      return false;
    }
  }
  return true;
}

//=============================================================================
// DatePicker_SetSelectedDate
//
// Sets the value in the DatePicker to the given Javascript Date object
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! CAUTION: Javascript dates use (Year, Month-1, Date)  for (y/m/d)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// The calling function should pass in the reference object declared by the 
// DatePicker in question, which will have name DatePicker.JavascriptPointerVarName.
// (This function is static).
//
// Parameters:
//   xiDate                 - The new Date to set, or "null" to clear the DatePicker
//   xiDatePickerHandleObj  - The handle object, as emitted by the DatePicker control
//                            or the object representing the DatePicker's enclosing <span> element
//
// Returns: void
//=============================================================================
function DatePicker_SetSelectedDate(
     xiDate,
     xiDatePickerHandle)
{
  var lPtr = DatePicker_GetPointer(xiDatePickerHandle);
  
  if(!lPtr)
  {
    return false;
  }
    
  var lYear  = 0;
  var lMonth = 0;
  var lDate  = 0;
  var lMonthYear = -1;

  if (xiDate)
  {
    lYear  = xiDate.getFullYear();
    lMonth = xiDate.getMonth() + 1; //convert from Javascript month to c# month
    lDate  = xiDate.getDate();
    lMonthYear = DatePicker_encodeMonthYear(lMonth, lYear);
  }

  if(lPtr.getDateTextBox())
  {
    if (xiDate)
    {
      //=========================================================================
      // We currently only support dd/mm/yyyy format.
      //=========================================================================
      lPtr.getDateTextBox().value = 
        (lDate < 10 ? "0" + lDate : lDate) + 
        "/" + 
        (lMonth < 10 ? "0" + lMonth : lMonth) + 
        "/" + 
        (lYear < 10 ? "0" + lYear : lYear);
    }
    else
    {
      lPtr.getDateTextBox().value = lPtr.DateFormatUserPrompt;
    }
  }
  
  if(lPtr.getDayDropDown())
  {
    DatePicker_setValueInDropdown(lPtr.getDayDropDown(), lDate);
  }
  
  if(lPtr.getMonthDropDown())
  {
    DatePicker_setValueInDropdown(lPtr.getMonthDropDown(), lMonth);
  }
  
  if(lPtr.getYearDropDown())
  {  
    DatePicker_setValueInDropdown(lPtr.getYearDropDown(), lYear);
  }
  
  if(lPtr.getMonthYearDropDown())
  {
    DatePicker_setValueInDropdown(lPtr.getMonthYearDropDown(), lMonthYear);
  }

  if(lPtr.getDayTextBox())
  {
    lPtr.getDayTextBox().value = xiDate ? lDate : "";
  }

  if(lPtr.getMonthTextBox())
  {
    lPtr.getMonthTextBox().value = xiDate ? lMonth : "";
  }

  if(lPtr.getYearTextBox())
  {
    lPtr.getYearTextBox().value = xiDate ? lYear : "";
  }
}

//=============================================================================
// Encode a month & year as a single integer
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! CAUTION: Javascript dates use Month-1, but this function DOES NOT
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Aside from the above caution, this must match DatePicker.EncodeMonthYear
//=============================================================================
function DatePicker_encodeMonthYear(xiMonth, xiYear)
{
  return (xiYear - 2000) * 12 + (xiMonth - 1);
}

//=============================================================================
// Decode a month & year combination to a month
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! CAUTION: Javascript dates use Month-1, as does this function
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Aside from the above caution, this must match DatePicker.GetMonthFromEncoding
//
// We return the value as a string.
//=============================================================================
function DatePicker_getMonthFromEncoding(xiEncodedMonthYear)
{
  //=======================================================================
  // The % operator forces the value to an int, so we're safe to use +
  //=======================================================================
  var lMonth = (xiEncodedMonthYear % 12);
  
  if(lMonth < 0)
  {
    lMonth = (lMonth + 12) % 12;
  }

  return lMonth.toString();
}

//=============================================================================
// Decode a month & year combination to a year
// This must match DatePicker.GetYearFromEncoding
//=============================================================================
function DatePicker_getYearFromEncoding(xiEncodedMonthYear)
{
  return ((xiEncodedMonthYear - (xiEncodedMonthYear % 12))  / 12) + 2000;
}

//=============================================================================
// Set the selected item in a dropdown.
// Can't use xiDropdown.value = xiValue in all browsers
//=============================================================================
function DatePicker_setValueInDropdown(xiDropdown, xiValue)
{
  for(var i=0; i<xiDropdown.options.length; i++)
  {
    if(xiDropdown.options[i].value == xiValue)
    {
      xiDropdown.selectedIndex = i;
      break;
    }
  }
}

//=============================================================================
// Incredibly, new Date(), doesn't check that the date is valid.
// For example new Date(2005,1,30) gives Wed, Mar 2nd
// Can't use xiDropdown.value = xiValue in all browsers
//=============================================================================
function DatePicker_MakeNewDate(xiYear, xiMonth, xiDate)
{
  var lRet = new Date(xiYear, xiMonth, xiDate);
  if (xiYear != lRet.getFullYear() ||
      xiMonth != lRet.getMonth() ||
      xiDate != lRet.getDate())
  {
    return false;
  }
  else
  {
    return lRet;
  }
}


