//#############################################################################
//
// A JavaScript library for classes, values, and utilites used to render:
//
// PeterKemmer.com
// http://www.peterkemmer.com
//
// ©2007 Peter A. Kemmer
//
//#############################################################################

//-----------------------------------------------------------------------------
// Verify Dependencies
//-----------------------------------------------------------------------------

if (!isDefined(HTML_LIBRARY_LOADED)) {
    alert("Error: The library HTML.js needs to be loaded before Website.js");
}

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

var UTILITIES_LIBRARY_LOADED = true;

// Window title should always start with this string,
// it will get added, along with a dash, if it's not!

var WINDOW_TITLE_START = "PeterKemmer.com";

// Default style sheets, every header always loads STYLE_SHEET_LAYOUT

var STYLE_SHEET_LAYOUT = "/Style.Layout.css";
var STYLE_SHEET_BLACK = "/Style.Black.css";
var STYLE_SHEET_WHITE = "/Style.White.css";

var STYLE_SHEET_LTE_IE6 = "/Style.LTE.IE6.css";
var STYLE_SHEET_LTE_IE7 = "/Style.LTE.IE7.css";

var BAR_THIN_BAR = 3;           // Standard divider bar
var BAR_THIN_GAP = 5;           // Thin gap for veritcal spacing
var BAR_WIDE_GAP = 20;          // Wide gap for veritcal spacing

//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------

var gStyleSheets = new Array(STYLE_SHEET_LAYOUT);

var gWindowTitle = null;        // Window title
var gPageTitle = null;          // Top left of header
var gPageTitleRight = null;     // Top right of header

var gExtraHeader = null;        // Extra contnet to place in the header
var gExtraFooter = null;        // Extra contnet to place in the footer

var gPageCentered = false;      // Horizontal/vertical centering

//#############################################################################
// Page Customization
//#############################################################################

/**
 * addStyleSheet
 *
 * Add a path to a style sheet, used to style the page
 *
 * @param styleSheet - A path to a style sheet
 */
function addStyleSheet(styleSheet) {
    gStyleSheets[gStyleSheets.length] = styleSheet;
}

/**
 * getStyleSheets
 *
 * Get the style sheet paths
 */
function getStyleSheets() {
    return gStyleSheets;
}

/**
 * setWindowTitle
 *
 * Set the window title, seen in the title bar of the browser
 *
 * @param windowTitle - The window title
 */
function setWindowTitle(windowTitle) {
    gWindowTitle = windowTitle;
}

/**
 * getWindowTitle
 *
 * Get the window title, or the page title if unset
 */
function getWindowTitle() {
    if (gWindowTitle == null) {
        return getPageTitle();
    } else {
        return gWindowTitle;
    }
}

/**
 * setPageTitle
 *
 * Set the page title, seen at the upper left of the page header
 *
 * @param pageTitle - The page title
 */
function setPageTitle(pageTitle) {
    gPageTitle = pageTitle;
}

/**
 * getPageTitle
 *
 * Get the page title, or "Untitled" if unset
 */
function getPageTitle() {
    if (gPageTitle == null) {
        return "Untitled";
    } else {
        return gPageTitle;
    }
}

/**
 * setPageTitleRight
 *
 * Set the page subtitle, seen at the upper right of the page header
 *
 * @param pageTitleRight - The page subtitle
 */
function setPageTitleRight(pageTitleRight) {
    gPageTitleRight = pageTitleRight;
}

/**
 * getPageTitleRight
 *
 * Get the page subtitle, or null if unset
 */
function getPageTitleRight() {
    return gPageTitleRight;
}

/**
 * setPageCentered
 *
 * Set the page centering, will center both horizontally/vertically if true
 *
 * @param pageCentered - true/false center the page
 */
function setPageCentered(pageCentered) {
    gPageCentered = pageCentered;
}

/**
 * getPageCentered
 *
 * Get the page centering
 */
function getPageCentered() {
    return gPageCentered;
}

//#############################################################################
// Bar Rendering
//#############################################################################

/**
 * getBar
 *
 * Get a single horizontal bar used to split the page
 *
 * @param height - See below
 *
 * A positive row height will add a filled row, 0 height will
 * skip the row, and a negative height will add a spacer row!
 */
function getBar(height, marginOne, marginTwo) {
    var buffer = new StringBuffer();

    buffer.append("height: ", height, ";");

    // If there's only one buffer use
    // it for both the top and bottom

    if (marginOne != null) {
        buffer.append(" margin-top: ", marginOne, ";");

        if (marginTwo == null) {
            buffer.append(" margin-bottom: ", marginOne, ";");
        }
    }

    // If there's two, use separately

    if (marginTwo != null) {
        buffer.append(" margin-bottom: ", marginTwo, ";");
    }

    return getDiv("bar", null, "style", buffer.toString());
}

