// This is a concatenation of Day/Day.js, Dynamic.js, and Web.js.

// ---------- Day/Day.js ----------

function Day(monthOrDay, day, year) {
  if (arguments.length == 0) {
    this.date = new Date();
  } else if (monthOrDay instanceof Day) {
    this.date = new Date(monthOrDay.date.getTime());
  } else {
    this.date = new Date(year, monthOrDay - 1, day);
  }
}
Day.TIME_IN_DAY = 1000*60*60*24;
Day.DAYS = [
  "Sunday",
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday"
];
Day.MONTHS = [
  "January",
  "February",
  "March",
  "April",
  "May",
  "June",
  "July",
  "August",
  "September",
  "October",
  "November",
  "December"
];
Day.prototype.dateString = function() {
  var string = Day.DAYS[this.date.getDay()];
  string += " " + Day.MONTHS[this.date.getMonth()];
  return string + " " + this.date.getDate();
};
Day.prototype.getDayOfWeek = function() {
  return this.date.getDay() + 1;
};
Day.prototype.getDayOfWeekName = function(length) {
  var dayOfWeekName = Day.DAYS[this.date.getDay()];
  if (!length || length > dayOfWeekName.length) {
    return dayOfWeekName;
  }
  return dayOfWeekName.substring(0, length);
};
Day.prototype.getDayOfMonth = function() {
  return this.date.getDate();
};
Day.prototype.getMonth = function() {
  return this.date.getMonth() + 1;
};
Day.prototype.getMonthName = function(length) {
  var monthName = Day.MONTHS[this.date.getMonth()];
  if (!length || length > monthName.length) {
    return monthName;
  }
  return monthName.substring(0, length);
};
Day.prototype.compareToSelf = function(day) {
  return (day.date.getTime() - this.date.getTime())/Day.TIME_IN_DAY;
};
Day.prototype.toString = function() {
  return this.date.toDateString().substring(4);
};
Day.prototype.add = function(increment) {
  if (arguments.length == 0) {
    this.date.setTime(this.date.getTime() + Day.TIME_IN_DAY);
  } else {
    this.date.setTime(this.date.getTime() + increment*Day.TIME_IN_DAY);
  }
  return this;
};

function DayRange(start, endOrDuration) {
  this.start = start;
  var end;
  if (arguments.length == 1) {
    end = new Day(start).add();
  } else {
    if (endOrDuration instanceof Day) {
      end = new Day(endOrDuration).add();
    } else {
      end = new Day(start).add(endOrDuration);
    }
  }
  this.end = end;
}
DayRange.prototype.compareToSelf = function(day) {
  var startLead = this.start.compareToSelf(day);
  if (startLead < 0) {
    return startLead;
  }
  var endLead = this.end.compareToSelf(day) + 1;
  if (endLead > 0) {
    return endLead;
  }
  return 0;
};
DayRange.prototype.getLength = function() {
  return this.start.compareToSelf(end);
};
DayRange.prototype.toString = function() {
  var returnString = this.start.toString();
  var days = this.start.compareToSelf(this.end);
  if (days < 1) {
    returnString += "(" + days + " days)";
  } else if (days > 1) {
    returnString += " - " + new Day(this.end).add(-1).toString();
  }
  return returnString;
};

function DaySet(start, endOrDuration, exclusions) {
  var newRanges = new Array();
  var end;
  if (arguments.length == 1) {
    end = new Date(start.getTime + TIME_IN_DAY);
  } else {
    if (endOrDuration instanceof Date) {
      end = endOrDuration + Day.TIME_IN_DAY;
    } else {
      end = new Date(start.getTime + Day.TIME_IN_DAY*endOrDuration);
    }
  }
  newRanges.push(new DayRange(start, end));
  this.intervals = newRanges;
  for (var i = 2; i < arguments.length; i++) {
    this.addExclusion(arguments[i]);
  }
}
DaySet.prototype.addExclusion = function(exclusion) {
  if (exclusion instanceof DaySet) {
    for (var i = 0; i < exclusion.intervals.length; i++) {
      this.addExclusion(exclusion.intervals[i]);
    }
  } else {
    var newRanges = new Array();
    for (var i = 0; i < this.intervals.length; i++) {
      var oldRange = this.intervals[i];
      if (exclusion.startTime >= oldRange.endTime) {
        newRanges.push(oldRange);
      } else if (exclusion.startTime  > oldRange.startTime) {
        newRanges.push(new DayRange(oldRange.start, exclusion.start));
      }
      if (exclusion.endTime <= oldRange.startTime) {
        newRanges.push(oldRange);
      } else if (exclusion.endTime < oldRange.startTime) {
        newRanges.push(new DayRange(exclusion.end, oldRange.end));
      }
    }
    this.intervals = newRanges;
  }
};
DaySet.prototype.isEmpty = function() {
  return this.intervals.length = 0;
};
DaySet.prototype.isIn = function(date) {
  for (var i = 0; i < intervals.length; i++) {
    var comparison = intervals[i].compareToSelf(date);
    if (comparison > 0) {
      return false;
    } else if (comparison == 0) {
      return true;
    }
  }
  return false;
};
DaySet.prototype.setOnOrAfter = function(date, daysOfWeekSet) {
  if (date.getTime() < this.start.getTime()) {
    date.setTime(this.start.getTime());
  }
  for (var i = 0; i < intervals.length; i++) {
    interval = intervals[i];
    if (date.getTime() < interval.startTime()) {
      date.setTime(this.start.getTime());
      if (daysOfWeekSet) {
        daysOfWeekSet.setOnOrAfter(date);
      }
    }
    if (date.getTime() < interval.end.getTime()) {
      return date;
    }
  }
  return null;
};

