//
// AuctionCalendarView (for Prototype)
//
// Copyright 2007-2008 Singlesnet, Inc.
// Copyright 2002-2005 Mihai Bazon
//
// Maintained by Justin Mecham <justin@corp.singlesnet.com>
//
// This calendar is based very loosely on the Dynarch AuctionCalendar in that it was
// used as a base, but completely gutted and more or less rewritten in place
// to use the Prototype JavaScript library.
//
// As such, AuctionCalendarView is licensed under the terms of the GNU Lesser General
// Public License (LGPL). More information on the Dynarch AuctionCalendar can be
// found at:
//
//   www.dynarch.com/projects/calendar
//

var AuctionCalendar = Class.create()

//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------

AuctionCalendar.VERSION = '1.1'

AuctionCalendar.DAY_NAMES = new Array(
  'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
  'Sunday'
)

AuctionCalendar.SHORT_DAY_NAMES = new Array(
  'S', 'M', 'T', 'W', 'T', 'F', 'S', 'S'
)

AuctionCalendar.MONTH_NAMES = new Array(
  'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
  'September', 'October', 'November', 'December'
)

AuctionCalendar.SHORT_MONTH_NAMES = new Array(
  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
  'Dec' 
)

AuctionCalendar.NAV_PREVIOUS_YEAR  = -2
AuctionCalendar.NAV_PREVIOUS_MONTH = -1
AuctionCalendar.NAV_TODAY          =  0
AuctionCalendar.NAV_NEXT_MONTH     =  1
AuctionCalendar.NAV_NEXT_YEAR      =  2

// AuctionServices Addition
AuctionCalendar.railsFormatDate = function(date) {
  var year  = date.getFullYear()
  var month = date.getMonth()+1
  var day   = date.getDate()
  
  if (month < 10)
    month = '0'+month
  if (day < 10)
    day = '0'+day
    
  return year+'/'+month+'/'+day
}

//------------------------------------------------------------------------------
// Static Methods
//------------------------------------------------------------------------------

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown. If the click was outside the open
// calendar this function closes it.
AuctionCalendar._checkAuctionCalendar = function(event) {
  if (!window._popupAuctionCalendar)
    return false
  if (Element.descendantOf(Event.element(event), window._popupAuctionCalendar.container))
    return
  window._popupAuctionCalendar.callCloseHandler()
  return Event.stop(event)
}

//------------------------------------------------------------------------------
// Event Handlers
//------------------------------------------------------------------------------

AuctionCalendar.handleMouseDownEvent = function(event)
{
  Event.observe(document, 'mouseup', AuctionCalendar.handleMouseUpEvent)
  Event.stop(event)
}

// XXX I am not happy with how clicks of different actions are handled. Need to
// clean this up!
AuctionCalendar.handleMouseUpEvent = function(event)
{
  var el        = Event.element(event)
  var calendar  = el.calendar
  var isNewDate = false

  // If the element that was clicked on does not have an associated AuctionCalendar
  // object, return as we have nothing to do.
  if (!calendar) return false

  // Clicked on a day
  if (typeof el.navAction == 'undefined')
  {
    if (calendar.currentDateElement) {
      Element.removeClassName(calendar.currentDateElement, 'selected')
      Element.addClassName(el, 'selected')
      calendar.shouldClose = (calendar.currentDateElement == el)
      if (!calendar.shouldClose) calendar.currentDateElement = el
    }
    calendar.date.setDateOnly(el.date)
    isNewDate = true
    calendar.shouldClose = !el.hasClassName('otherDay')
    var isOtherMonth     = !calendar.shouldClose
    if (isOtherMonth) calendar.update(calendar.date)
  }

  // Clicked on an action button
  else
  {
    var date = new Date(calendar.date)

    if (el.navAction == AuctionCalendar.NAV_TODAY)
      date.setDateOnly(new Date())

    var year = date.getFullYear()
    var mon = date.getMonth()
    function setMonth(m) {
      var day = date.getDate()
      var max = date.getMonthDays(m)
      if (day > max) date.setDate(max)
      date.setMonth(m)
    }
    switch (el.navAction) {

      // Previous Year
      case AuctionCalendar.NAV_PREVIOUS_YEAR:
        if (year > calendar.minYear)
          date.setFullYear(year - 1)
        break

      // Previous Month
      case AuctionCalendar.NAV_PREVIOUS_MONTH:
        if (mon > 0) {
          setMonth(mon - 1)
        }
        else if (year-- > calendar.minYear) {
          date.setFullYear(year)
          setMonth(11)
        }
        break

      // Today
      case AuctionCalendar.NAV_TODAY:
        break

      // Next Month
      case AuctionCalendar.NAV_NEXT_MONTH:
        if (mon < 11) {
          setMonth(mon + 1)
        }
        else if (year < calendar.maxYear) {
          date.setFullYear(year + 1)
          setMonth(0)
        }
        break

      // Next Year
      case AuctionCalendar.NAV_NEXT_YEAR:
        if (year < calendar.maxYear)
          date.setFullYear(year + 1)
        break

    }

    if (!date.equalsTo(calendar.date)) {
      calendar.setDate(date)
      isNewDate = true
    } else if (el.navAction == 0) {
      isNewDate = (calendar.shouldClose = true)
    }
  }

  if (isNewDate) event && calendar.callSelectHandler()
  if (calendar.shouldClose) event && calendar.callCloseHandler()

  Event.stopObserving(document, 'mouseup', AuctionCalendar.handleMouseUpEvent)

  return Event.stop(event)
}