/**
 * writeBar
 *
 * Write a single horizontal bar used to split the page
 *
 * @param height - See below
 *
 * A positive row height will add a filled row, 0 height will
 * skip the row, and a negative height will add a spacer row!
 */
function writeBar(height) {
    write(getBar(height));
}

/**
 * getHeaderBar
 *
 * Get a header bar - a thin gap, a divider, and wide gap
 */
function getHeaderBar() {
    return getBar(BAR_THIN_BAR, BAR_THIN_GAP, BAR_WIDE_GAP);
}

/**
 * writeHeaderBar
 *
 * Write a header bar - a thin gap, a divider, and wide gap
 */
function writeHeaderBar() {
    write(getHeaderBar());
}

/**
 * getSubtitleBar
 *
 * Get a subtitle bar - a wide gap, a divider, thin gap, and subtitle
 *
 * @param subtitle - The subtitle
 */
function getSubtitleBar(subtitle) {
    var buffer = new StringBuffer();

    buffer.append(
        getBar(BAR_THIN_BAR, BAR_WIDE_GAP, BAR_THIN_GAP),
        "\n",
        getDiv("subtitle thinBottom", subtitle)
    );

    return buffer.toString();
}

/**
 * writeSubtitleBar
 *
 * Write a subtitle bar - a wide gap, a divider, thin gap, and subtitle
 *
 * @param subtitle - The subtitle
 */
function writeSubtitleBar(subtitle) {
    write(getSubtitleBar(subtitle));
}

/**
 * getSplitterBar
 *
 * Get a splitter bar - a thin gap, a divider, and thin gap
 */
function getSplitterBar() {
    return getBar(BAR_THIN_BAR, BAR_THIN_GAP);
}

/**
 * writeSplitterBar
 *
 * Write a splitter bar - a thin gap, a divider, and thin gap
 */
function writeSplitterBar() {
    write(getSplitterBar());
}

/**
 * getSeparatorBar
 *
 * Get a separator - a wide gap, a divider, and wide gap
 */
function getSeparatorBar() {
    return getBar(BAR_THIN_BAR, BAR_WIDE_GAP);
}

/**
 * writeSeparatorBar
 *
 * Write a separator - a wide gap, a divider, and wide gap
 */
function writeSeparatorBar() {
    write(getSeparatorBar());
}

/**
 * getFooterBar
 *
 * Get a footer bar - a wide gap, a divider, and thin gap
 */
function getFooterBar() {
    return getBar(BAR_THIN_BAR, BAR_WIDE_GAP, BAR_THIN_GAP);
}

/**
 * writeFooterBar
 *
 * Write a footer bar - a wide gap, a divider, and thin gap
 */
function writeFooterBar() {
    write(getFooterBar());
}

//#############################################################################
// Strip Layouts
//#############################################################################

/**
 * getImageStrip
 *
 * Get html used to arrange images in a column or non-wrapping row
 *
 * @param hrefOpt - Optional url to link the images to
 * @param extraStyleOpt - Optional style to add padding after the strip, etc.
 * @param column - Display as a column, or not
 */
function getImageStrip(hrefOpt, extraStyleOpt, column) {
    var divClazz = column ? "imageColumn" : "imageRow";
    var spanClazz = column ? "imageColumnPadding" : "imageRowPadding";

    // Add href to image attributes

    var attributes = new Attributes("class", "centered");

    if (hrefOpt != null) {
        attributes.href = hrefOpt;
    }

    // Shove images into new buffer

    var buffer = new StringBuffer();

    for (var ii = 3; ii < arguments.length; ii++) {
        var argument = arguments[ii];

        if (isArray(argument)) {
            for (var jj = 0; jj < argument.length; jj++) {
                if (ii < arguments.length - 1 || jj < argument.length - 1) {
                    buffer.append(getSpan(spanClazz, getImg(argument[jj], null, attributes)));
                } else {
                    buffer.append(getImg(argument[jj], null, attributes));
                }
            }
        } else {
            if (ii < arguments.length - 1) {
                buffer.append(getSpan(spanClazz, getImg(argument, null, attributes)));
            } else {
                buffer.append(getImg(argument, null, attributes));
            }
        }

    }

    return getDiv(extraStyleOpt, buffer.toString(), "class", divClazz);
}

/**
 * getImageRow
 *
 * Get html used to arrange images in a row
 *
 * @param hrefOpt - Optional url to link the images to
 * @param extraStyleOpt - Optional style to add padding after the strip, etc.
 */
