/* 
 * Script to handle 'Article' Functionality for WebReader.
*/
ArticleViewer = {
    articleFlag : false,
    articleMain : null,
    articleMainHandle : null,
    articleResizer : null,
    articleGhost: null,
    documentArticleFlag : null,
    documentArticleFlagWrapper : null,
    documentContainer : null,
    articleFlagText : null,
    action_catalyst : false,
    article : null,
    articleTocUrl : "/Article.action",
    articleTextUrl : "/Article.action?article_id=",
    initialized : false,
    active : false,
    hashParamName : "article_id",
    articlePreloadStarted : false,
//    backgroundLoad : true,
    backgroundLoad : false,
//    backgroundLoadWait : 5,  // wait between each article load for background process 
    backgroundLoadWait : 0,  // wait between each article load for background process 
    articleViewerHeight : 450,
    articleViewerWidth : 375,
    articleViewerMinHeight : 110,
    articleViewerMinWidth : 200,
    articleFixedSizes : {},
    
    // Initialize ArticleViewer
    init : function(){
        if(ArticleViewer.initialized === false){
            ArticleViewer.initWidthStorage();
            ArticleViewer.articleMain = $("#layer1");
            ArticleViewer.articleMainHandle = $("#layer1_handle");
            ArticleViewer.articleGhost = $("#layer1_ghost");
            ArticleViewer.documentArticleFlag = $("#documentArticleFlag");
            ArticleViewer.documentArticleFlagWrapper = $("#documentArticleFlagWrapper");
            ArticleViewer.articleFlagText = $("#articleFlagText");
            ArticleViewer.documentContainer = $("#documentContainer");
            ArticleViewer.Articles.init();
            ArticleViewer.Content.init();
            ArticleViewer.Comment.init();
            ArticleViewer.initialized = true;
        }
    },

    // Calculate and store values that are used many times, but that don't change
    // Note: For Safari & Chrome craziness; only use margin-left value.  This only
    //       works as left and right margins for caps are the same.
    initWidthStorage : function() {
        ArticleViewer.articleViewerWidth = $(document).width() < ArticleViewer.articleViewerWidth ?
                $(document).width() : ArticleViewer.articleViewerWidth;
        ArticleViewer.articleViewerWidth = $(document).width() < ArticleViewer.articleViewerWidth ?
                $(document).width() : ArticleViewer.articleViewerWidth;
        ArticleViewer.articleFixedSizes["cap1"] =
                (parseInt($(".cap1").css("margin-left"), 10) * 2) +
                (parseInt($(".cap1").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["cap2"] =
                (parseInt($(".cap2").css("margin-left"), 10) * 2) +
                (parseInt($(".cap2").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["cap3"] =
                (parseInt($(".cap3").css("margin-left"), 10) * 2) +
                (parseInt($(".cap3").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["cap4t"] =
                (parseInt($(".cap4t").css("margin-left"), 10) * 2) +
                (parseInt($(".cap4t").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["cap4b"] =
                (parseInt($(".cap4b").css("margin-left"), 10) * 2) +
                (parseInt($(".cap4b").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["articleWrapper"] =
                (parseInt($("#article").css("margin-left"), 10) * 2) +
                (parseInt($("#article").css("border-left-width"), 10) * 2);
        ArticleViewer.articleFixedSizes["articleMainVertical"] =
                parseInt($("#layer1").css("padding-top"), 10) +
                parseInt($("#layer1").css("padding-bottom"), 10);
    },
    
    /**
     * Call to display an article in the Viewer.
     * Checks to see if an article has already been loaded into the cache.  If not,
     * load the article content and call to store and show the article.  If cached,
     * just call to show the article.
     * If no article_id is passed in , check to see if the article_id is passed
     * as a parameter in the url.  If so, set the article_id from that.
     * If there is still no article_id, exit.
     * 
     * @param article_id Optional parameter for article id to load content
     * @param force_reload Optional parameter to force an article to reload
     */
    viewArticle : function(article_id, force_reload) {
        article_id = article_id ? article_id : null;
        force_reload = force_reload ? force_reload : false;
        if (article_id === null) {
            var idInUrl = document.location.href.indexOf(ArticleViewer.hashParamName) != -1;
            if (idInUrl){
                article_id = document.location.href.replace(/.*article_id=(\d+)(.*)/,'$1');
            }
        }
        // check if there is an article id and that it is in the list
        if (article_id !== null &&
                ($.inArray(article_id, ArticleViewer.Articles.list) != -1 ||
                force_reload === true)) {
            $("#fit_view").click();  //Set zoom level to 'fit page'
            ArticleViewer.show();
            ArticleViewer.setBusy();
            if (!force_reload && ArticleViewer.Articles.data[article_id] &&
                    ArticleViewer.Articles.data[article_id].hasOwnProperty("content")) {
                ArticleViewer.storeAndShowArticle(ArticleViewer.Articles.data[article_id]["content"], article_id);
            } else {
                DataSwitch.get({
                    url: DocumentProperties.getDocumentUrl() + ArticleViewer.articleTextUrl + article_id,
                    cache: false,
                    success: function(data){
                        ArticleViewer.storeAndShowArticle(data, article_id);
                    }
                });
            }
        }
    },

    /**
     * Show "Article Flag", if page has articles.
     * Given a Reading Order page, determine if that page has an
     * article on it.  If yes, show the Article Flag and setup the
     * Article Flag to show or hide the article on click.  If no,
     * hide the Article Flag.
     * 
     * @param pageNumber Reading order page number to find article
     */
    showArticleFlag : function(pageNumber) {
      var folios = PageController.getDisplayedPages(pageNumber)["folios"];
      if (ArticleViewer.Articles.list.length > 0) {
          var article_id = null;
          for (var i = 0; i < folios.length; i++) {
              article_id = ArticleViewer.Articles.getArticleIdByPageFolio(folios[i]);
              if (article_id !== null) {
                  break;
              }
          }

          if (article_id === null) {
              ArticleViewer.documentArticleFlag.css("visibility", "hidden");
          } else {
              ArticleViewer.documentArticleFlag.css("visibility", "visible");
              ArticleViewer.documentArticleFlagWrapper.corners("top-left top-right");
              ArticleViewer.documentArticleFlag.unbind('click').bind('click', function(){
                  ArticleViewer.articleFlag = true;
                  if (ArticleViewer.articleFlagText.text() == "Open Article") {
                      ArticleViewer.articleFlagText.text("Close Article");
                      ArticleViewer.viewArticle(article_id);
                  } else {
                      ArticleViewer.articleFlagText.text("Open Article");
                      ArticleViewer.hide();
                  }
              });
          }
      }
    },

    /**
     * Store article content data returned from Ajax call to get article content.
     * If article pre-loading has not been completed yet, add the next and previous
     * articles to the stack for priority loading.
     * Then call showLoadedArticle to show the article contents in the UI.
     * 
     * @param data article contents
     * @param article_id article id
     */
    storeAndShowArticle : function(data, article_id) {
        if (!ArticleViewer.Articles.data[article_id]) {
            ArticleViewer.hide();
        } else {
            ArticleViewer.Articles.data[article_id]["content"] = data;
            var nextId = ArticleViewer.Articles.next_id(article_id);
            var prevId = ArticleViewer.Articles.prev_id(article_id);
            if (!(ArticleViewer.Articles.data[nextId].hasOwnProperty("content") &&
                    ArticleViewer.Articles.data[prevId].hasOwnProperty("content"))) {
                ArticleViewer.ArticleLoader.add(nextId);
                ArticleViewer.ArticleLoader.add(prevId);
                ArticleViewer.ArticleLoader.populateArticleContent();
            }
            ArticleViewer.showLoadedArticle(article_id, data);
        }
    },

    /**
     * Show the article when AJAX request is complete and article has been cached
     * Make sure the viewer is setup properly to display the article and that all
     * the buttons are enabled.
     * 
     * @param article_id Article id of article to show
     * @param content Article text content
     */
    // 
    showLoadedArticle : function(article_id, content){
        if (ArticleViewer.Articles.data.hasOwnProperty(article_id)) {
            content = content ? content : ArticleViewer.Articles.data[article_id]["content"];
            ArticleViewer.Content.processArticleData(content);
            ArticleViewer.Content.show();
            ArticleViewer.updateHash(article_id);
            ArticleViewer.active = true;
            ArticleViewer.setArticle(article_id);
            ArticleViewer.action_catalyst = true;
            var folio = ArticleViewer.Articles.data[article_id].pgs[0];
            $("#curPageNumber").text(folio);
            if (ArticleViewer.articleFlag !== true) {
                PageController.handleGoToPage(PageController.getPageByFolio(folio));
            }
        }
    },

    /**
     * Show the Article viewer in the UI.  If the Article Flag is
     * visible, change the text to "Close Article"
     * Note: We use the visibility parameter in order to be able to
     * resize the viewer when it is not shown.
     */
    show : function(){
        ArticleViewer.active = true;
        ArticleViewer.Content.adjustDisplaySize();
        if (ArticleViewer.articleMain !== null) {
            ArticleViewer.articleMain.css({
                "visibility": "visible"
            });
        }
        if (ArticleViewer.articleFlagText != null) {
            ArticleViewer.articleFlagText.text("Close Article");
        }
    },
    
    /**
     * Hide the Article viewer.  If the Article Flag is visible,
     * change the text to "Open Article"
     */
    hide : function(e){
        ArticleViewer.active = false;
        if (ArticleViewer.articleMain !== null){
            ArticleViewer.articleMain.css({
                "visibility": "hidden"
            });
        }
        if (ArticleViewer.articleFlagText!= null){
          ArticleViewer.articleFlagText.text("Open Article");  
        }
    },
    
    setBusy : function() {
        var left = (ArticleViewer.Content.article.width() - 128)/2;
        var top = (ArticleViewer.Content.article.height() - ArticleViewer.articleMainHandle.height()) * 0.4;
        var source = '<img class=\"busy\" src=\"/images/misc/ajax-loader.gif\" border=\"0\"' +
                'style=\"margin-left:' + left + 'px;' +
                'margin-top:' + top + 'px;\" alt=\"loading\" />';
        ArticleViewer.Content.content_wrapper.html(source);
    },
    
    /**
     * Update the current article (ArticleViewer.article) given the article_id
     * of the article.  If the article_id cannot be found in the Articles.data
     * object, set the value to null.
     * 
     * @param article_id Article id used to get article object
     */
    setArticle : function(article_id){
        if(ArticleViewer.article !== null && ArticleViewer.article["article_id"] == article_id){
            return;
        }
        ArticleViewer.article =
            (typeof article_id != "undefined" && ArticleViewer.Articles.data.hasOwnProperty(article_id)) ?
                    ArticleViewer.Articles.data[article_id] :
                    null;
    },
    
    /**
     * Using the index value, find the article_id in the original article data
     * using the data in ArticleViewer.Articles.list.  Using this article_id,
     * return the article data object from Articles.data.
     * 
     * @param x Index of the article in the Articles list
     * @return the article object from Articles data
     */
    getArticleByIndex : function(x){
        if (x < 0 || (x > ArticleViewer.Articles.list.length - 1)) {
            return null;
        }
        var articleId = ArticleViewer.Articles.list[x];
        return ArticleViewer.Articles.data[articleId];
    },

    /**
     * Initilize Next, Prev, First and Last navigation behaviors for Article.
     */
    initPageNavigationButtonBehaviors : function(){
        $(".nextArticlePage")
            .unbind('click')
            .bind('click',ArticleViewer.nextArticle);
        $(".prevArticlePage")
            .unbind('click')
            .bind('click',ArticleViewer.prevArticle);
    },    

    /**
     * Go to Next Article
     * Find the next article, load it if not loaded, then show it in the
     * viewer
     * @param e Click event
     */
    nextArticle : function(e){
        e.preventDefault();
        e.stopPropagation();
        if (ArticleViewer.article) {
            var id = ArticleViewer.article["article_id"];
            var next_id = ArticleViewer.Articles.next_id(id);
            ArticleViewer.articleFlag = false;
            ArticleViewer.viewArticle(next_id);
        }
    },
    
    /**
     * Go to Previous Article
     * Find the previous article, load it if not loaded, then show it in the
     * viewer
     * @param e Click event
     */
    prevArticle : function(e){
        e.preventDefault();
        e.stopPropagation();
        if (ArticleViewer.article) {
            var id = ArticleViewer.article["article_id"];
            var prev_id = ArticleViewer.Articles.prev_id(id);
            ArticleViewer.articleFlag = false;
            ArticleViewer.viewArticle(prev_id);
        }
    },

    /**
     * Update URL
     * @param article_id Article Id to use to update url
     */
    updateHash : function(article_id){
        var param = ArticleViewer.hashParamName;
        var h_pattern = new RegExp("([^&?"+param+"]+)(&?"+param+"=[\\d]+)(.*)");
        var h = document.location.hash;
        var new_hash = "";
        if (article_id) {
            new_hash = param+"="+article_id;
        } else {
            new_hash = h.replace(h_pattern,'$1$3').replace("#","");
        }
        PageController.updateBrowserHistory(new_hash);
    }


};

ArticleViewer.Content = {
    wrapper : null,
    content_wrapper : null,
    contentMain : null,
    template : null,
    min_font_size : 10,
    default_font_size : 16,
    max_font_size : 24,
    go_to_comments_link : null,
    close_article_viewer_link : null,
    comment_submit_button : null,
    font_sizer_links : null,
    commentFormHeight : 175,
    doScrollToComments : false, 
    
    // Content initilization
    init : function(){
        var aWidth = ArticleViewer.documentContainer.width()/2 - 20;
        var aLeft = ArticleViewer.documentContainer.position().left + aWidth + 25;
        var aTop = ArticleViewer.documentContainer.position().top + 40;
        ArticleViewer.Content.article = $("#article", ArticleViewer.articleMain);
        ArticleViewer.Content.content_wrapper = $("#article_content_wrapper", this.wrapper);
        ArticleViewer.Content.initToolLinks();
        ArticleViewer.Content.initCommentsLinks();
        ArticleViewer.initPageNavigationButtonBehaviors();
        ArticleViewer.Content.adjustDisplaySize();
        ArticleViewer.articleMain.css('left',aLeft);
        ArticleViewer.articleMain.css('top',aTop);
    },
    
    // Show Contents
    show : function(){
        ArticleViewer.Content.article.css({
            "display": "block"
        });
    },
    
    // Hide Contents
    hide : function(){
        ArticleViewer.Content.article.css({
            "display": "none"
        });
    },
    
    // Handle article 'Close', Make Draggable and Resizable 
    initToolLinks : function(){
        $('#close').bind('click',function(e){
            if(e){
                e.preventDefault();
                e.stopPropagation();
            }
            ArticleViewer.hide();
        });

        ArticleViewer.articleMain.draggable(
        {
            zIndex: 20,
            opacity: 0.7,
            handle: '#layer1_handle',
            start: function(event, ui) {
                ArticleViewer.Content.articleDraggableStart();
            },
         // default, overridden later
            containment: [0, 0,
                    ($(window).width() - ArticleViewer.articleViewerMinWidth),
                    ($(window).height() - ArticleViewer.articleViewerMinHeight)]
        });
        
        ArticleViewer.articleMain.resizable(
        {
            handles: {'se':$('#layer1_resizer_handle')},
            alsoResize: ArticleViewer.articleGhost,
            start: function(event, ui) {
                ArticleViewer.Content.articleResizeStart();
            },
            resize: function(event, ui){},
            minHeight: ArticleViewer.articleViewerMinHeight,
            minWidth: ArticleViewer.articleViewerMinWidth,
            stop: function(event, ui) {
                ArticleViewer.Content.articleResizeStop();
            }
        });

   	},

    // some of these links are present when article viewer is created, some
    // are added later when the article is populated.  Anyway, do them all...
    initCommentsLinks: function() {
        var comment_submit_button = $("#comment_submit",ArticleViewer.Content.article);
        var go_to_comments_link = $("#article_comment_quicklink");
        var add_comments_link = $("#addArticleComment");
        comment_submit_button
            .unbind('click.create_comment')
            .bind('click.create_comment',ArticleViewer.Comment.create);
        go_to_comments_link
            .unbind('click.scrollToComments')
            .bind('click.scrollToComments',ArticleViewer.Content.scrollToComments);
        add_comments_link
            .unbind('click.scrollToAddComments')
            .bind('click.scrollToAddComments',ArticleViewer.Content.scrollToAddComments);
        $(".comment_reply a").live('click.comment_reply',ArticleViewer.Comment.initiateCommentReply);
   	},

    // some of these links are present when article viewer is created, some
    // are added later when the article is populated.  Anyway, do them all...
    initCommentReply: function() {
        var comment_submit_button = $("#comment_reply_submit",ArticleViewer.Content.article);
        comment_submit_button
            .unbind('click.create_comment')
            .bind('click.create_comment',ArticleViewer.Comment.create);
   	},
   	

   	// Scroll to 'Comments'
    scrollToComments : function(e){
        if(e){
            e.preventDefault();
            e.stopPropagation();
        }
        var ac = $("#article_content_inner",this.wrapper);
        if ($("#comments",this.wrapper).get(0) !== null) {
            var ct = $("#comments",this.wrapper).get(0).offsetTop - 60;
        } else {
            ct = $("#addCommentTitle",this.wrapper).get(0).offsetTop - 60;
        }
        if(ac.scrollTop() < ct){
       	    $("#article_content").animate({ scrollTop: ct },300);
        }
    },
    
    // Scroll to 'Add Comments'
    scrollToAddComments : function(e){
        if(e){
            e.preventDefault();
            e.stopPropagation();
        }       
        var ac = $("#article_content_inner",this.wrapper);       
        var ct = $("#addCommentTitle",this.wrapper).get(0).offsetTop - 60;        
        if(ac.scrollTop() < ct){       	
       		$("#article_content").animate({ scrollTop: ct },300);
        }        
    },

    // Process Article Change
    processArticleData : function(data){
        ArticleViewer.Content.content_wrapper.html(data);
        ArticleViewer.Content.adjustDisplaySize();
        ArticleViewer.Content.initCommentsLinks();
        ArticleViewer.action_catalyst = true;
        if (ArticleViewer.Content.doScrollToComments === true){
            ArticleViewer.Content.scrollToComments();
            // reset so only a single time
            ArticleViewer.Content.doScrollToComments = false;
        }
        ArticleViewer.Comment.init();
        setTimeout(function(){ArticleViewer.action_catalyst = false;},200);
    },

    // Determine Display size and placement. Add Scrollbar.
    adjustDisplaySize : function(){
        ArticleViewer.articleMain.css({
                'width': ArticleViewer.articleViewerWidth,
                'height': ArticleViewer.articleViewerHeight});
        ArticleViewer.Content.article.css({
                'width': ArticleViewer.articleViewerWidth -
                        ArticleViewer.articleFixedSizes["articleWrapper"],
                'height': ArticleViewer.articleViewerHeight -
                        $("#layer1_top_cap").outerHeight()
        });
        if ($("#article_content").length > 0) {
            var newHeight = $("#article").height() -
                    parseInt($("#layer1_handle").css("margin-bottom"), 10) -
                    ArticleViewer.articleMainHandle.outerHeight() -
                    parseInt($("#article_content").css("border-bottom-width"), 10) -
                    parseInt($("#article_content").css("border-top-width"), 10) -
                    $("#article_title").outerHeight();
            newHeight = newHeight >= 0 ? newHeight : 0;
            $("#article_content").height(newHeight);
        }

        var ghostHeight = ArticleViewer.articleMain.outerHeight();
        ArticleViewer.articleGhost.css({
                'width': ArticleViewer.articleViewerWidth,
                'height': ghostHeight});

        var artTabWidth = $("#articleTab").width(); 
        if (artTabWidth > 0) {
            $(".artTab1").addClass("b1");
            $(".artTab1").css({'width': artTabWidth-8});
            $(".artTab2").addClass("b2");
            $(".artTab2").css({'width': artTabWidth-8});
            $(".artTab3").addClass("b3");
            $(".artTab3").css({'width': artTabWidth-4});
            $(".artTab4").addClass("b4");
            $(".artTab4").css({'width': artTabWidth-2});
        }
        if (ArticleViewer.articleViewerWidth > 0) {
            $(".cap1").css("width", ArticleViewer.articleViewerWidth -
                    ArticleViewer.articleFixedSizes["cap1"]);
            $(".cap2").css("width", ArticleViewer.articleViewerWidth -
                    ArticleViewer.articleFixedSizes["cap2"]);
            $(".cap3").css("width", ArticleViewer.articleViewerWidth -
                    ArticleViewer.articleFixedSizes["cap3"]);
            $(".cap4t").css("width", ArticleViewer.articleViewerWidth -
                    ArticleViewer.articleFixedSizes["cap4t"]);
            $(".cap4b").css("width", ArticleViewer.articleViewerWidth -
                    ArticleViewer.articleFixedSizes["cap4b"]);
        }
        // 50 = padding and scrollbar width (approximate only, but good enough)
        var imgWidth = $("#article").width() - 50;
        $("img", ArticleViewer.Content.content_wrapper).each(function() {
            $(this).css("max-width", imgWidth +"px");
        });
    },

    articleResizeStart : function() {
        ArticleViewer.articleGhost.css("display", "block");
        ArticleViewer.articleGhost.css("height", ArticleViewer.articleViewerHeight);
        ArticleViewer.articleGhost.css("width", ArticleViewer.articleViewerWidth);
    },
    
    articleResizeStop : function() {
        ArticleViewer.articleViewerHeight = ArticleViewer.articleMain.height();
        ArticleViewer.articleViewerWidth = ArticleViewer.articleMain.width();
        ArticleViewer.Content.adjustDisplaySize();
        ArticleViewer.articleGhost.css("display", "none");
    },
    
    articleDraggableStart : function() {
        var maxX = $(window).width() - ArticleViewer.articleViewerMinWidth;
        var maxY = $(window).height() - ArticleViewer.articleViewerMinHeight;
        ArticleViewer.articleMain.draggable("option", "containment",
                [0, 0,
                ($(window).width() - ArticleViewer.articleViewerMinWidth),
                ($(window).height() - ArticleViewer.articleViewerMinHeight)]);
    }

};


/**
 * Create an Articles class to capture and store information about the articles
 * in a particular issue.  The Articles class captures article information in:
 *     data : Object stores information about an article
 *         article_id
 *         title
 *         pgs - the folio page numbers the article extends over
 *         index - match the index in Articles.list
 *         content - article contents
 *         comments - article comments
 *     list : Array lookup article by index position, for next and previous
 *     startFolioArticles : Object lookup article by starting folio page
 *     folioArticles : Object lookup articles on each folio page
 */
ArticleViewer.Articles = {
    data : {},
    list : [],
    startFolioArticle : {},
    folioArticles : {},

	/**
	 *  Initialize the Articles object.  Create the data object and store article
	 *  data.  Call buildArticlesPageArray to create the overall pages array.
	 */
    init : function(){
        if (ArticleViewer.articlePreloadStarted === true) {
            return;
        }
        ArticleViewer.articlePreloadStarted = true;
        DataSwitch.get({ 
            url: DocumentProperties.getDocumentUrl() + ArticleViewer.articleTocUrl,
            cache: false,
            dataType: "json",
            success: function(data){
                ArticleViewer.Articles.buildArticleData(data);
            }
        });
    },

    /**
     * Get article data as an Object (associative array) from the server and
     * assign it to the Articles data object.  Add each article id to the
     * Articles list depending on the "index" value in the data object to make
     * it easier to navigate to next and previous articles.
     * Convert pgs - a comma-separated string of folios to an array.
     * Build startFolioArticle and folioArticles to make it easy to find the
     * articles on a page.
     * 
     * @param data Article data from server
     */
    buildArticleData : function(data) {
        var afterInit = [];
        if(data && data != {}){
            for (var article_id in data) {
                ArticleViewer.Articles.list[data[article_id]["index"]] = article_id;
                if (data[article_id].hasOwnProperty("pgs")){
                    data[article_id].pgs = data[article_id].pgs.split(","); 
                    var pgKey = data[article_id]["pgs"][0];
                    if (!ArticleViewer.Articles.startFolioArticle.hasOwnProperty(pgKey)) {
                        ArticleViewer.Articles.startFolioArticle[pgKey] = article_id;
                    }
                    for (var i = 0; i < data[article_id]["pgs"].length; i++) {
                        var folio = data[article_id]["pgs"][i];
                        if (ArticleViewer.Articles.folioArticles.hasOwnProperty(folio)) {
                            ArticleViewer.Articles.folioArticles[folio].push(article_id);
                        } else {
                            ArticleViewer.Articles.folioArticles[folio] = [article_id];
                        }
                    }
                }
            }
            ArticleViewer.Articles.data = data;

            // Show Article flag if page has articles
            ArticleViewer.showArticleFlag(PageController.currentPage);
            // kick off pre-loading articles in background
            afterInit.push(ArticleViewer.ArticleLoader.start);
            ViewHelper.schedule(afterInit,ArticleViewer.Articles);
            // Check to see if article id is in url, if so, load article
            ArticleViewer.viewArticle();
        }
    },

    /**
     * Return the next id in the list
     * @param article_id Article id for key
     * @return next article_id in the Articles list
     */
    next_id : function(article_id) {
        var index = ArticleViewer.Articles.data[article_id]["index"];
        var listLen = ArticleViewer.Articles.list.length;
        var next = (index < listLen - 1) ?
                ArticleViewer.Articles.list[index + 1] :
                ArticleViewer.Articles.list[0];
       return next;
    },

    /**
     * Return the previous id in the list
     * @param article_id Article id for key
     * @return previous article_id in the Articles list
     */
    prev_id : function(article_id) {
        var index = ArticleViewer.Articles.data[article_id]["index"];
        var endIndex = ArticleViewer.Articles.list.length - 1;
        var prev = (index == 0) ?
                ArticleViewer.Articles.list[endIndex] :
                ArticleViewer.Articles.list[index - 1];
       return prev;
    },

    /**
     * Given a page folio value, find and return the article id.
     * Match first on starting page.  If not found in the list of
     * starting pages, search through any page which can have an
     * article for a match.
     * 
     * @param page_folio Folio value to use to find potential matching article
     * @return article_id or null if not found
     */
    getArticleIdByPageFolio : function(page_folio){
        if (ArticleViewer.Articles.startFolioArticle.hasOwnProperty(page_folio)) {
            return ArticleViewer.Articles.startFolioArticle[page_folio];
        } else if (ArticleViewer.Articles.folioArticles.hasOwnProperty(page_folio)) {
            return ArticleViewer.Articles.folioArticles[page_folio][0];
        }
        return null;
    },

    /**
     * Given a reading order page number, find and return the article id.
     * Finds the folio value matching the page number and calls
     * getArticleIdByPageFolio
     * 
     * @param page_number Reading order page number
     * @return article_id or null if not found
     */
    getArticleIdByPageNumber : function(page_number){
        if (PageModel.pages.hasOwnProperty(page_number)) {
            return ArticleViewer.Articles.getArticleIdByPageFolio(PageModel.pages[page_number]);
        }
        return null;
    }

};


//Article 'Comments'
ArticleViewer.Comment = {
    commentFields : {},
    init : function(){
        var comment_name = CookieManager.get('comment_name');
        $(".comment_input",ArticleViewer.Content.article).each(function(){
            $(this).data("required",$(this).hasClass('required'));
            $(this).data("default",$(this).val());
            ArticleViewer.Comment.commentFields[$(this).attr("id")] = $(this);
            ArticleViewer.Comment.attachBehaviors.call(this);
        });
        if(comment_name){
            $("#comment_name",ArticleViewer.Content.article).val(comment_name);
        }
        
    },
    create : function(obj){
    	var fields = ArticleViewer.Comment.commentFields;
        var commentComplete = true;
        for( var field in fields ){
            var tmp_field = ArticleViewer.Comment.commentFields[field];
            var tmp_value = tmp_field.val();
            if(tmp_field.data('required') === true && (tmp_value=="" || tmp_field.data('default') == tmp_value)){
                commentComplete = false;
                break;
            }
        }
        if(commentComplete === true){
            // check if a reply (comment_parent_id is defined)
            // if so, set the parent id, otherwise set to 0
            var parent_id = 0;
            if (typeof(fields.comment_parent_id) != "undefined") {
                parent_id = fields.comment_parent_id.val() || 0;
            }
            var xmlDoc = "<CommentRequest><articleId>"+ArticleViewer.article.article_id+"</articleId><comment>"+fields.comment_text.val()+"</comment><subject></subject><name></name><commentId>0</commentId><parentId>"+parent_id+"</parentId></CommentRequest>" ;
            var path = location.pathname;
            if (path.substring(path.length-1) == '/') {
                path = path.substring(0,path.length-1);
            }
            ArticleViewer.setBusy();
            DataSwitch.post({
                url : path + "/WSComments.xml",
                processData : false,
                contentType : "text/xml",
                data : xmlDoc,
                success : function(json_data){
                    ArticleViewer.viewArticle(ArticleViewer.article.article_id, true);
                    ArticleViewer.Comment.resetFields(true);
//                    $("#comment_parent_id",ArticleViewer.Content.article).val("");
                    //CookieManager.set('comment_name',fields.comment_name.val());
                    //ArticleViewer.Comment.showCommentResponse("success");
                    ArticleViewer.Content.doScrollToComments = true;
                },
                error : function(){
                    ArticleViewer.Comment.showCommentResponse("error");
                }
            });
        }else{
            alert("you must complete all fields to post a comment.");
        }
    },
    resetFields : function(force){
        var fields = ArticleViewer.Comment.commentFields;
        for( var field in fields ){
            ArticleViewer.Comment.resetField.call(fields[field],force);
        }
    },
    resetField : function(force){
        var tmp_val = $(this).val();
        var force_reset = typeof force != "undefined" ? force : false;
        if(tmp_val == "" || force_reset === true){
            $(this).val($(this).data("default"));
        }
    },
    fieldBlur : function(){
        ArticleViewer.Comment.resetField.call($(this));
    },
    fieldFocus : function(){
        var tmp_val = $(this).val();
        if(tmp_val == $(this).data("default")){
            $(this).val("");
        }
    },
    attachBehaviors : function(){
        $(this).unbind('focus.comment_blur',ArticleViewer.Comment.fieldFocus).bind('focus.comment_blur',ArticleViewer.Comment.fieldFocus);
        $(this).unbind('blur.comment_blur',ArticleViewer.Comment.fieldBlur).bind('blur.comment_blur',ArticleViewer.Comment.fieldBlur);
    },
    
    initiateCommentReply : function(e){
        e.preventDefault();
        e.stopPropagation();
        if ($(this).parents("div").next(".comment_reply_text").is(':hidden')) {
            ArticleViewer.Comment.closeCommentReply()
            $(this).text("close");
            $(this).parents("div").next(".comment_reply_text").append("" +
                    "<fieldset>" +
                        "<input id='comment_parent_id' class='comment_input' type='hidden' value='' />" +
                        "<textarea id='comment_text' class='comment_input required'></textarea>" +
                        "<div id='comment_reply_submit' class='gradient_button'><span>SUBMIT</span></div>" +
                    "</fieldset>"
            );
            $(".comment_reply_text").hide();
            var comment_name = CookieManager.get('comment_name');
            $(".comment_input",$(this).parents("div").next(".comment_reply_text")).each(function(){
                $(this).data("required",$(this).hasClass('required'));
                $(this).data("default",$(this).val());
                ArticleViewer.Comment.commentFields[$(this).attr("id")] = $(this);
                ArticleViewer.Comment.attachBehaviors.call(this);
            });
            if(comment_name){
                $("#comment_name",ArticleViewer.Content.article).val(comment_name);
            }
            $(this).parents("div").next(".comment_reply_text").show();
            var link_parts = $(this).attr("href").split("/");
            var parent_id = link_parts[link_parts.length-1];
            var parent_comment = $(this).closest("div.comment");
            var parent_subject = parent_comment.find("h3").text();
            $("#comment_parent_id",ArticleViewer.Content.article).val(parent_id);
//            $("#comment_subject",ArticleViewer.Content.article).val("re: " + parent_subject); // Not currently used
            ArticleViewer.Content.initCommentReply();
            return false;
        } else {
            $(this).text("reply");
            $(this).parents("div").next(".comment_reply_text").find("fieldset").remove();
            $(this).parents("div").next(".comment_reply_text").hide();
        }
    },
    
    closeCommentReply : function(){
        $("#comments").find(".comment_reply_text").find("fieldset").remove();
        $("#comments").find(".comment").find("div.links").find("a").text("reply");
    },

    showCommentResponse : function(response_status){
        var response_content = response_status == "success" 
              ? $("#comment_success",ArticleViewer.Content.article).html()
              : $("#comment_error",ArticleViewer.Content.article).html();
        $(ViewHelper.shadowWrap(response_content,"black")).dialog({
            height:300,
            width:400,
            modal:false,
            close: function(){
                $(this).dialog('destroy').remove();
            },
            open: function(){
              PageElements.dialogs["comment_response"] = {
                'id':'comment_response',
                'link_active':false,
                'dialog_active':true
              };
            },
            resizable:false
        });
    }
};


/**
 * Object to handle loading articles in the background.  This object
 * will create a build list, then pick articles one at a time from the
 * list to get the article content from the remote cms.  Downloading
 * articles is on a timeout to minimize performance problems.
 * 
 * Methods can add an article to the top of the list to prioritize
 * article loading - for instance, if an article is loaded, we may
 * want to ensure that the next article downloaded is the article
 * that comes next in the original articles list.
 */
ArticleViewer.ArticleLoader = {
    buildStack : [],
    
    /**
     * Make a copy of the Articles list.  Reverse the order in the
     * list so that when we start loading articles, we load them in
     * the original order.  Once done, call populateArticleContent
     * to actually populate article data.
     */
    start : function() {
	    if (ArticleViewer.backgroundLoad === true) {
            ArticleViewer.ArticleLoader.buildStack = ArticleViewer.Articles.list.slice(0);
            ArticleViewer.ArticleLoader.buildStack.reverse();
	    }
        ArticleViewer.ArticleLoader.populateArticleContent();
    },

    /**
     * Add an article id to the build list.  Articles added this way
     * will be processed first.
     * 
     * @param article_id Article id to add to list
     */
    add : function(article_id) {
        if (!ArticleViewer.Articles.data[article_id].hasOwnProperty("content")) {
            ArticleViewer.ArticleLoader.buildStack.push(article_id);
        }
    },

    /**
     * Pops an article id from the build list.  Checks to see if the article
     * content has already been loaded.  If not, make an Ajax call to get the
     * content.  The Ajax call will call processArticleContent when done.
     * If the article has already been loaded, get another article id from the list.
     * Once all entries on the build list have been processed, set completed flag.
     */
    populateArticleContent : function() {
        var article_id;
        var filled = true;
        while (filled && ArticleViewer.ArticleLoader.buildStack.length > 0) {
            article_id = ArticleViewer.ArticleLoader.buildStack.pop();
            filled = ArticleViewer.Articles.data[article_id].hasOwnProperty("content");
        }
        // Done, just return
        if (filled && ArticleViewer.ArticleLoader.buildStack.length == 0) {
            return;
        }
        DataSwitch.get({
            url: DocumentProperties.getDocumentUrl() + ArticleViewer.articleTextUrl + article_id,
            cache: false,
            success: function(data){
                ArticleViewer.ArticleLoader.processArticleContent(data, article_id);
            }
        });
    },

    /**
     * Process the article data returned from an Ajax call made from
     * populateArticleContent.  After processing, call back to
     * populateArticleContent on a timer to allow other processes to
     * execute and provide a smaller performance hit.  Currently, the
     * delay is set to backgroundLoadWait seconds before the next call.
     * 
     * @param data Article content returned from Ajax call
     * @param article_id Article id for content
     */
    processArticleContent : function(data, article_id) {
        ArticleViewer.Articles.data[article_id]["content"] = data;
        setTimeout(function(){ArticleViewer.ArticleLoader.populateArticleContent()}, (ArticleViewer.backgroundLoadWait*1000));
    }
};