AuctionCalendar.defaultSelectHandler = function(calendar)
{
	// AuctionServices Additions
	if (calendar.auctions.get(AuctionCalendar.railsFormatDate(calendar.date)) != null)
		document.location = calendar.auctionDetail+'?id='+calendar.auctions.get(AuctionCalendar.railsFormatDate(calendar.date))
		
	// Remaining portions of this callback deleted by AuctionServices.
	// Further, any references to dateField has been deleted.
}

AuctionCalendar.defaultCloseHandler = function(calendar)
{
  calendar.hide()
}


//------------------------------------------------------------------------------
// AuctionCalendar Setup
//------------------------------------------------------------------------------

AuctionCalendar.setup = function(params)
{

  function param_default(name, def) {
    if (!params[name]) params[name] = def
  }

  param_default('triggerElement', null)
  param_default('parentElement', null)
  param_default('selectHandler',  null)
  param_default('closeHandler', null)

	// AuctionServices Addition
	param_default('auctionDetail', 'auction_detail.php')
	
  // In-Page AuctionCalendar
  if (params.parentElement)
  {
    var calendar = new AuctionCalendar(params.parentElement)
    calendar.setSelectHandler(params.selectHandler || AuctionCalendar.defaultSelectHandler)
    if (params.dateFormat)
      calendar.setDateFormat(params.dateFormat)
    calendar.show()

		// AuctionServices Addition
		calendar.setAuctionDetail(params.auctionDetail)
		
    return calendar
  }

  // Popup AuctionCalendars
  //
  // XXX There is significant optimization to be had here by creating the
  // calendar and storing it on the page, but then you will have issues with
  // multiple calendars on the same page.
  else
  {
    var triggerElement = $(params.triggerElement)
    triggerElement.onclick = function() {
      var calendar = new AuctionCalendar()
      calendar.setSelectHandler(params.selectHandler || AuctionCalendar.defaultSelectHandler)
      calendar.setCloseHandler(params.closeHandler || AuctionCalendar.defaultCloseHandler)
      if (params.dateFormat)
        calendar.setDateFormat(params.dateFormat)
      calendar.showAtElement(triggerElement)

			// AuctionServices Addition
			calendar.setAuctionDetail(params.auctionDetail)

      return calendar
    }
  }

}



//------------------------------------------------------------------------------
// AuctionCalendar Instance
//------------------------------------------------------------------------------