function DayOfWeekSet(daysOfWeek) {
  var newIncrements = new Array();
  for (var d = 1; d < 7; d++) {
    newIncrements[d] = 7;
  }
  for (var i = 0; i < daysOfWeek.length; i++) {
    var newDay = daysOfWeek[i];
    for (var increment = 1; increment < 7; increment++) {
      var day = newDay - increment;
      if ( day < 0) {
        day += 7;
      }
      if (newIncrements[day] <= increment) {
        break;
      }
      newIncrements[day] = increment;
    }
  }
  this.increments = newIncrements;
}
DayOfWeekSet.prototype.setOnOrAfter = function(date) {
  var increment = this.increments[date.getDay()];
  date.setTime(date.getTime() + increment*Day.TIME_IN_DAY);
};
DayOfWeekSet.prototype.setNext = function(date) {
  date.setTime(date.getTime() + Day.TIME_IN_DAY);
  this.setOnOrAfter(date);
};

// ---------- Dynamic.js ----------

function createLocalLink(site, relativeUrl, text) {
  var link = document.createElement("a");
  link.href = "javascript: Web.goToLocal('" + site + ", " + relativeUrl + "');"
  link.appendChild(document.createTextNode(text));
  return link;
}

function createWebLink(url, text) {
  var link = document.createElement("a");
  link.href = "javascript: Web.goTo('" + url + "');"
  link.appendChild(document.createTextNode(text));
  return link;
}

function createCourseLink(hash, text) {
  var link = document.createElement("a");
  link.href = "javascript: Navigator.setPage('" + hash + "');"
  link.appendChild(document.createTextNode(text));
  return link;
}

function createHeader(text) {
  var header = document.createElement("h4");
  header.appendChild(document.createTextNode(text));
  return header;
}

function createStyledParagraph(class1, text) {
  var paragraph = document.createElement("p");
  paragraph.appendChild(document.createTextNode(text));
  paragraph.className = class1;
  return paragraph;
}

function createParagraph(text) {
  var paragraph = document.createElement("p");
  paragraph.appendChild(document.createTextNode(text));
  return paragraph;
}

function createNavSection(hash, label) {
  var division = document.createElement("div");
  division.className = "nav-section";
  division.setAttribute("hash", hash);
  if (arguments.length > 1) {
    division.setAttribute("label", label);
  }
  return division;
}

function createNavLoad(url, hash, label) {
  var division = document.createElement("div");
  division.className = "nav-load";
  division.setAttribute("url", url);
  division.setAttribute("hash", hash);
  if (arguments.length > 2) {
    division.setAttribute("label", label);
  }
  return division;
}

function createTableColumnHeader(class1, text) {
  var header = document.createElement("th");
  header.className = class1;
  header.appendChild(document.createTextNode(text));
  return header;
}

function createTableEntry(class1, text) {
  var entry = document.createElement("td");
  entry.className = class1;
  entry.appendChild(document.createTextNode(text));
  return entry;
}

var Dynamic = {
  builders : {},
  addType : function(type, builder) {
    this.builders[type] = builder;
  },
  getSection : function(type) {
    var builder = this.builders[type];
    if (!builder) {
      var message = "Dynamic.getSection(" + type + ") failed.  Types are:";
      for (var name in this.builders) {
        message += " " + name;
      }
      message += ".";
      alert(message);
    }
    return builder();
  }
};

// ---------- Web.js ----------

function getHomeUrl() {
  var href = window.location.href;
  var index = href.lastIndexOf("umdweb");
  if (index < 0) {
    index = href.lastIndexOf("gshute");
  }
  return href.substring(0, index + 6);
}
    
var Web = {
  sites : {},
  addSite : function(name) {
    var homeUrl = getHomeUrl();
    this.sites[name] = homeUrl + "/" + name;
  },
  getSite : function(name) {
    var site = this.sites[name];
    if (!site) {
      var message = "Web.getSite(" + name + ", " + relativeURL + ") failed.  Sites are:";
      for (var siteName in this.sites) {
        message += " " + siteName;
      }
      message += ".";
      alert(message);
    }
    return site;
  },
  getUrl : function(name, relativeUrl) {
    return this.getSite(name) + "/" + relativeUrl;
  },
  goTo : function(url) {
    window.location = url;
  }
};

Web.addSite("cs2521");
Web.addSite("arch");
Web.addSite("asm");
Web.addSite("ds");
Web.addSite("java");
Web.addSite("net");
Web.addSite("os");
Web.addSite("softeng");
Web.addSite("spimsal");
Web.addSite("swing");

