//#############################################################################
//
// 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 = "Wunderkemmer.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", "Wunderkemmer.com - Putting The I In iPhone"));
    head.append(getMetaName("keywords", "Peter Adam Kemmer, Peter A. Kemmer, Peter Kemmer, Peter, Kemmer, iPhone, iPurr"));
    head.append(getMetaName("reply-to", "webmaster@wunderkemmer.com"));
    head.append(getMetaName("robots", "index, follow"));
    head.newline();

    head.append(getLink("http://www.wunderkemmer.com/", "rel", "home"));
    head.append(getLink("http://www.wunderkemmer.com/Favicon.ico", "rel", "icon", "type", "image/x-icon"));
    head.append(getLink("mailto:webmaster@wunderkemmer.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.wunderkemmer.com",
            getImg("/Favicon.ico", "wunderkemmer.com", "align", "top", "style", "margin-top: 1")
        ),
        " "
    );

    if (pageTitle.startsWith(WINDOW_TITLE_START)) {
        fullTitle.append(
            getA("http://www.wunderkemmer.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.wunderkemmer.com/", "www.wunderkemmer.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));
}