function getImageRow(hrefOpt, extraStyleOpt) {
    return getImageStrip(hrefOpt, extraStyleOpt, false, trimArguments(arguments, 2));
}

/**
 * writeImageRow
 *
 * Write html used to arrange images in a row
 *
 * @param hrefOpt - Optional url to link the images to
 * @param extraStyleOpt - Optional style to add padding after the strip, etc.
 */
function writeImageRow(hrefOpt, extraStyleOpt) {
    write(getImageStrip(hrefOpt, extraStyleOpt, false, trimArguments(arguments, 2)));
}

/**
 * getImageColumn
 *
 * Get html used to arrange images in a column
 *
 * @param hrefOpt - Optional url to link the images to
 * @param extraStyleOpt - Optional style to add padding after the strip, etc.
 */
function getImageColumn(hrefOpt, extraStyleOpt) {
    return getImageStrip(hrefOpt, extraStyleOpt, true, trimArguments(arguments, 2));
}

/**
 * writeImageColumn
 *
 * Write html used to arrange images in a column
 *
 * @param hrefOpt - Optional url to link the images to
 * @param extraStyleOpt - Optional style to add padding after the strip, etc.
 */
function writeImageColumn(hrefOpt, extraStyleOpt) {
    write(getImageStrip(hrefOpt, extraStyleOpt, true, trimArguments(arguments, 2)));
}

//#############################################################################
// Page Header & Footer
//#############################################################################

/**
 * getPageHeader
 *
 * Get the page header
 */
function getPageHeader() {
    var html = new StringBuffer("\n");
    var head = new StringBuffer("\n", 1);
    var header = new StringBuffer("\n", 1);

    // Start the html and head tags

    html.append("<html>\n<head>");
    html.newline();

    // Write the tag to set the window's title

    var windowTitle = getWindowTitle();

    if (!windowTitle.startsWith(WINDOW_TITLE_START)) {
        windowTitle = "".append(WINDOW_TITLE_START, " - ", windowTitle);
    }

    head.append(getTitle(windowTitle));
    head.newline();

    // Write the tags to set the style sheets

    var styleSheets = getStyleSheets();

    for (var ii = 0; ii < styleSheets.length; ii++) {
        head.append(getStyleSheet(styleSheets[ii]));
    }

    head.newline();

    head.append(getConditionalComment("LTE IE 6", getStyleSheet(STYLE_SHEET_LTE_IE6)));
    head.append(getConditionalComment("LTE IE 7", getStyleSheet(STYLE_SHEET_LTE_IE7)));
    head.newline();

    // Write the remaining head tags

    head.append(getMetaHttpEquiv("Content-Type", "text/html; charset=UTF-8"));
    head.newline();

    head.append(getMetaName("author", "Peter A. Kemmer"));
    head.append(getMetaName("description", "PeterKemmer.com - Putting The I In Internet"));
    head.append(getMetaName("keywords", "Peter Adam Kemmer, Peter A. Kemmer, Peter Kemmer, Peter, Kemmer, Resume, CV, Network Appliance, NetApp, NTAP, NetCache, DataFabric Manager, DFM, DataFabric Backup Manager, DFBM, DataFabric Disaster Recovery Manager, DFDRM, Operations Manager, NetApp Management Framework, NMF, NetApp Management Console, NMC, Protection Manager, Disaster Recovery, Provisioning Manager, Diablo II, Oddballz, Dogz II, Catz II, Dogz II Premium, Dogz II Add-On Pack, Catz II Add-On Pack, Dogz 3, Catz 3, After Dark 3.0, The Simpsons Screen Saver, The Star Trek: TNG Screen Saver, The Marvel Screen Saver, The Looney Tunes Saver, After Dark 4.0"));
    head.append(getMetaName("reply-to", "webmaster@peterkemmer.com"));
    head.append(getMetaName("robots", "index, follow"));
    head.newline();

    head.append(getLink("http://www.peterkemmer.com/", "rel", "home"));
    head.append(getLink("http://www.peterkemmer.com/Favicon.ico", "rel", "icon", "type", "image/x-icon"));
    head.append(getLink("mailto:webmaster@peterkemmer.com", "rev", "made", "title", "PeterKemmer.com"));
    head.newline();

    html.append(head.toString());

    // Done with the head!

    html.append("</head>\n<body>");
    html.newline();

    // Write the top of the table that wraps the
    // page content with header and footer areas

    html.append('<table class="fullsize"><tr><td>');

    var fullTitle = new StringBuffer();
    var pageTitle = getPageTitle();

    fullTitle.append(
        getA(
            "http://www.peterkemmer.com",
            getImg("/Favicon.ico", "peterkemmer.com", "align", "top", "style", "margin-top: 1")
        ),
        " "
    );

    if (pageTitle.startsWith(WINDOW_TITLE_START)) {
        fullTitle.append(
            getA("http://www.peterkemmer.com", WINDOW_TITLE_START, "class", "title"),
            pageTitle.substr(WINDOW_TITLE_START.length)
        );
    } else {
        fullTitle.append(pageTitle);
    }

    header.append(getSpan("header left", fullTitle.toString()));

    if (getPageTitleRight() != null) {
        header.append(getSpan("header right", getPageTitleRight()));
    }

    header.append(getHeaderBar());

    html.append(header.toString());

    if (getPageCentered()) {
        html.append('</td></tr><tr><td class="fullsize centered">');
    } else {
        html.append('</td></tr><tr><td class="fullsize topleft">');
    }

    return html.toString();
}