AuctionCalendar.prototype = {

  // The HTML Container Element
  container: null,

  // Callbacks
  selectHandler: null,
  closeHandler: null,

  // Configuration
  minYear: 1900,
  maxYear: 2100,
  dateFormat: '%Y-%m-%d',

  // Dates
  date: new Date(),
  currentDateElement: null,

  // Status
  shouldClose: false,
  isPopup: true,

	// AuctionServices Addition.
	auctions: new Hash({"2010/05/08":131310,"2010/12/01":125528,"2010/04/05":129333,"2010/03/27":129013,"2010/03/28":129013,"2010/03/18":129011,"2010/04/21":131307,"2010/06/16":125525,"2010/08/25":125524,"2010/04/11":129667,"2010/04/24":131309}),
	auctionDetail: 'auction_detail.php',

  //----------------------------------------------------------------------------
  // Initialize
  //----------------------------------------------------------------------------

  initialize: function(parent)
  {
    if (parent)
      this.create($(parent))
    else
      this.create()
  },

  //----------------------------------------------------------------------------
  // Update / (Re)initialize AuctionCalendar
  //----------------------------------------------------------------------------

  update: function(date)
  {
    var calendar   = this
    var today      = new Date()
    var thisYear   = today.getFullYear()
    var thisMonth  = today.getMonth()
    var thisDay    = today.getDate()
    var month      = date.getMonth();
    var dayOfMonth = date.getDate();

    // Ensure date is within the defined range
    if (date.getFullYear() < this.minYear)
      date.setFullYear(this.minYear)
    else if (date.getFullYear() > this.maxYear)
      date.setFullYear(this.maxYear)

    this.date = new Date(date)

    // Calculate the first day to display (including the previous month)
    date.setDate(1)
    date.setDate(-(date.getDay()) + 1)

		// Fill in the days of the month
    Element.getElementsBySelector(this.container, 'tbody tr').each(
      function(row, i) {
        var rowHasDays = false
        row.immediateDescendants().each(
          function(cell, j) {
            var day            = date.getDate()
            var dayOfWeek      = date.getDay()
            var isCurrentMonth = (date.getMonth() == month)

            // Reset classes on the cell
            cell.className = ''
            cell.date = new Date(date)
            cell.update(day)

            // Account for days of the month other than the current month
            if (!isCurrentMonth)
              cell.addClassName('otherDay')
            else
              rowHasDays = true

            // Ensure the current day is selected
            if (isCurrentMonth && day == dayOfMonth) {
              cell.addClassName('selected')
              calendar.currentDateElement = cell
            }

            // Today
            if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
              cell.addClassName('today')

            // Weekend
            if ([0, 6].indexOf(dayOfWeek) != -1)
              cell.addClassName('weekend')

						// AuctionServices Addition
						if (calendar.auctions.get(AuctionCalendar.railsFormatDate(date)) != null)
							cell.addClassName('event')

            // Set the date to tommorrow
            date.setDate(day + 1)
          }
        )
        // Hide the extra row if it contains only days from another month
        !rowHasDays ? row.hide() : row.show()
      }
    )

    this.container.getElementsBySelector('td.title')[0].update(
      AuctionCalendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear()
    )
  },



  //----------------------------------------------------------------------------
  // Create/Draw the AuctionCalendar HTML Elements
  //----------------------------------------------------------------------------

  create: function(parent)
  {

    // If no parent was specified, assume that we are creating a popup calendar.
    if (!parent) {
      parent = document.getElementsByTagName('body')[0]
      this.isPopup = true
    } else {
      this.isPopup = false
    }

    // AuctionCalendar Table
    var table = new Element('table')

    // AuctionCalendar Header
    var thead = new Element('thead')
    table.appendChild(thead)

    // Title Placeholder
    var row  = new Element('tr')
    var cell = new Element('td', { colSpan: 7, className: 'title' })
    cell.addClassName('title')
    row.appendChild(cell)
    thead.appendChild(row)

    // AuctionCalendar Navigation
    row = new Element('tr')
    this._drawButtonCell(row, '&#x00ab;', 1, AuctionCalendar.NAV_PREVIOUS_YEAR)
    this._drawButtonCell(row, '&#x2039;', 1, AuctionCalendar.NAV_PREVIOUS_MONTH)
    this._drawButtonCell(row, 'Today',    3, AuctionCalendar.NAV_TODAY)
    this._drawButtonCell(row, '&#x203a;', 1, AuctionCalendar.NAV_NEXT_MONTH)
    this._drawButtonCell(row, '&#x00bb;', 1, AuctionCalendar.NAV_NEXT_YEAR)
    thead.appendChild(row)

    // Day Names
    row = new Element('tr')
    for (var i = 0; i < 7; ++i) {
      cell = new Element('th').update(AuctionCalendar.SHORT_DAY_NAMES[i])
      if (i == 0 || i == 6)
        cell.addClassName('weekend')
      row.appendChild(cell)
    }
    thead.appendChild(row)

    // AuctionCalendar Days
    var tbody = table.appendChild(new Element('tbody'))
    for (i = 6; i > 0; --i) {
      r = new Element('tr', { className: 'days' })
      r.addClassName('days')
      row = tbody.appendChild(r)
      for (var j = 7; j > 0; --j) {
        cell = row.appendChild(new Element('td'))
        cell.calendar = this
      }
    }

    // AuctionCalendar Container (div)
    el = new Element('div', { className: 'calendar' })
    el.addClassName('calendar')
    this.container = el
    if (this.isPopup) {
      this.container.setStyle({ position: 'absolute', display: 'none' })
      this.container.addClassName('popup')
    }
    this.container.appendChild(table)

    // Initialize AuctionCalendar
    this.update(this.date)

    // Observe the container for mousedown events
    Event.observe(this.container, 'mousedown', AuctionCalendar.handleMouseDownEvent)

    // Append to parent element
    parent.appendChild(this.container)

  },

  _drawButtonCell: function(parent, text, colSpan, navAction)
  {
    var cell          = new Element('td')
    if (colSpan > 1) cell.colSpan = colSpan
    cell.className    = 'button'
    cell.calendar     = this
    cell.navAction    = navAction
    cell.innerHTML    = text
    cell.unselectable = 'on' // IE
    parent.appendChild(cell)
    return cell
  },



  //------------------------------------------------------------------------------
  // Callbacks
  //------------------------------------------------------------------------------

  // Calls the Select Handler (if defined)
  callSelectHandler: function()
  {
    if (this.selectHandler)
      this.selectHandler(this, this.date.print(this.dateFormat))
  },

  // Calls the Close Handler (if defined)
  callCloseHandler: function()
  {
    if (this.closeHandler)
      this.closeHandler(this)
  },



  //------------------------------------------------------------------------------
  // AuctionCalendar Display Functions
  //------------------------------------------------------------------------------

  // Shows the AuctionCalendar
  show: function()
  {
    this.container.show()
    if (this.isPopup) {
      window._popupAuctionCalendar = this
      Event.observe(document, 'mousedown', AuctionCalendar._checkAuctionCalendar)
    }
  },

  // Shows the calendar at the given absolute position
  showAt: function (x, y)
  {
    this.container.setStyle({ left: x + 'px', top: y + 'px' })
    this.show()
  },

  // Shows the AuctionCalendar at the coordinates of the provided element
  showAtElement: function(element)
  {
    var pos = Position.cumulativeOffset(element)
    this.showAt(pos[0], pos[1])
  },

  // Hides the AuctionCalendar
  hide: function()
  {
    if (this.isPopup)
      Event.stopObserving(document, 'mousedown', AuctionCalendar._checkAuctionCalendar)
    this.container.hide()
  },



  //------------------------------------------------------------------------------
  // Miscellaneous
  //------------------------------------------------------------------------------

  // Tries to identify the date represented in a string.  If successful it also
  // calls this.setDate which moves the calendar to the given date.
  parseDate: function(str, format)
  {
    if (!format)
      format = this.dateFormat
    this.setDate(Date.parseDate(str, format))
  },



  //------------------------------------------------------------------------------
  // Getters/Setters
  //------------------------------------------------------------------------------

  setSelectHandler: function(selectHandler)
  {
    this.selectHandler = selectHandler
  },

  setCloseHandler: function(closeHandler)
  {
    this.closeHandler = closeHandler
  },

  setDate: function(date)
  {
    if (!date.equalsTo(this.date))
      this.update(date)
  },

	// AuctionServices Addition
	setAuctionDetail: function(page)
	{
		this.auctionDetail = page
	},

  setDateFormat: function(format)
  {
    this.dateFormat = format
  },

  setRange: function(minYear, maxYear)
  {
    this.minYear = minYear
    this.maxYear = maxYear
  }

}

// global object that remembers the calendar
window._popupAuctionCalendar = null

// Date extensions removed from this script as its meant to be
// used with the AuctionServices Javascript bundle on the client PHP.