/**
 * writePageHeader
 *
 * Write the page header
 */
function writePageHeader() {
    write(getPageHeader());
}

/**
 * getPageFooter
 *
 * Get the page footer
 */
function getPageFooter() {
    var html = new StringBuffer("\n");
    var footer = new StringBuffer("\n", 1);

    // Write the end of the table that wraps the
    // page content with header and footer areas

    html.append("</td></tr><tr><td>");

    footer.append(getFooterBar());
    footer.append(getSpan("footer left", getA("http://www.peterkemmer.com/", "www.peterkemmer.com")));
    footer.append(getSpan("footer right", '<i>Spectacular</i> web hosting provided by ' + getA("http://www.dreamhost.com/rewards.cgi?pkmousie", "DreamHost")));

    html.append(footer.toString());
    html.append("</td></tr></table>");
    html.newline();

    // End the body and html tags, we're done!!!

    html.append("</body>\n</html>");

    return html.toString();
}

/**
 * writePageFooter
 *
 * Write the page footer
 */
function writePageFooter() {
    write(getPageFooter());
}

//#############################################################################
// ResumeItem - A convenience class to define/render a resume item
//#############################################################################

/**
 * ResumeItem 'Constructor'
 *
 * A convenience class to define/render a resume item:
 *
 * name           date
 * role info info info
 * info info info info
 * info info info info
 *
 * @param name - The name of the item
 * @param date - The dates involved
 * @param role - The role performed
 * @param info - The item information
 */
function ResumeItem(name, info, role, date) {

    // class variables --------------------------------------------------------

    this.name = name;
    this.info = info;
    this.role = role;
    this.date = date;
}

/**
 * ResumeItem.toString
 *
 * Gets the HTML used to render an ResumeItem object
 */
ResumeItem.prototype.toString = function() {
    var buffer = new StringBuffer("\n");

    // Date span comes first because it floats, it only APPEARS second!

    if (this.date != null) {
        buffer.append(getSpan("resumename right", this.date));
    }

    // Note the <br> that drops the role/info down below the name/date!

    if (this.name != null) {
        buffer.append(getSpan("resumename", this.name) + "<br>");
    }

    // Note that I'm sneaking in a colon after the value of the role!!!

    if (this.role != null) {
        buffer.append(getSpan("resumerole", this.role + ":"));
    }

    if (this.info != null) {
        buffer.append(getSpan("resumeinfo", this.info));
    }

    return buffer.toString();
}

//#############################################################################
// Resume Functions
//#############################################################################

/**
 * getResumeAddress
 *
 * Get a address formatted for a resume
 *
 * @param content - The address
 */
function getResumeAddress(address) {
    return getSpan("resumeaddress", address);
}

/**
 * writeResumeAddress
 *
 * Get a address formatted for a resume
 *
 * @param content - The content
 */
function writeResumeAddress(address) {
    write(getResumeAddress(address));
}

/**
 * getResumeSection
 *
 * Get a section of a resume
 *
 * @param subtitle - The subtitle of the section
 * @param content - The content
 */
function getResumeSection(subtitle, content) {
    var buffer = new StringBuffer("\n");

    buffer.append(getSubtitleBar(subtitle));
    buffer.newline();

    // If we're just displaying single primitive/string, don't wrap in list

    if (content != null) {
        if (typeof content != "object") {
            buffer.append(content);
        } else {
            buffer.append(new List(content, false, "resumelist", "thinBottom"));
        }
    }

    buffer.newline();

    return buffer.toString();
}

/**
 * writeResumeSection
 *
 * Write a section of a resume
 */
function writeResumeSection(subtitle, content) {
    write(getResumeSection(subtitle, content));
}